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