OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // TcpSocket.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 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 unsigned int sockbufsize = 0 ; 00161 int size = sizeof(int) ; 00162 int err = getsockopt( descript, IPPROTO_TCP, TCP_MAXSEG, 00163 (void *)&sockbufsize, (socklen_t*)&size) ; 00164 cerr << "max size of tcp segment = " << sockbufsize << endl ; 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 //set socket to non-blocking mode 00179 holder = fcntl(_socket, F_GETFL, NULL); 00180 holder = holder | O_NONBLOCK; 00181 fcntl(_socket, F_SETFL, holder); 00182 00183 // we must set the send and receive buffer sizes before the connect call 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 //reset socket to blocking mode 00207 holder = fcntl(_socket, F_GETFL, NULL); 00208 holder = holder & (~O_NONBLOCK); 00209 fcntl(_socket, F_SETFL, holder); 00210 00211 //throw error - select could not resolve socket 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 //check socket status 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 //reset socket to blocking mode 00232 holder = fcntl(_socket, F_GETFL, NULL); 00233 holder = holder & (~O_NONBLOCK); 00234 fcntl(_socket, F_SETFL, holder); 00235 00236 //throw error - did not successfully connect 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 //reset socket to blocking mode 00245 holder = fcntl(_socket, F_GETFL, NULL); 00246 holder = holder & (~O_NONBLOCK); 00247 fcntl(_socket, F_SETFL, holder); 00248 00249 //succesful connetion to server 00250 _connected = true; 00251 } 00252 } 00253 } 00254 else 00255 { 00256 00257 //reset socket to blocking mode 00258 holder = fcntl(_socket, F_GETFL, NULL); 00259 holder = holder & (~O_NONBLOCK); 00260 fcntl(_socket, F_SETFL, holder); 00261 00262 //throw error - errno was not EINPROGRESS 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 // The socket connect request completed immediately 00273 // even that the socket was in non-blocking mode 00274 00275 //reset socket to blocking mode 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 // The send and receive buffer sizes must be set before the call to 00343 // ::listen. 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 TheBESKeys::TheKeys()->get_value( "BES.SetSockRecvSize", 00407 setit, found); 00408 } 00409 catch( ... ) 00410 { 00411 // ignore any exceptions caught trying to get this key. The 00412 // client also calls this function. 00413 setit = "No" ; 00414 } 00415 if( setit == "Yes" || setit == "yes" || setit == "Yes" ) 00416 { 00417 found = false ; 00418 string sizestr ; 00419 TheBESKeys::TheKeys()->get_value( "BES.SockRecvSize", 00420 sizestr, found ) ; 00421 istringstream sizestrm( sizestr ) ; 00422 unsigned int sizenum = 0 ; 00423 sizestrm >> sizenum ; 00424 if( !sizenum ) 00425 { 00426 string err = "Socket Recv Size malformed: " + sizestr ; 00427 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ; 00428 } 00429 00430 // call setsockopt 00431 int err = setsockopt( _socket, SOL_SOCKET, SO_RCVBUF, 00432 (char *)&sizenum, (socklen_t)sizeof(sizenum) ) ; 00433 int myerrno = errno ; 00434 if( err == -1 ) 00435 { 00436 char *serr = strerror( myerrno ) ; 00437 string err = "Failed to set the socket receive buffer size: " ; 00438 if( serr ) 00439 err += serr ; 00440 else 00441 err += "unknow error occurred" ; 00442 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ; 00443 } 00444 00445 BESDEBUG( "ppt", "Tcp receive buffer size set to " 00446 << (unsigned long)sizenum << endl ) ; 00447 } 00448 } 00449 } 00450 00469 void 00470 TcpSocket::setTcpSendBufferSize() 00471 { 00472 bool found = false ; 00473 vector<string> vals ; 00474 string setit ; 00475 try 00476 { 00477 TheBESKeys::TheKeys()->get_value( "BES.SetSockSendSize", setit, found ); 00478 } 00479 catch( ... ) 00480 { 00481 // ignore any exceptions caught trying to get this key. The 00482 // client also calls this function. 00483 setit = "No" ; 00484 } 00485 if( setit == "Yes" || setit == "yes" || setit == "Yes" ) 00486 { 00487 found = false ; 00488 string sizestr ; 00489 try 00490 { 00491 TheBESKeys::TheKeys()->get_value( "BES.SockSendSize", sizestr, found ) ; 00492 } 00493 catch( BESError &e ) 00494 { 00495 throw BESInternalFatalError( e.get_message(), e.get_file(), 00496 e.get_line() ) ; 00497 } 00498 istringstream sizestrm( sizestr ) ; 00499 unsigned int sizenum = 0 ; 00500 sizestrm >> sizenum ; 00501 if( !sizenum ) 00502 { 00503 string err = "Socket Send Size malformed: " + sizestr ; 00504 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ; 00505 } 00506 00507 // call setsockopt 00508 int err = setsockopt( _socket, SOL_SOCKET, SO_SNDBUF, 00509 (char *)&sizenum, (socklen_t)sizeof(sizenum) ) ; 00510 int myerrno = errno ; 00511 if( err == -1 ) 00512 { 00513 char *serr = strerror( myerrno ) ; 00514 string err = "Failed to set the socket send buffer size: " ; 00515 if( serr ) 00516 err += serr ; 00517 else 00518 err += "unknow error occurred" ; 00519 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ; 00520 } 00521 00522 BESDEBUG( "ppt", "Tcp send buffer size set to " 00523 << (unsigned long)sizenum << endl ) ; 00524 } 00525 } 00526 00535 unsigned int 00536 TcpSocket::getRecvBufferSize() 00537 { 00538 if( !_haveRecvBufferSize ) 00539 { 00540 // call getsockopt and set the internal variables to the result 00541 unsigned int sizenum = 0 ; 00542 socklen_t sizelen = sizeof(sizenum) ; 00543 int err = getsockopt( _socket, SOL_SOCKET, SO_RCVBUF, 00544 (char *)&sizenum, (socklen_t *)&sizelen ) ; 00545 int myerrno = errno ; 00546 if( err == -1 ) 00547 { 00548 char *serr = strerror( myerrno ) ; 00549 string err = "Failed to get the socket receive buffer size: " ; 00550 if( serr ) 00551 err += serr ; 00552 else 00553 err += "unknow error occurred" ; 00554 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ; 00555 } 00556 00557 BESDEBUG( "ppt", "Tcp receive buffer size is " 00558 << (unsigned long)sizenum << endl ) ; 00559 00560 _haveRecvBufferSize = true ; 00561 _recvBufferSize = sizenum ; 00562 } 00563 return _recvBufferSize ; 00564 } 00565 00574 unsigned int 00575 TcpSocket::getSendBufferSize() 00576 { 00577 if( !_haveSendBufferSize ) 00578 { 00579 // call getsockopt and set the internal variables to the result 00580 unsigned int sizenum = 0 ; 00581 socklen_t sizelen = sizeof(sizenum) ; 00582 int err = getsockopt( _socket, SOL_SOCKET, SO_SNDBUF, 00583 (char *)&sizenum, (socklen_t *)&sizelen ) ; 00584 int myerrno = errno ; 00585 if( err == -1 ) 00586 { 00587 char *serr = strerror( myerrno ) ; 00588 string err = "Failed to get the socket send buffer size: " ; 00589 if( serr ) 00590 err += serr ; 00591 else 00592 err += "unknow error occurred" ; 00593 throw BESInternalFatalError( err, __FILE__, __LINE__ ) ; 00594 } 00595 00596 BESDEBUG( "ppt", "Tcp send buffer size is " 00597 << (unsigned long)sizenum << endl ) ; 00598 00599 _haveSendBufferSize = true ; 00600 _sendBufferSize = sizenum ; 00601 } 00602 return _sendBufferSize ; 00603 } 00604 00608 bool 00609 TcpSocket::allowConnection() 00610 { 00611 bool retval = true ; 00612 00613 #ifdef HAVE_LIBWRAP 00614 struct request_info req ; 00615 request_init( &req, RQ_DAEMON, "besdaemon", RQ_FILE, 00616 getSocketDescriptor(), 0 ) ; 00617 fromhost() ; 00618 00619 if( STR_EQ( eval_hostname(), paranoid ) && hosts_access() ) 00620 { 00621 retval = false ; 00622 } 00623 #endif 00624 00625 return retval ; 00626 } 00627 00634 void 00635 TcpSocket::dump( ostream &strm ) const 00636 { 00637 strm << BESIndent::LMarg << "TcpSocket::dump - (" 00638 << (void *)this << ")" << endl ; 00639 BESIndent::Indent() ; 00640 strm << BESIndent::LMarg << "host: " << _host << endl ; 00641 strm << BESIndent::LMarg << "port: " << _portVal << endl ; 00642 strm << BESIndent::LMarg << "have recv buffer size: " << _haveRecvBufferSize 00643 << endl ; 00644 strm << BESIndent::LMarg << "recv buffer size: " << _recvBufferSize 00645 << endl ; 00646 strm << BESIndent::LMarg << "have send buffer size: " << _haveSendBufferSize 00647 << endl ; 00648 strm << BESIndent::LMarg << "send buffer size: " << _sendBufferSize 00649 << endl ; 00650 Socket::dump( strm ) ; 00651 BESIndent::UnIndent() ; 00652 } 00653