blob: 90298f6bcab2bf10b9f352bf5846aa30fc0f926b [file] [log] [blame]
#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