| #ifndef _H_Socket | |
| #define _H_Socket | |
| /* | |
| * Copyright 2008 Google Inc. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
| * use this file except in compliance with the License. You may obtain a copy of | |
| * the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| * License for the specific language governing permissions and limitations under | |
| * the License. | |
| */ | |
| #include "Platform.h" | |
| #include "Debug.h" | |
| #include <string> | |
| #ifdef _WINDOWS | |
| #include <winsock2.h> | |
| #include <ws2tcpip.h> | |
| #else | |
| #include <netdb.h> | |
| #include <sys/socket.h> | |
| #include <netinet/in.h> | |
| #include <arpa/inet.h> | |
| #include <unistd.h> | |
| #include <sys/time.h> | |
| #endif | |
| /** | |
| * Encapsulates platform dependencies regarding buffered sockets. | |
| */ | |
| class Socket { | |
| private: | |
| // Buffer size, chosen to fit in a single packet after TCP/IP overhead. | |
| static const int BUF_SIZE = 1400; | |
| // Can't rely on a sentinel value for the socket descriptor | |
| bool connected; | |
| SOCKETTYPE sock; | |
| // Read buffer | |
| char* readBuf; | |
| // One bye past end of valid data in readBuf | |
| char* readValid; | |
| // Current read pointer | |
| char* readBufPtr; | |
| // Write buffer | |
| char* writeBuf; | |
| // Current write pointer | |
| char* writeBufPtr; | |
| // Stats | |
| unsigned long numReads; | |
| unsigned long long totReadBytes; | |
| size_t maxReadBytes; | |
| unsigned long numWrites; | |
| unsigned long long totWriteBytes; | |
| size_t maxWriteBytes; | |
| private: | |
| void init(); | |
| bool fillReadBuf(); | |
| bool emptyWriteBuf(); | |
| public: | |
| Socket() : connected(false), readBuf(new char[BUF_SIZE]), writeBuf(new char[BUF_SIZE]) { | |
| readBufPtr = readValid = readBuf; | |
| writeBufPtr = writeBuf; | |
| numReads = numWrites = 0; | |
| maxReadBytes = maxWriteBytes = 0; | |
| totReadBytes = totWriteBytes = 0; | |
| init(); | |
| } | |
| ~Socket() { | |
| disconnect(); | |
| #ifdef _WINDOWS | |
| if (0) WSACleanup(); | |
| #endif | |
| // TODO(jat): LEAK LEAK LEAK | |
| // delete[] readBuf; | |
| // delete[] writeBuf; | |
| Debug::log(Debug::Debugging) << "Socket: #r=" << numReads << ", bytes/read=" | |
| << (numReads ? totReadBytes / numReads : 0) << ", maxr=" << maxReadBytes << "; #w=" | |
| << numWrites << ", bytes/write=" << (numWrites ? totWriteBytes / numWrites : 0) << ", maxw=" | |
| << maxWriteBytes << Debug::flush; | |
| } | |
| /** | |
| * Connects this socket to a specified port on a host. | |
| * | |
| * @param host host name or IP address to connect to | |
| * @param port TCP port to connect to | |
| * @return true if the connection succeeds | |
| */ | |
| bool connect(const char* host, int port); | |
| /** | |
| * Returns true if the socket is connected. | |
| */ | |
| bool isConnected() const { | |
| return connected; | |
| } | |
| /** | |
| * Disconnect this socket. | |
| * | |
| * @param doFlush true (the default value) if the socket should be flushed. | |
| * @return true if disconnect succeeds | |
| */ | |
| bool disconnect(bool doFlush = true); | |
| /** | |
| * Read a single byte from the socket. | |
| * | |
| * @return -1 on error, otherwise unsigned byte read. | |
| */ | |
| int readByte() { | |
| if (readBufPtr >= readValid) { | |
| if (!fillReadBuf()) { | |
| return -1; | |
| } | |
| } | |
| return static_cast<unsigned char>(*readBufPtr++); | |
| } | |
| /** | |
| * Write a single byte to the socket. | |
| * | |
| * @return true on success. | |
| */ | |
| bool writeByte(char c) { | |
| if (writeBufPtr >= writeBuf + BUF_SIZE) { | |
| if (!emptyWriteBuf()) { | |
| return false; | |
| } | |
| } | |
| *writeBufPtr++ = c; | |
| return true; | |
| } | |
| /** | |
| * Flush any pending writes on the socket. | |
| * | |
| * @return true on success | |
| */ | |
| bool flush() { | |
| if (writeBufPtr > writeBuf) { | |
| if (!emptyWriteBuf()) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| }; | |
| #endif |