00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <ctype.h>
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <netinet/in.h>
00037 #include <arpa/inet.h>
00038 #include <netdb.h>
00039 #include <errno.h>
00040 #include <fcntl.h>
00041
00042 #include "TcpSocket.h"
00043 #include "SocketConfig.h"
00044 #include "SocketException.h"
00045
00046 void
00047 TcpSocket::connect()
00048 {
00049 if( _listening )
00050 {
00051 string err( "Socket is already listening" ) ;
00052 throw SocketException( err, __FILE__, __LINE__ ) ;
00053 }
00054
00055 if( _connected )
00056 {
00057 string err( "Socket is already connected" ) ;
00058 throw SocketException( err, __FILE__, __LINE__ ) ;
00059 }
00060
00061 if( _host == "" )
00062 _host = "localhost" ;
00063
00064 struct protoent *pProtoEnt ;
00065 struct sockaddr_in sin ;
00066 struct hostent *ph ;
00067 long address ;
00068 if( isdigit( _host[0] ) )
00069 {
00070 if( ( address = inet_addr( _host.c_str() ) ) == -1 )
00071 {
00072 string err( "Invalid host ip address " ) ;
00073 err += _host ;
00074 throw SocketException( err, __FILE__, __LINE__ ) ;
00075 }
00076 sin.sin_addr.s_addr = address ;
00077 sin.sin_family = AF_INET ;
00078 }
00079 else
00080 {
00081 if( ( ph = gethostbyname( _host.c_str() ) ) == NULL )
00082 {
00083 switch( h_errno )
00084 {
00085 case HOST_NOT_FOUND:
00086 {
00087 string err( "No such host " ) ;
00088 err += _host ;
00089 throw SocketException( err, __FILE__, __LINE__ ) ;
00090 }
00091 case TRY_AGAIN:
00092 {
00093 string err( "Host " ) ;
00094 err += _host + " is busy, try again later" ;
00095 throw SocketException( err, __FILE__, __LINE__ ) ;
00096 }
00097 case NO_RECOVERY:
00098 {
00099 string err( "DNS error for host " ) ;
00100 err += _host ;
00101 throw SocketException( err, __FILE__, __LINE__ ) ;
00102 }
00103 case NO_ADDRESS:
00104 {
00105 string err( "No IP address for host " ) ;
00106 err += _host ;
00107 throw SocketException( err, __FILE__, __LINE__ ) ;
00108 }
00109 default:
00110 {
00111 throw SocketException( "unknown error", __FILE__, __LINE__ ) ;
00112 }
00113 }
00114 }
00115 else
00116 {
00117 sin.sin_family = ph->h_addrtype ;
00118 for( char **p =ph->h_addr_list; *p != NULL; p++ )
00119 {
00120 struct in_addr in ;
00121 (void)memcpy( &in.s_addr, *p, sizeof( in.s_addr ) ) ;
00122 memcpy( (char*)&sin.sin_addr, (char*)&in, sizeof( in ) ) ;
00123 }
00124 }
00125 }
00126
00127 sin.sin_port = htons( _portVal ) ;
00128 pProtoEnt = getprotobyname( "tcp" ) ;
00129
00130 _connected = false;
00131 int descript = socket( AF_INET, SOCK_STREAM, pProtoEnt->p_proto ) ;
00132
00133 if( descript == -1 )
00134 {
00135 string err("getting socket descriptor: ");
00136 const char* error_info = strerror(errno);
00137 if(error_info)
00138 err += (string)error_info;
00139 throw SocketException( err, __FILE__, __LINE__ ) ;
00140 } else {
00141 long holder;
00142 _socket = descript;
00143
00144
00145 holder = fcntl(_socket, F_GETFL, NULL);
00146 holder = holder | O_NONBLOCK;
00147 fcntl(_socket, F_SETFL, holder);
00148
00149 int res = ::connect( descript, (struct sockaddr*)&sin, sizeof( sin ) );
00150
00151
00152 if( res == -1 )
00153 {
00154 if(errno == EINPROGRESS) {
00155
00156 fd_set write_fd ;
00157 struct timeval timeout ;
00158 int maxfd = _socket;
00159
00160 timeout.tv_sec = 5;
00161 timeout.tv_usec = 0;
00162
00163 FD_ZERO( &write_fd);
00164 FD_SET( _socket, &write_fd );
00165
00166 if( select( maxfd+1, NULL, &write_fd, NULL, &timeout) < 0 ) {
00167
00168
00169 holder = fcntl(_socket, F_GETFL, NULL);
00170 holder = holder & (~O_NONBLOCK);
00171 fcntl(_socket, F_SETFL, holder);
00172
00173
00174 string err( "selecting sockets: " ) ;
00175 const char *error_info = strerror( errno ) ;
00176 if( error_info )
00177 err += (string)error_info ;
00178 throw SocketException( err, __FILE__, __LINE__ ) ;
00179
00180 }
00181 else
00182 {
00183
00184
00185 socklen_t lon;
00186 int valopt;
00187 lon = sizeof(int);
00188 getsockopt(_socket, SOL_SOCKET, SO_ERROR, (void*) &valopt, &lon);
00189
00190 if(valopt)
00191 {
00192
00193
00194 holder = fcntl(_socket, F_GETFL, NULL);
00195 holder = holder & (~O_NONBLOCK);
00196 fcntl(_socket, F_SETFL, holder);
00197
00198
00199 string err("Did not successfully connect to server\n");
00200 err += "Server may be down or you may be trying on the wrong port";
00201 throw SocketException( err, __FILE__, __LINE__ ) ;
00202
00203 }
00204 else
00205 {
00206
00207 holder = fcntl(_socket, F_GETFL, NULL);
00208 holder = holder & (~O_NONBLOCK);
00209 fcntl(_socket, F_SETFL, holder);
00210
00211
00212 _connected = true;
00213 }
00214 }
00215 }
00216 else
00217 {
00218
00219
00220 holder = fcntl(_socket, F_GETFL, NULL);
00221 holder = holder & (~O_NONBLOCK);
00222 fcntl(_socket, F_SETFL, holder);
00223
00224
00225 string err("socket connect: ");
00226 const char* error_info = strerror(errno);
00227 if(error_info)
00228 err += (string)error_info;
00229 throw SocketException( err, __FILE__, __LINE__ ) ;
00230 }
00231 }
00232 else
00233 {
00234
00235
00236
00237
00238 holder = fcntl(_socket, F_GETFL, NULL);
00239 holder = holder & (~O_NONBLOCK);
00240 fcntl(_socket, F_SETFL, holder);
00241 _connected = true;
00242 }
00243
00244 }
00245 }
00246
00247 void
00248 TcpSocket::listen()
00249 {
00250 if( _connected )
00251 {
00252 string err( "Socket is already connected" ) ;
00253 throw SocketException( err, __FILE__, __LINE__ ) ;
00254 }
00255
00256 if( _listening )
00257 {
00258 string err( "Socket is already listening" ) ;
00259 throw SocketException( err, __FILE__, __LINE__ ) ;
00260 }
00261
00262 int on = 1 ;
00263 struct sockaddr_in server ;
00264 server.sin_family = AF_INET ;
00265 server.sin_addr.s_addr = INADDR_ANY ;
00266 struct servent *sir = 0 ;
00267 sir = getservbyport( _portVal, "tcp" ) ;
00268 if( sir )
00269 {
00270 string error = sir->s_name + (string)" is using my socket" ;
00271 throw SocketException( error, __FILE__, __LINE__ ) ;
00272 }
00273 server.sin_port = htons( _portVal ) ;
00274 _socket = socket( AF_INET, SOCK_STREAM, 0 ) ;
00275 if( _socket != -1 )
00276 {
00277 if( !setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR,
00278 (char*)&on, sizeof( on ) ) )
00279 {
00280 if( bind( _socket, (struct sockaddr*)&server, sizeof server) != -1 )
00281 {
00282 int length = sizeof( server ) ;
00283 #ifdef _GETSOCKNAME_USES_SOCKLEN_T
00284 if( getsockname( _socket, (struct sockaddr *)&server,
00285 (socklen_t *)&length ) == -1 )
00286 #else
00287 if( getsockname( _socket, (struct sockaddr *)&server,
00288 &length ) == -1 )
00289 #endif
00290 {
00291 string error( "getting socket name" ) ;
00292 const char* error_info = strerror( errno ) ;
00293 if( error_info )
00294 error += " " + (string)error_info ;
00295 throw SocketException( error, __FILE__, __LINE__ ) ;
00296 }
00297 if( ::listen( _socket, 5 ) == 0 )
00298 {
00299 _listening = true ;
00300 }
00301 else
00302 {
00303 string error( "could not listen TCP socket" ) ;
00304 const char* error_info = strerror( errno ) ;
00305 if( error_info )
00306 error += " " + (string)error_info ;
00307 throw SocketException( error, __FILE__, __LINE__ ) ;
00308 }
00309 }
00310 else
00311 {
00312 string error( "could not bind TCP socket" ) ;
00313 const char* error_info = strerror( errno ) ;
00314 if( error_info )
00315 error += " " + (string)error_info ;
00316 throw SocketException( error, __FILE__, __LINE__ ) ;
00317 }
00318 }
00319 else
00320 {
00321 string error( "could not set SO_REUSEADDR on TCP socket" ) ;
00322 const char* error_info = strerror( errno ) ;
00323 if( error_info )
00324 error += " " + (string)error_info ;
00325 throw SocketException( error, __FILE__, __LINE__ ) ;
00326 }
00327 }
00328 else
00329 {
00330 string error( "could not create socket" ) ;
00331 const char *error_info = strerror( errno ) ;
00332 if( error_info )
00333 error += " " + (string)error_info ;
00334 throw SocketException( error, __FILE__, __LINE__ ) ;
00335 }
00336 }
00337
00344 void
00345 TcpSocket::dump( ostream &strm ) const
00346 {
00347 strm << BESIndent::LMarg << "TcpSocket::dump - ("
00348 << (void *)this << ")" << endl ;
00349 BESIndent::Indent() ;
00350 strm << BESIndent::LMarg << "host: " << _host << endl ;
00351 strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00352 Socket::dump( strm ) ;
00353 BESIndent::UnIndent() ;
00354 }
00355