socket.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002  ** This file is part of the network simulator Shawn.                  **
00003  ** Copyright (C) 2004-2007 by the SwarmNet (www.swarmnet.de) project  **
00004  ** Shawn is free software; you can redistribute it and/or modify it   **
00005  ** under the terms of the BSD License. Refer to the shawn-licence.txt **
00006  ** file in the root of the Shawn source tree for further details.     **
00007  ************************************************************************/
00008 
00009 #ifdef SHAWN
00010     #include <apps/tcpip/socket.h>
00011     #include <sys/simulation/simulation_controller.h>
00012 #else
00013     #include "socket.h"
00014 #endif
00015 
00016 #ifdef BUILD_TCPIP
00017 
00018 
00019 #ifndef WIN32
00020     #include <sys/types.h>
00021     #include <sys/socket.h>
00022     #include <netinet/in.h>
00023     #include <netinet/tcp.h>
00024     #include <arpa/inet.h>
00025     #include <netdb.h>
00026     #include <errno.h>
00027     #include <fcntl.h>
00028 #else
00029     #ifdef ERROR
00030         #undef ERROR
00031     #endif
00032 
00033     #include <winsock2.h>
00034 
00035     #ifndef vsnprintf
00036         #define vsnprintf _vsnprintf
00037     #endif
00038 
00039 #endif
00040 
00041 #include <cstdio>
00042 #include <cstring>
00043 #include <cstdarg>
00044 #include <string>
00045 #include <vector>
00046 #include <string>
00047 #include <algorithm>
00048 #include <string.h>
00049 
00050 using namespace std;
00051 
00052 
00053 #ifdef SHAWN
00054     extern "C" void init_tcpip( shawn::SimulationController& sc )
00055     {
00056             // std::cout << "tcpip init" << std::endl;
00057     }
00058 #endif
00059 
00060 namespace tcpip
00061 {
00062 #ifdef WIN32
00063     bool Socket::init_windows_sockets_ = true;
00064     bool Socket::windows_sockets_initialized_ = false;
00065     int Socket::instance_count_ = 0;
00066 #endif
00067 
00068     // ----------------------------------------------------------------------
00069     Socket::
00070 		Socket(std::string host, int port) 
00071         : host_( host ),
00072         port_( port ),
00073         socket_(-1),
00074         server_socket_(-1),
00075         blocking_(true)
00076     {
00077         verbose_ = false;
00078         init();
00079     }
00080 
00081     // ----------------------------------------------------------------------
00082     Socket::
00083         Socket(int port) 
00084         : host_(""),
00085         port_( port ),
00086         socket_(-1),
00087         server_socket_(-1),
00088         blocking_(true)
00089     {
00090         verbose_ = false;
00091         init();
00092     }
00093 
00094     // ----------------------------------------------------------------------
00095     void
00096         Socket::
00097 		init()
00098     {
00099 #ifdef WIN32
00100         instance_count_++;
00101 
00102         if( init_windows_sockets_ && !windows_sockets_initialized_ )
00103         {
00104             WSAData wsaData;
00105             if( WSAStartup(MAKEWORD(1, 1), &wsaData) != 0 )
00106                 BailOnSocketError("Unable to init WSA Sockets");
00107             windows_sockets_initialized_ = true;
00108         }
00109 #endif
00110     }
00111 
00112     // ----------------------------------------------------------------------
00113     Socket::
00114 		~Socket()
00115     {
00116         // Close first an existing client connection ...
00117         close();
00118 #ifdef WIN32
00119         instance_count_--;
00120 #endif
00121 
00122         // ... then the server socket
00123         if( server_socket_ >= 0 )
00124         {
00125 #ifdef WIN32
00126             ::closesocket( server_socket_ );
00127 #else
00128 			::close( server_socket_ );
00129 #endif
00130             server_socket_ = -1;
00131         }
00132 
00133 #ifdef WIN32
00134         if( server_socket_ == -1 && socket_ == -1 
00135             && init_windows_sockets_ && instance_count_ == 0 )
00136                 WSACleanup();
00137                 windows_sockets_initialized_ = false;
00138 #endif
00139     }
00140 
00141     // ----------------------------------------------------------------------
00142     void 
00143         Socket::
00144 		BailOnSocketError( std::string context) 
00145         const throw( SocketException )
00146     {
00147 #ifdef WIN32
00148         int e = WSAGetLastError();
00149         std::string msg = GetWinsockErrorString( e );
00150 #else
00151         std::string msg = strerror( errno );
00152 #endif
00153         throw SocketException( context + ": " + msg );
00154     }
00155 
00156     // ----------------------------------------------------------------------
00157     int  
00158         Socket::
00159 		port()
00160     {
00161         return port_;
00162     }
00163 
00164 
00165     // ----------------------------------------------------------------------
00166     bool 
00167         Socket::
00168 		datawaiting(int sock) 
00169         const throw()
00170     {
00171         fd_set fds;
00172         FD_ZERO( &fds );
00173         FD_SET( sock, &fds );
00174 
00175         struct timeval tv;
00176         tv.tv_sec = 0;
00177         tv.tv_usec = 0;
00178 
00179         int r = select( sock+1, &fds, NULL, NULL, &tv);
00180 
00181         if (r < 0)
00182             BailOnSocketError("tcpip::Socket::datawaiting @ select");
00183 
00184         if( FD_ISSET( sock, &fds ) )
00185             return true;
00186         else
00187             return false;
00188     }
00189 
00190     // ----------------------------------------------------------------------
00191     bool
00192         Socket::
00193 		atoaddr( std::string address, struct in_addr& addr)
00194     {
00195         struct hostent* host;
00196         struct in_addr saddr;
00197 
00198         // First try nnn.nnn.nnn.nnn form
00199         saddr.s_addr = inet_addr(address.c_str());
00200         if (saddr.s_addr != static_cast<unsigned int>(-1)) 
00201         {
00202             addr = saddr;
00203             return true;
00204         }
00205 
00206         host = gethostbyname(address.c_str());
00207         if( host ) {
00208             addr = *((struct in_addr*)host->h_addr_list[0]);
00209             return true;
00210         }
00211 
00212         return false;
00213     }
00214 
00215 
00216     // ----------------------------------------------------------------------
00217     void 
00218         Socket::
00219 		accept()
00220         throw( SocketException )
00221     {
00222         if( socket_ >= 0 )
00223             return;
00224 
00225         struct sockaddr_in client_addr;
00226 #ifdef WIN32
00227         int addrlen = sizeof(client_addr);
00228 #else
00229         socklen_t addrlen = sizeof(client_addr);
00230 #endif
00231 
00232         if( server_socket_ < 0 )
00233         {
00234             struct sockaddr_in self;
00235 
00236             //Create the server socket
00237             server_socket_ = static_cast<int>(socket( AF_INET, SOCK_STREAM, 0 ));
00238             if( server_socket_ < 0 )
00239                 BailOnSocketError("tcpip::Socket::accept() @ socket");
00240             
00241             //"Address already in use" error protection
00242             {
00243                 int reuseaddr = 1;
00244 
00245                 #ifdef WIN32
00246                     //setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(reuseaddr));
00247                     // No address reuse in Windows!!!
00248                 #else
00249                     setsockopt(server_socket_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
00250                 #endif
00251             }
00252 
00253             // Initialize address/port structure
00254             memset(&self, 0, sizeof(self));
00255             self.sin_family = AF_INET;
00256             self.sin_port = htons(port_);
00257             self.sin_addr.s_addr = htonl(INADDR_ANY);
00258 
00259             // Assign a port number to the socket
00260             if ( bind(server_socket_, (struct sockaddr*)&self, sizeof(self)) != 0 )
00261                 BailOnSocketError("tcpip::Socket::accept() Unable to create listening socket");
00262 
00263 
00264             // Make it a "listening socket"
00265             if ( listen(server_socket_, 10) == -1 )
00266                 BailOnSocketError("tcpip::Socket::accept() Unable to listen on server socket");
00267 
00268             // Make the newly created socket blocking or not
00269             set_blocking(blocking_);
00270         }
00271 
00272         socket_ = static_cast<int>(::accept(server_socket_, (struct sockaddr*)&client_addr, &addrlen));
00273 
00274         if( socket_ >= 0 )
00275         {
00276             int x = 1;
00277             setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x));
00278         }
00279     }
00280 
00281     // ----------------------------------------------------------------------
00282     void 
00283         Socket::
00284 		set_blocking(bool blocking) 
00285         throw(SocketException )
00286     {
00287         blocking_ = blocking;
00288 
00289         if( server_socket_ > 0 )
00290         {
00291 #ifdef WIN32
00292             ULONG NonBlock = blocking_ ? 0 : 1;
00293             if (ioctlsocket(server_socket_, FIONBIO, &NonBlock) == SOCKET_ERROR)
00294                 BailOnSocketError("tcpip::Socket::set_blocking() Unable to initialize non blocking I/O");
00295 #else
00296             long arg = fcntl(server_socket_, F_GETFL, NULL);
00297             if (blocking_)
00298             {
00299                 arg &= ~O_NONBLOCK;
00300             } else {
00301                 arg |= O_NONBLOCK;
00302             }
00303             fcntl(server_socket_, F_SETFL, arg);
00304 #endif
00305         }
00306     
00307     }
00308 
00309     // ----------------------------------------------------------------------
00310     void 
00311         Socket::
00312 		connect()
00313         throw( SocketException )
00314     {
00315         in_addr addr;
00316         if( !atoaddr( host_.c_str(), addr) )
00317             BailOnSocketError("tcpip::Socket::connect() @ Invalid network address");
00318 
00319         sockaddr_in address;
00320         memset( (char*)&address, 0, sizeof(address) );
00321         address.sin_family = AF_INET;
00322         address.sin_port = htons( port_ );
00323         address.sin_addr.s_addr = addr.s_addr;
00324 
00325         socket_ = static_cast<int>(socket( PF_INET, SOCK_STREAM, 0 ));
00326         if( socket_ < 0 )
00327             BailOnSocketError("tcpip::Socket::connect() @ socket");
00328 
00329         if( ::connect( socket_, (sockaddr const*)&address, sizeof(address) ) < 0 )
00330             BailOnSocketError("tcpip::Socket::connect() @ connect");
00331 
00332         if( socket_ >= 0 )
00333         {
00334             int x = 1;
00335             setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (const char*)&x, sizeof(x));
00336         }
00337 
00338     }
00339 
00340     // ----------------------------------------------------------------------
00341     void 
00342         Socket::
00343 		close()
00344     {
00345         // Close client-connection 
00346         if( socket_ >= 0 )
00347         {
00348 #ifdef WIN32
00349             ::closesocket( socket_ );
00350 #else
00351 			::close( socket_ );
00352 #endif
00353 
00354             socket_ = -1;
00355         }
00356     }
00357 
00358     // ----------------------------------------------------------------------
00359     void 
00360         Socket::
00361 		send( std::vector<unsigned char> b) 
00362         throw( SocketException )
00363     {
00364         if( socket_ < 0 ) return;
00365 
00366         size_t numbytes = b.size();
00367         unsigned char *const buf = new unsigned char[numbytes];
00368 
00369         for(size_t i = 0; i < numbytes; ++i)
00370         {
00371             buf[i] = b[i];
00372         }
00373 
00374         if (verbose_) 
00375         {
00376             cerr << "Send " << numbytes << " bytes via tcpip::Socket: [";
00377             for(size_t i = 0; i < numbytes; ++i)
00378             {
00379                 buf[i] = b[i];
00380                 cerr << " " << (int)b[i] << " ";
00381             }
00382             cerr << "]" << endl;
00383         }
00384 
00385         unsigned char const *buf_ptr = buf;
00386         while( numbytes > 0 )
00387         {
00388 #ifdef WIN32
00389             int n = ::send( socket_, (const char*)buf_ptr, static_cast<int>(numbytes), 0 );
00390 #else
00391             int n = ::send( socket_, buf_ptr, numbytes, 0 );
00392 #endif
00393             if( n<0 )
00394             {
00395                 // BailOnSocketError definitely throws an exception so clear up heap
00396                 delete[] buf;
00397                 BailOnSocketError( "send failed" );
00398             }
00399 
00400             numbytes -= n;
00401             buf_ptr += n;
00402         }
00403 
00404         delete[] buf;
00405     }
00406     
00407 
00408     
00409         // ----------------------------------------------------------------------
00410 
00411     void
00412         Socket::
00413 		sendExact( const Storage &b)
00414         throw( SocketException )
00415     {
00416         int length = static_cast<int>(b.size());
00417         Storage length_storage;
00418         length_storage.writeInt(length + 4);
00419         vector<unsigned char> msg;
00420         msg.insert(msg.end(), length_storage.begin(), length_storage.end());
00421         msg.insert(msg.end(), b.begin(), b.end());
00422         send(msg);
00423     }
00424 
00425 
00426     
00427     // ----------------------------------------------------------------------
00428     vector<unsigned char> 
00429         Socket::
00430 		receive(int bufSize)
00431         throw( SocketException )
00432     {
00433         vector<unsigned char> b;
00434 
00435         if( socket_ < 0 )
00436             connect();
00437 
00438         if( !datawaiting( socket_) )
00439             return b;
00440 
00441         unsigned char const * const buf = new unsigned char[bufSize];
00442         int a = recv( socket_, (char*)buf, bufSize, 0 );
00443 
00444         if( a <= 0 )
00445         {
00446             // BailOnSocketError definitely throws an exception so clear up heap
00447             delete[] buf;
00448             BailOnSocketError( "tcpip::Socket::receive() @ recv" );
00449         }
00450 
00451         b.resize(a);
00452         for(int i = 0; i < a; ++i)
00453         {
00454             b[i] = buf[i];
00455         }
00456 
00457         if (verbose_) 
00458         {
00459             cerr << "Rcvd "  << a <<  " bytes via tcpip::Socket: [";
00460             for(int i = 0; i < a; ++i)
00461             {
00462                 cerr << " " << (int)b[i] << " ";
00463             }
00464             cerr << "]" << endl;
00465         }
00466 
00467         delete[] buf;
00468         return b;
00469     }
00470 
00471     // ----------------------------------------------------------------------
00472     
00473 
00474     bool
00475         Socket::
00476 		receiveExact( Storage &msg )
00477         throw( SocketException )
00478     {
00479         /* receive length of vector */
00480         unsigned char * const bufLength = new unsigned char[4];
00481         int bytesRead = 0;
00482         int readThisTime = 0;
00483         
00484         while (bytesRead<4)
00485         {
00486             readThisTime = recv( socket_, (char*)(bufLength + bytesRead), 4-bytesRead, 0 );
00487 
00488             if( readThisTime <= 0 )
00489             {
00490                 // BailOnSocketError definitely throws an exception so clear up heap
00491                 delete[] bufLength;
00492                 BailOnSocketError( "tcpip::Socket::receive() @ recv" );
00493             }
00494 
00495             bytesRead += readThisTime;
00496         }
00497         Storage length_storage(bufLength,4);
00498         int NN = length_storage.readInt() - 4;
00499 
00500         /* receive vector */
00501         unsigned char * const buf = new unsigned char[NN];
00502         bytesRead = 0;
00503         readThisTime = 0;
00504         
00505         while (bytesRead<NN)
00506         {
00507             readThisTime = recv( socket_, (char*)(buf + bytesRead), NN-bytesRead, 0 );
00508 
00509             if( readThisTime <= 0 )
00510             {
00511                 // BailOnSocketError definitely throws an exception so clear up heap
00512                 delete[] bufLength;
00513                 delete[] buf;
00514                 BailOnSocketError( "tcpip::Socket::receive() @ recv" );
00515             }
00516 
00517             bytesRead += readThisTime;
00518         }
00519         msg.reset();
00520         msg.writePacket(buf, NN);
00521         
00522         if (verbose_)
00523         {
00524             cerr << "Rcvd Storage with "  << 4 + NN <<  " bytes via tcpip::Socket: [";
00525             for (int i=0; i < 4; ++i)
00526             {
00527                 cerr << " " << (int)bufLength[i] << " ";
00528             }
00529             for (int i=0; i < NN; ++i)
00530             {
00531                 cerr << " " << (int)buf[i] << " ";
00532             }
00533             cerr << "]" << endl;
00534         }
00535 
00536         delete[] buf;
00537         delete[] bufLength;
00538         return true;
00539     }
00540     
00541     
00542     // ----------------------------------------------------------------------
00543     bool 
00544         Socket::
00545 		has_client_connection() 
00546         const
00547     {
00548         return socket_ >= 0;
00549     }
00550 
00551     // ----------------------------------------------------------------------
00552     bool 
00553         Socket::
00554 		is_blocking() 
00555         throw()
00556     {
00557         return blocking_;
00558     }
00559 
00560 
00561 #ifdef WIN32
00562     // ----------------------------------------------------------------------
00563     std::string 
00564         Socket::
00565         GetWinsockErrorString(int err) 
00566         const
00567     {
00568 
00569         switch( err)
00570         {
00571         case 0:                 return "No error";
00572         case WSAEINTR:          return "Interrupted system call";
00573         case WSAEBADF:          return "Bad file number";
00574         case WSAEACCES:         return "Permission denied";
00575         case WSAEFAULT:         return "Bad address";
00576         case WSAEINVAL:         return "Invalid argument";
00577         case WSAEMFILE:         return "Too many open sockets";
00578         case WSAEWOULDBLOCK:    return "Operation would block";
00579         case WSAEINPROGRESS:    return "Operation now in progress";
00580         case WSAEALREADY:       return "Operation already in progress";
00581         case WSAENOTSOCK:       return "Socket operation on non-socket";
00582         case WSAEDESTADDRREQ:   return "Destination address required";
00583         case WSAEMSGSIZE:       return "Message too long";
00584         case WSAEPROTOTYPE:     return "Protocol wrong type for socket";
00585         case WSAENOPROTOOPT:    return "Bad protocol option";
00586         case WSAEPROTONOSUPPORT:    return "Protocol not supported";
00587         case WSAESOCKTNOSUPPORT:    return "Socket type not supported";
00588         case WSAEOPNOTSUPP:     return "Operation not supported on socket";
00589         case WSAEPFNOSUPPORT:   return "Protocol family not supported";
00590         case WSAEAFNOSUPPORT:   return "Address family not supported";
00591         case WSAEADDRINUSE:     return "Address already in use";
00592         case WSAEADDRNOTAVAIL:  return "Can't assign requested address";
00593         case WSAENETDOWN:       return "Network is down";
00594         case WSAENETUNREACH:    return "Network is unreachable";
00595         case WSAENETRESET:      return "Net Socket reset";
00596         case WSAECONNABORTED:   return "Software caused tcpip::Socket abort";
00597         case WSAECONNRESET:     return "Socket reset by peer";
00598         case WSAENOBUFS:        return "No buffer space available";
00599         case WSAEISCONN:        return "Socket is already connected";
00600         case WSAENOTCONN:       return "Socket is not connected";
00601         case WSAESHUTDOWN:      return "Can't send after socket shutdown";
00602         case WSAETOOMANYREFS:   return "Too many references, can't splice";
00603         case WSAETIMEDOUT:      return "Socket timed out";
00604         case WSAECONNREFUSED:   return "Socket refused";
00605         case WSAELOOP:          return "Too many levels of symbolic links";
00606         case WSAENAMETOOLONG:   return "File name too long";
00607         case WSAEHOSTDOWN:      return "Host is down";
00608         case WSAEHOSTUNREACH:   return "No route to host";
00609         case WSAENOTEMPTY:      return "Directory not empty";
00610         case WSAEPROCLIM:       return "Too many processes";
00611         case WSAEUSERS:         return "Too many users";
00612         case WSAEDQUOT:         return "Disc quota exceeded";
00613         case WSAESTALE:         return "Stale NFS file handle";
00614         case WSAEREMOTE:        return "Too many levels of remote in path";
00615         case WSASYSNOTREADY:    return "Network system is unavailable";
00616         case WSAVERNOTSUPPORTED:    return "Winsock version out of range";
00617         case WSANOTINITIALISED: return "WSAStartup not yet called";
00618         case WSAEDISCON:        return "Graceful shutdown in progress";
00619         case WSAHOST_NOT_FOUND: return "Host not found";
00620         case WSANO_DATA:        return "No host data of that type was found";
00621         }
00622 
00623         return "unknown";
00624     }
00625 
00626 #endif // WIN32
00627 
00628 } // namespace tcpip
00629 
00630 #endif // BUILD_TCPIP
00631 
00632 /*-----------------------------------------------------------------------
00633 * Source  $Source: $
00634 * Version $Revision: 385 $
00635 * Date    $Date: 2010-01-13 16:10:20 +0100 (Wed, 13 Jan 2010) $
00636 *-----------------------------------------------------------------------
00637 * $Log: $
00638 *-----------------------------------------------------------------------*/

Generated on Wed May 5 00:06:36 2010 for Sumo - Simulation of Urban MObility by  doxygen 1.5.6