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 #include <netinet/tcp.h>
00041
00042 #ifdef HAVE_LIBWRAP
00043 extern "C" {
00044 #include "tcpd.h"
00045 int allow_severity;
00046 int deny_severity;
00047 }
00048 #endif
00049
00050 #include <cstring>
00051 #include <cerrno>
00052
00053 #include <iostream>
00054 #include <sstream>
00055
00056 using std::cerr ;
00057 using std::endl ;
00058 using std::istringstream ;
00059
00060 #include "TcpSocket.h"
00061 #include "SocketConfig.h"
00062 #include "TheBESKeys.h"
00063 #include "BESDebug.h"
00064 #include "BESInternalError.h"
00065 #include "BESInternalFatalError.h"
00066
00067 void
00068 TcpSocket::connect()
00069 {
00070 if( _listening )
00071 {
00072 string err( "Socket is already listening" ) ;
00073 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00074 }
00075
00076 if( _connected )
00077 {
00078 string err( "Socket is already connected" ) ;
00079 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00080 }
00081
00082 if( _host == "" )
00083 _host = "localhost" ;
00084
00085 struct protoent *pProtoEnt ;
00086 struct sockaddr_in sin ;
00087 struct hostent *ph ;
00088 long address ;
00089 if( isdigit( _host[0] ) )
00090 {
00091 if( ( address = inet_addr( _host.c_str() ) ) == -1 )
00092 {
00093 string err( "Invalid host ip address " ) ;
00094 err += _host ;
00095 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00096 }
00097 sin.sin_addr.s_addr = address ;
00098 sin.sin_family = AF_INET ;
00099 }
00100 else
00101 {
00102 if( ( ph = gethostbyname( _host.c_str() ) ) == NULL )
00103 {
00104 switch( h_errno )
00105 {
00106 case HOST_NOT_FOUND:
00107 {
00108 string err( "No such host " ) ;
00109 err += _host ;
00110 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00111 }
00112 case TRY_AGAIN:
00113 {
00114 string err( "Host " ) ;
00115 err += _host + " is busy, try again later" ;
00116 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00117 }
00118 case NO_RECOVERY:
00119 {
00120 string err( "DNS error for host " ) ;
00121 err += _host ;
00122 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00123 }
00124 case NO_ADDRESS:
00125 {
00126 string err( "No IP address for host " ) ;
00127 err += _host ;
00128 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00129 }
00130 default:
00131 {
00132 throw BESInternalError( "unknown error", __FILE__, __LINE__ ) ;
00133 }
00134 }
00135 }
00136 else
00137 {
00138 sin.sin_family = ph->h_addrtype ;
00139 for( char **p =ph->h_addr_list; *p != NULL; p++ )
00140 {
00141 struct in_addr in ;
00142 (void)memcpy( &in.s_addr, *p, sizeof( in.s_addr ) ) ;
00143 memcpy( (char*)&sin.sin_addr, (char*)&in, sizeof( in ) ) ;
00144 }
00145 }
00146 }
00147
00148 sin.sin_port = htons( _portVal ) ;
00149 pProtoEnt = getprotobyname( "tcp" ) ;
00150 if( !pProtoEnt )
00151 {
00152 string err( "Error retreiving tcp protocol information" ) ;
00153 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00154 }
00155
00156 _connected = false;
00157 int descript = socket( AF_INET, SOCK_STREAM, pProtoEnt->p_proto ) ;
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 if( descript == -1 )
00168 {
00169 string err("getting socket descriptor: ");
00170 const char* error_info = strerror(errno);
00171 if(error_info)
00172 err += (string)error_info;
00173 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00174 } else {
00175 long holder;
00176 _socket = descript;
00177
00178
00179 holder = fcntl(_socket, F_GETFL, NULL);
00180 holder = holder | O_NONBLOCK;
00181 fcntl(_socket, F_SETFL, holder);
00182
00183
00184 setTcpRecvBufferSize( ) ;
00185 setTcpSendBufferSize( ) ;
00186
00187 int res = ::connect( descript, (struct sockaddr*)&sin, sizeof( sin ) );
00188
00189
00190 if( res == -1 )
00191 {
00192 if(errno == EINPROGRESS) {
00193
00194 fd_set write_fd ;
00195 struct timeval timeout ;
00196 int maxfd = _socket;
00197
00198 timeout.tv_sec = 5;
00199 timeout.tv_usec = 0;
00200
00201 FD_ZERO( &write_fd);
00202 FD_SET( _socket, &write_fd );
00203
00204 if( select( maxfd+1, NULL, &write_fd, NULL, &timeout) < 0 ) {
00205
00206
00207 holder = fcntl(_socket, F_GETFL, NULL);
00208 holder = holder & (~O_NONBLOCK);
00209 fcntl(_socket, F_SETFL, holder);
00210
00211
00212 string err( "selecting sockets: " ) ;
00213 const char *error_info = strerror( errno ) ;
00214 if( error_info )
00215 err += (string)error_info ;
00216 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00217
00218 }
00219 else
00220 {
00221
00222
00223 socklen_t lon;
00224 int valopt;
00225 lon = sizeof(int);
00226 getsockopt(_socket, SOL_SOCKET, SO_ERROR, (void*) &valopt, &lon);
00227
00228 if(valopt)
00229 {
00230
00231
00232 holder = fcntl(_socket, F_GETFL, NULL);
00233 holder = holder & (~O_NONBLOCK);
00234 fcntl(_socket, F_SETFL, holder);
00235
00236
00237 string err("Did not successfully connect to server\n");
00238 err += "Server may be down or you may be trying on the wrong port";
00239 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00240
00241 }
00242 else
00243 {
00244
00245 holder = fcntl(_socket, F_GETFL, NULL);
00246 holder = holder & (~O_NONBLOCK);
00247 fcntl(_socket, F_SETFL, holder);
00248
00249
00250 _connected = true;
00251 }
00252 }
00253 }
00254 else
00255 {
00256
00257
00258 holder = fcntl(_socket, F_GETFL, NULL);
00259 holder = holder & (~O_NONBLOCK);
00260 fcntl(_socket, F_SETFL, holder);
00261
00262
00263 string err("socket connect: ");
00264 const char* error_info = strerror(errno);
00265 if(error_info)
00266 err += (string)error_info;
00267 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00268 }
00269 }
00270 else
00271 {
00272
00273
00274
00275
00276 holder = fcntl(_socket, F_GETFL, NULL);
00277 holder = holder & (~O_NONBLOCK);
00278 fcntl(_socket, F_SETFL, holder);
00279 _connected = true;
00280 }
00281 }
00282 }
00283
00284 void
00285 TcpSocket::listen()
00286 {
00287 if( _connected )
00288 {
00289 string err( "Socket is already connected" ) ;
00290 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00291 }
00292
00293 if( _listening )
00294 {
00295 string err( "Socket is already listening" ) ;
00296 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00297 }
00298
00299 int on = 1 ;
00300 struct sockaddr_in server ;
00301 server.sin_family = AF_INET ;
00302 server.sin_addr.s_addr = INADDR_ANY ;
00303 struct servent *sir = 0 ;
00304 sir = getservbyport( _portVal, "tcp" ) ;
00305 if( sir )
00306 {
00307 string error = sir->s_name + (string)" is using my socket" ;
00308 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00309 }
00310 server.sin_port = htons( _portVal ) ;
00311 _socket = socket( AF_INET, SOCK_STREAM, 0 ) ;
00312 if( _socket != -1 )
00313 {
00314 if( setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR,
00315 (char*)&on, sizeof( on ) ) )
00316 {
00317 string error( "could not set SO_REUSEADDR on TCP socket" ) ;
00318 const char* error_info = strerror( errno ) ;
00319 if( error_info )
00320 error += " " + (string)error_info ;
00321 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00322 }
00323
00324 if( bind( _socket, (struct sockaddr*)&server, sizeof server) != -1 )
00325 {
00326 int length = sizeof( server ) ;
00327 #ifdef _GETSOCKNAME_USES_SOCKLEN_T
00328 if( getsockname( _socket, (struct sockaddr *)&server,
00329 (socklen_t *)&length ) == -1 )
00330 #else
00331 if( getsockname( _socket, (struct sockaddr *)&server,
00332 &length ) == -1 )
00333 #endif
00334 {
00335 string error( "getting socket name" ) ;
00336 const char* error_info = strerror( errno ) ;
00337 if( error_info )
00338 error += " " + (string)error_info ;
00339 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00340 }
00341
00342
00343
00344 setTcpRecvBufferSize( ) ;
00345 setTcpSendBufferSize( ) ;
00346
00347 if( ::listen( _socket, 5 ) == 0 )
00348 {
00349 _listening = true ;
00350 }
00351 else
00352 {
00353 string error( "could not listen TCP socket" ) ;
00354 const char* error_info = strerror( errno ) ;
00355 if( error_info )
00356 error += " " + (string)error_info ;
00357 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00358 }
00359 }
00360 else
00361 {
00362 string error( "could not bind TCP socket" ) ;
00363 const char* error_info = strerror( errno ) ;
00364 if( error_info )
00365 error += " " + (string)error_info ;
00366 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00367 }
00368 }
00369 else
00370 {
00371 string error( "could not create socket" ) ;
00372 const char *error_info = strerror( errno ) ;
00373 if( error_info )
00374 error += " " + (string)error_info ;
00375 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00376 }
00377 }
00378
00397 void
00398 TcpSocket::setTcpRecvBufferSize()
00399 {
00400 if( !_haveRecvBufferSize )
00401 {
00402 bool found = false ;
00403 string setit ;
00404 try
00405 {
00406 setit = TheBESKeys::TheKeys()->get_key( "BES.SetSockRecvSize", found );
00407 }
00408 catch( ... )
00409 {
00410
00411
00412 setit = "No" ;
00413 }
00414 if( setit == "Yes" || setit == "yes" || setit == "Yes" )
00415 {
00416 string sizestr
00417 = TheBESKeys::TheKeys()->get_key( "BES.SockRecvSize", found ) ;
00418 istringstream sizestrm( sizestr ) ;
00419 unsigned int sizenum = 0 ;
00420 sizestrm >> sizenum ;
00421 if( !sizenum )
00422 {
00423 string err = "Socket Recv Size malformed: " + sizestr ;
00424 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ;
00425 }
00426
00427
00428 int err = setsockopt( _socket, SOL_SOCKET, SO_RCVBUF,
00429 (char *)&sizenum, (socklen_t)sizeof(sizenum) ) ;
00430 int myerrno = errno ;
00431 if( err == -1 )
00432 {
00433 char *serr = strerror( myerrno ) ;
00434 string err = "Failed to set the socket receive buffer size: " ;
00435 if( serr )
00436 err += serr ;
00437 else
00438 err += "unknow error occurred" ;
00439 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ;
00440 }
00441
00442 BESDEBUG( "ppt", "Tcp receive buffer size set to "
00443 << (unsigned long)sizenum << endl )
00444 }
00445 }
00446 }
00447
00466 void
00467 TcpSocket::setTcpSendBufferSize()
00468 {
00469 bool found = false ;
00470 string setit ;
00471 try
00472 {
00473 setit = TheBESKeys::TheKeys()->get_key( "BES.SetSockSendSize", found );
00474 }
00475 catch( ... )
00476 {
00477
00478
00479 setit = "No" ;
00480 }
00481 if( setit == "Yes" || setit == "yes" || setit == "Yes" )
00482 {
00483 string sizestr
00484 = TheBESKeys::TheKeys()->get_key( "BES.SockSendSize", found ) ;
00485 istringstream sizestrm( sizestr ) ;
00486 unsigned int sizenum = 0 ;
00487 sizestrm >> sizenum ;
00488 if( !sizenum )
00489 {
00490 string err = "Socket Send Size malformed: " + sizestr ;
00491 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ;
00492 }
00493
00494
00495 int err = setsockopt( _socket, SOL_SOCKET, SO_SNDBUF,
00496 (char *)&sizenum, (socklen_t)sizeof(sizenum) ) ;
00497 int myerrno = errno ;
00498 if( err == -1 )
00499 {
00500 char *serr = strerror( myerrno ) ;
00501 string err = "Failed to set the socket send buffer size: " ;
00502 if( serr )
00503 err += serr ;
00504 else
00505 err += "unknow error occurred" ;
00506 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ;
00507 }
00508
00509 BESDEBUG( "ppt", "Tcp send buffer size set to "
00510 << (unsigned long)sizenum << endl )
00511 }
00512 }
00513
00522 unsigned int
00523 TcpSocket::getRecvBufferSize()
00524 {
00525 if( !_haveRecvBufferSize )
00526 {
00527
00528 unsigned int sizenum = 0 ;
00529 socklen_t sizelen = sizeof(sizenum) ;
00530 int err = getsockopt( _socket, SOL_SOCKET, SO_RCVBUF,
00531 (char *)&sizenum, (socklen_t *)&sizelen ) ;
00532 int myerrno = errno ;
00533 if( err == -1 )
00534 {
00535 char *serr = strerror( myerrno ) ;
00536 string err = "Failed to get the socket receive buffer size: " ;
00537 if( serr )
00538 err += serr ;
00539 else
00540 err += "unknow error occurred" ;
00541 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ;
00542 }
00543
00544 BESDEBUG( "ppt", "Tcp receive buffer size is "
00545 << (unsigned long)sizenum << endl )
00546
00547 _haveRecvBufferSize = true ;
00548 _recvBufferSize = sizenum ;
00549 }
00550 return _recvBufferSize ;
00551 }
00552
00561 unsigned int
00562 TcpSocket::getSendBufferSize()
00563 {
00564 if( !_haveSendBufferSize )
00565 {
00566
00567 unsigned int sizenum = 0 ;
00568 socklen_t sizelen = sizeof(sizenum) ;
00569 int err = getsockopt( _socket, SOL_SOCKET, SO_SNDBUF,
00570 (char *)&sizenum, (socklen_t *)&sizelen ) ;
00571 int myerrno = errno ;
00572 if( err == -1 )
00573 {
00574 char *serr = strerror( myerrno ) ;
00575 string err = "Failed to get the socket send buffer size: " ;
00576 if( serr )
00577 err += serr ;
00578 else
00579 err += "unknow error occurred" ;
00580 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ;
00581 }
00582
00583 BESDEBUG( "ppt", "Tcp send buffer size is "
00584 << (unsigned long)sizenum << endl )
00585
00586 _haveSendBufferSize = true ;
00587 _sendBufferSize = sizenum ;
00588 }
00589 return _sendBufferSize ;
00590 }
00591
00595 bool
00596 TcpSocket::allowConnection()
00597 {
00598 bool retval = true ;
00599
00600 #ifdef HAVE_LIBWRAP
00601 struct request_info req ;
00602 request_init( &req, RQ_DAEMON, "besdaemon", RQ_FILE,
00603 getSocketDescriptor(), 0 ) ;
00604 fromhost() ;
00605
00606 if( STR_EQ( eval_hostname(), paranoid ) && hosts_access() )
00607 {
00608 retval = false ;
00609 }
00610 #endif
00611
00612 return retval ;
00613 }
00614
00621 void
00622 TcpSocket::dump( ostream &strm ) const
00623 {
00624 strm << BESIndent::LMarg << "TcpSocket::dump - ("
00625 << (void *)this << ")" << endl ;
00626 BESIndent::Indent() ;
00627 strm << BESIndent::LMarg << "host: " << _host << endl ;
00628 strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00629 strm << BESIndent::LMarg << "have recv buffer size: " << _haveRecvBufferSize
00630 << endl ;
00631 strm << BESIndent::LMarg << "recv buffer size: " << _recvBufferSize
00632 << endl ;
00633 strm << BESIndent::LMarg << "have send buffer size: " << _haveSendBufferSize
00634 << endl ;
00635 strm << BESIndent::LMarg << "send buffer size: " << _sendBufferSize
00636 << endl ;
00637 Socket::dump( strm ) ;
00638 BESIndent::UnIndent() ;
00639 }
00640