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 if( !pProtoEnt )
00130 {
00131 string err( "Error retreiving tcp protocol information" ) ;
00132 throw SocketException( err, __FILE__, __LINE__ ) ;
00133 }
00134
00135 _connected = false;
00136 int descript = socket( AF_INET, SOCK_STREAM, pProtoEnt->p_proto ) ;
00137
00138 if( descript == -1 )
00139 {
00140 string err("getting socket descriptor: ");
00141 const char* error_info = strerror(errno);
00142 if(error_info)
00143 err += (string)error_info;
00144 throw SocketException( err, __FILE__, __LINE__ ) ;
00145 } else {
00146 long holder;
00147 _socket = descript;
00148
00149
00150 holder = fcntl(_socket, F_GETFL, NULL);
00151 holder = holder | O_NONBLOCK;
00152 fcntl(_socket, F_SETFL, holder);
00153
00154 int res = ::connect( descript, (struct sockaddr*)&sin, sizeof( sin ) );
00155
00156
00157 if( res == -1 )
00158 {
00159 if(errno == EINPROGRESS) {
00160
00161 fd_set write_fd ;
00162 struct timeval timeout ;
00163 int maxfd = _socket;
00164
00165 timeout.tv_sec = 5;
00166 timeout.tv_usec = 0;
00167
00168 FD_ZERO( &write_fd);
00169 FD_SET( _socket, &write_fd );
00170
00171 if( select( maxfd+1, NULL, &write_fd, NULL, &timeout) < 0 ) {
00172
00173
00174 holder = fcntl(_socket, F_GETFL, NULL);
00175 holder = holder & (~O_NONBLOCK);
00176 fcntl(_socket, F_SETFL, holder);
00177
00178
00179 string err( "selecting sockets: " ) ;
00180 const char *error_info = strerror( errno ) ;
00181 if( error_info )
00182 err += (string)error_info ;
00183 throw SocketException( err, __FILE__, __LINE__ ) ;
00184
00185 }
00186 else
00187 {
00188
00189
00190 socklen_t lon;
00191 int valopt;
00192 lon = sizeof(int);
00193 getsockopt(_socket, SOL_SOCKET, SO_ERROR, (void*) &valopt, &lon);
00194
00195 if(valopt)
00196 {
00197
00198
00199 holder = fcntl(_socket, F_GETFL, NULL);
00200 holder = holder & (~O_NONBLOCK);
00201 fcntl(_socket, F_SETFL, holder);
00202
00203
00204 string err("Did not successfully connect to server\n");
00205 err += "Server may be down or you may be trying on the wrong port";
00206 throw SocketException( err, __FILE__, __LINE__ ) ;
00207
00208 }
00209 else
00210 {
00211
00212 holder = fcntl(_socket, F_GETFL, NULL);
00213 holder = holder & (~O_NONBLOCK);
00214 fcntl(_socket, F_SETFL, holder);
00215
00216
00217 _connected = true;
00218 }
00219 }
00220 }
00221 else
00222 {
00223
00224
00225 holder = fcntl(_socket, F_GETFL, NULL);
00226 holder = holder & (~O_NONBLOCK);
00227 fcntl(_socket, F_SETFL, holder);
00228
00229
00230 string err("socket connect: ");
00231 const char* error_info = strerror(errno);
00232 if(error_info)
00233 err += (string)error_info;
00234 throw SocketException( err, __FILE__, __LINE__ ) ;
00235 }
00236 }
00237 else
00238 {
00239
00240
00241
00242
00243 holder = fcntl(_socket, F_GETFL, NULL);
00244 holder = holder & (~O_NONBLOCK);
00245 fcntl(_socket, F_SETFL, holder);
00246 _connected = true;
00247 }
00248
00249 }
00250 }
00251
00252 void
00253 TcpSocket::listen()
00254 {
00255 if( _connected )
00256 {
00257 string err( "Socket is already connected" ) ;
00258 throw SocketException( err, __FILE__, __LINE__ ) ;
00259 }
00260
00261 if( _listening )
00262 {
00263 string err( "Socket is already listening" ) ;
00264 throw SocketException( err, __FILE__, __LINE__ ) ;
00265 }
00266
00267 int on = 1 ;
00268 struct sockaddr_in server ;
00269 server.sin_family = AF_INET ;
00270 server.sin_addr.s_addr = INADDR_ANY ;
00271 struct servent *sir = 0 ;
00272 sir = getservbyport( _portVal, "tcp" ) ;
00273 if( sir )
00274 {
00275 string error = sir->s_name + (string)" is using my socket" ;
00276 throw SocketException( error, __FILE__, __LINE__ ) ;
00277 }
00278 server.sin_port = htons( _portVal ) ;
00279 _socket = socket( AF_INET, SOCK_STREAM, 0 ) ;
00280 if( _socket != -1 )
00281 {
00282 if( !setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR,
00283 (char*)&on, sizeof( on ) ) )
00284 {
00285 if( bind( _socket, (struct sockaddr*)&server, sizeof server) != -1 )
00286 {
00287 int length = sizeof( server ) ;
00288 #ifdef _GETSOCKNAME_USES_SOCKLEN_T
00289 if( getsockname( _socket, (struct sockaddr *)&server,
00290 (socklen_t *)&length ) == -1 )
00291 #else
00292 if( getsockname( _socket, (struct sockaddr *)&server,
00293 &length ) == -1 )
00294 #endif
00295 {
00296 string error( "getting socket name" ) ;
00297 const char* error_info = strerror( errno ) ;
00298 if( error_info )
00299 error += " " + (string)error_info ;
00300 throw SocketException( error, __FILE__, __LINE__ ) ;
00301 }
00302 if( ::listen( _socket, 5 ) == 0 )
00303 {
00304 _listening = true ;
00305 }
00306 else
00307 {
00308 string error( "could not listen TCP socket" ) ;
00309 const char* error_info = strerror( errno ) ;
00310 if( error_info )
00311 error += " " + (string)error_info ;
00312 throw SocketException( error, __FILE__, __LINE__ ) ;
00313 }
00314 }
00315 else
00316 {
00317 string error( "could not bind TCP socket" ) ;
00318 const char* error_info = strerror( errno ) ;
00319 if( error_info )
00320 error += " " + (string)error_info ;
00321 throw SocketException( error, __FILE__, __LINE__ ) ;
00322 }
00323 }
00324 else
00325 {
00326 string error( "could not set SO_REUSEADDR on TCP socket" ) ;
00327 const char* error_info = strerror( errno ) ;
00328 if( error_info )
00329 error += " " + (string)error_info ;
00330 throw SocketException( error, __FILE__, __LINE__ ) ;
00331 }
00332 }
00333 else
00334 {
00335 string error( "could not create socket" ) ;
00336 const char *error_info = strerror( errno ) ;
00337 if( error_info )
00338 error += " " + (string)error_info ;
00339 throw SocketException( error, __FILE__, __LINE__ ) ;
00340 }
00341 }
00342
00349 void
00350 TcpSocket::dump( ostream &strm ) const
00351 {
00352 strm << BESIndent::LMarg << "TcpSocket::dump - ("
00353 << (void *)this << ")" << endl ;
00354 BESIndent::Indent() ;
00355 strm << BESIndent::LMarg << "host: " << _host << endl ;
00356 strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00357 Socket::dump( strm ) ;
00358 BESIndent::UnIndent() ;
00359 }
00360