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