Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

TcpConnection.cpp

Go to the documentation of this file.
00001 #include "headers.h"
00002 
00007 
00008 
00009 TcpConnection::TcpConnection() 
00010 {
00011     m_stream = OS_SPEC_INVALID_SOCKET;
00012 } // ctor
00013 
00014 
00015 TcpConnection::TcpConnection(SocketAddress socketAddress) 
00016 {
00017     m_stream = OS_SPEC_INVALID_SOCKET;
00018     m_socketAddress = socketAddress;
00019 } // ctor
00020 
00021 
00022 TcpConnection::TcpConnection(IpAddress ipAddr, unsigned short port) 
00023 {
00024     m_stream = OS_SPEC_INVALID_SOCKET;
00025     m_socketAddress = SocketAddress(ipAddr, port);
00026 } // ctor
00027 
00028 
00032 TcpConnection::TcpConnection(unsigned short port) 
00033 {
00034     m_stream = OS_SPEC_INVALID_SOCKET;
00035     m_socketAddress = SocketAddress(IpAddress((unsigned long)INADDR_ANY), port);
00036 } // ctor
00037 
00038 
00042 TcpConnection::~TcpConnection() {
00043     close();
00044 } // dtor
00045 
00046 
00047 ConnectionInterface::ObjectType
00048 TcpConnection::getConnectionType() {
00049     return TCP_CONNECTION;
00050 } // fn getConnectionType
00051 
00052 
00057 void
00058 TcpConnection::setSocketOptions() {
00059     // Disable the Nagle algorithm - it slows down SSL
00060     int turnOn = 1;
00061     int err = setsockopt(m_stream, IPPROTO_TCP, TCP_NODELAY, (const char*)&turnOn, sizeof(int));
00062     if (err == OS_SPEC_SOCKET_ERROR) {
00063         debug(DEBUG_CONN, "Error setting TCP_NODELAY");
00064     }
00065     
00066     // Keep the connection alive by sending keep-alive packets
00067     err = setsockopt(m_stream, SOL_SOCKET, SO_KEEPALIVE, (const char*)&turnOn, sizeof(int));
00068     if (err == OS_SPEC_SOCKET_ERROR) {
00069         debug(DEBUG_CONN, "Error setting socket Keep-Alive");
00070     }
00071 } // fn setSocketOptions
00072 
00073 
00078 int
00079 TcpConnection::connect()
00080 {
00081     if(!isConnected()) {
00082         m_stream = socket(AF_INET, SOCK_STREAM, 0);
00083         
00084         // Check for errors
00085         if (m_stream == OS_SPEC_INVALID_SOCKET) {
00086             debug(DEBUG_CONN, "Socket error, windows return code:\n%s", printWsaErrorCode());
00087             return 0;
00088         }
00089         
00090         setSocketOptions();
00091 
00092         debug(DEBUG_CONN, "Trying to connect to %s, port %d", 
00093             m_socketAddress.getIpAddress().toCStr(),
00094             m_socketAddress.getPort());
00095         
00096         if (::connect(m_stream, (struct sockaddr *) m_socketAddress.getSockAddrStruct(), sizeof(struct sockaddr_in)) != 0)
00097         {
00098             debug(DEBUG_CONN,  "connect error");
00099             debug(DEBUG_CONN, "%s", printWsaErrorCode());
00100             OS_SPEC_SOCKETCLOSE(m_stream);
00101             m_stream = OS_SPEC_INVALID_SOCKET;
00102             return 0;
00103         }
00104             
00105         debug(DEBUG_CONN, "Connected to %s, port %d", 
00106               m_socketAddress.getIpAddress().toCStr(),
00107               m_socketAddress.getPort());
00108             
00109         fireEvent(CONNECTION_OPENED);
00110 
00111         debug(DEBUG_CONN, "connect() successful");
00112         return 1;
00113     } // if (!isConnected())
00114     else {
00115         debug(DEBUG_CONN, "Already connected");
00116     }
00117     return 0;
00118 } // fn connect
00119 
00120 
00131 int
00132 TcpConnection::read(unsigned char* buffer, int bufferSize, int amountToRead)
00133 {
00134     if (!isConnected()) {
00135         debug(DEBUG_CONN, "trying to read from a Connection that isnt connected!");
00136         return -1;
00137     }
00138 
00139     if (amountToRead > bufferSize) {
00140         debug(DEBUG_CONN, "ERROR: (amountToRead > bufferSize)");
00141         return -1;
00142     }
00143 
00144     //memset(&buffer[0], 0, bufferSize);
00145 
00146     int bytesRead = 0;
00147     int totalBytesRead = 0;
00148 
00149     if (amountToRead == 0) {
00150         totalBytesRead = recv(getStream(), (char*)buffer, bufferSize, 0);
00151         // check for read errors
00152         if (totalBytesRead <= 0) {
00153             debug(DEBUG_CONN, "socket read error: %s", strerror(errno));
00154             debug(DEBUG_CONN, "%s", printWsaErrorCode());
00155         }
00156     }
00157     else {
00158         while ((bytesRead >= 0) && (totalBytesRead != amountToRead)) { 
00159             bytesRead = recv(getStream(), (char*)buffer + totalBytesRead, amountToRead - totalBytesRead, 0);
00160             // check for read errors
00161             if (bytesRead <= 0) {
00162                 debug(DEBUG_CONN, "socket read error: %s", strerror(errno));
00163                 debug(DEBUG_CONN, "%s", printWsaErrorCode());
00164                 // return the error code from recv()
00165                 totalBytesRead = bytesRead;
00166                 break;
00167             }
00168             totalBytesRead += bytesRead;
00169         }
00170     }
00171 
00172         debug(DEBUG_CONN, "read data: %d bytes", totalBytesRead);
00173         return totalBytesRead;
00174 } // fn read
00175 
00176 
00181 int
00182 TcpConnection::write(unsigned char* buffer, int amountToWrite) {
00183         int bytesWritten = 0;
00184     int sendResult = 0;
00185 
00186     do {
00187         sendResult = send(m_stream, (const char*)&buffer[bytesWritten], amountToWrite - bytesWritten, 0);
00188         bytesWritten += sendResult;
00189     } while ((bytesWritten != amountToWrite) && (sendResult > 0));
00190 
00191     if (bytesWritten != amountToWrite) {
00192         debug(DEBUG_CONN, "Error - did not send all data");
00193     }
00194 
00195     if (sendResult < 0) {
00196         printWsaErrorCode();
00197         return sendResult;
00198     }
00199     return bytesWritten;
00200 } // fn writePacket
00201 
00202 
00211 int 
00212 TcpConnection::listen() {
00213         m_stream = createListeningSocket(m_socketAddress);
00214         if (m_stream != OS_SPEC_INVALID_SOCKET) {
00215                 return 1;
00216         }
00217         else {
00218                 return 0;
00219         }
00220 } // fn listen
00221 
00222 
00228 OS_SPEC_SOCKET_TYPE 
00229 TcpConnection::createListeningSocket(SocketAddress socketAddress) {
00230         OS_SPEC_SOCKET_TYPE stream;
00231     stream = socket(AF_INET, SOCK_STREAM, 0);
00232         
00233         if (stream == OS_SPEC_INVALID_SOCKET) {
00234                 debug(DEBUG_ERR, "socket creation error");
00235                 debug(DEBUG_ERR, "%s", printWsaErrorCode());
00236         }
00237         else {
00238                 if ((0 != bind(stream, 
00239                        (struct sockaddr *)socketAddress.getSockAddrStruct(), 
00240                        *(socketAddress.getSockAddrStructLen()))))
00241                 {
00242                         debug(DEBUG_ERR, "bind error: IP address: %s", socketAddress.toCStr());
00243                         debug(DEBUG_ERR, "%s", printWsaErrorCode());
00244                         stream = OS_SPEC_INVALID_SOCKET;
00245                 }
00246                 else {
00247             // The +5 is a fudge factor
00248                         (void) ::listen(stream, MAX_CONNECTIONS + 5);
00249                         debug(DEBUG_ERR, "Socket stream fd=%d listening on address %s",  
00250                                 stream, socketAddress.toCStr());
00251                 }
00252         }
00253         return stream;
00254 } // fn createListeningSocket
00255 
00256 
00265 ConnectionInterface*
00266 TcpConnection::accept()
00267 {
00268     int n = 0;
00269     int newfd = 0;
00270     int i = 0;
00271     int acceptHighestFd = 0;
00272     TcpConnection* newConnection = NULL;
00273     fd_set listenSockets;
00274     
00275     // Note: We use select in order to be able to change ports at run-time
00276     // if you just use "accept" it doesnt work
00277     
00278     // add all local ports to our fd_set
00279     FD_ZERO(&listenSockets);
00280     
00281     // stream was set during listen()
00282     setSocketOptions();
00283     int stream = m_stream;
00284     if (stream != OS_SPEC_INVALID_SOCKET) {
00285         OS_SPEC_FD_SET(stream, &listenSockets);
00286         if (stream > acceptHighestFd) {
00287             acceptHighestFd = stream;
00288         }
00289     }
00290     else {
00291         debug(DEBUG_CONN, "ERROR: stream is bad!");
00292         return NULL;
00293     }
00294 
00295     // wait for an accept from foreign host, or another thread to signal us
00296     n = select(acceptHighestFd + 1, &listenSockets, NULL, NULL, NULL);
00297     debug(DEBUG_CONN, "select: returned %d", n);
00298     
00299     // Check for errors
00300 #ifdef WIN32
00301     if (n == INVALID_SOCKET) {
00302 #else
00303     if (n <= 0) {
00304 #endif
00305         debug(DEBUG_CONN, "select error: %s\n Highest fd: %d", printWsaErrorCode(), acceptHighestFd);
00306         return NULL;
00307     }
00308         
00309     //
00310     // Check if we have received a new connection from a remote node
00311     //
00312     if(OS_SPEC_FD_ISSET(m_stream, &listenSockets))
00313     {
00314         // wait for a connection
00315         SocketAddress socketAddress;
00316         if ((newfd = ::accept(m_stream, 
00317                               (struct sockaddr *) socketAddress.getSockAddrStruct(), 
00318                               socketAddress.getSockAddrStructLen())) < 0) {
00319             debug(DEBUG_CONN, "accept() error, port#%d: %s", i, strerror(errno));
00320             return NULL;
00321         }
00322         // re-sync the object because sockaddr_in has been modified outside its control
00323         socketAddress.setSocketAddress(socketAddress.getSockAddrStruct());
00324 
00325         // We have received a connection from a remote node
00326         debug(DEBUG_CONN, "new incoming connection: %s", socketAddress.toCStr());
00327         
00328         // Create the new connection object
00329         newConnection = new TcpConnection(socketAddress);
00330         MEMCHECK(newConnection);
00331         newConnection->setStream(newfd);
00332     }
00333     else {
00334         debug(DEBUG_CONN, "Select returned, but no sockets flagged");
00335     }
00336     return newConnection;
00337 } // fn accept
00338 
00339   
00343 void 
00344 TcpConnection::close() {
00345     if(isConnected()) {
00346         debug(DEBUG_CONN, "Closing connection");
00347         if (m_stream != OS_SPEC_INVALID_SOCKET) {
00348             OS_SPEC_SOCKETCLOSE(m_stream);
00349             m_stream = OS_SPEC_INVALID_SOCKET;
00350         }
00351         debug(DEBUG_CONN, "connection closed");
00352         // inform listeners
00353         fireEvent(ConnectionInterface::CONNECTION_CLOSED);
00354     }
00355 } // fn close
00356 
00357 
00361 bool 
00362 TcpConnection::isConnected() {
00363     if (m_stream != OS_SPEC_INVALID_SOCKET) {
00364         return true;
00365     }
00366     else {
00367         return false;
00368     }
00369 } // fn isConnected
00370 
00371 
00376 bool 
00377 TcpConnection::isConnectedTo(IpAddress ipAddr) {
00378     if ((m_socketAddress.getIpAddress().equals(ipAddr)) && isConnected()) {
00379         return true;
00380     }
00381     else {
00382         return false;
00383     }
00384 } // fn isConnectedTo
00385 
00386 
00387 SocketAddress*
00388 TcpConnection::getSocketAddress() {
00389     return &m_socketAddress;
00390 } // fn getSocketAddress
00391 
00392 
00393 void
00394 TcpConnection::setSocketAddress(SocketAddress* socketAddress) {
00395     m_socketAddress = *socketAddress;
00396 } // fn setSocketAddress
00397 
00398 
00402 int 
00403 TcpConnection::getStream() {
00404     return m_stream;
00405 } // fn getStream
00406 
00407 
00411 void 
00412 TcpConnection::setStream(int stream) {
00413         if (!isConnected()) {
00414                 m_stream = stream;
00415         }
00416 } // fn setStream
00417 
00418 
00419 void
00420 TcpConnection::toStream(std::ostream& out) {
00421     out << m_socketAddress;    
00422 } // fn toStream
00423 

Generated at Thu Jul 11 13:31:52 2002 for Peekabooty by doxygen1.2.9 written by Dimitri van Heesch, © 1997-2001