|  | #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 |