OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // UnixSocket.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 // szednik Stephan Zednik <zednik@ucar.edu> 00033 00034 #include <unistd.h> // for unlink 00035 #include <sys/un.h> 00036 #include <sys/socket.h> 00037 #include <sys/types.h> 00038 00039 #include <cstdio> 00040 #include <cerrno> 00041 #include <cstring> 00042 00043 #include "UnixSocket.h" 00044 #include "BESInternalError.h" 00045 #include "SocketUtilities.h" 00046 00047 void 00048 UnixSocket::connect() 00049 { 00050 if( _listening ) 00051 { 00052 string err( "Socket is already listening" ) ; 00053 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00054 } 00055 00056 if( _connected ) 00057 { 00058 string err( "Socket is already connected" ) ; 00059 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00060 } 00061 00062 struct sockaddr_un client_addr ; 00063 struct sockaddr_un server_addr ; 00064 00065 // what is the max size of the path to the unix socket 00066 unsigned int max_len = sizeof( client_addr.sun_path ) ; 00067 00068 char path[107] = "" ; 00069 getcwd( path, sizeof( path ) ) ; 00070 _tempSocket = path ; 00071 _tempSocket += "/" ; 00072 _tempSocket += SocketUtilities::create_temp_name() ; 00073 _tempSocket += ".unixSocket" ; 00074 // maximum path for struct sockaddr_un.sun_path is 108 00075 // get sure we will not exceed to max for creating sockets 00076 // 107 characters in pathname + '\0' 00077 if( _tempSocket.length() > max_len - 1 ) 00078 { 00079 string msg = "path to temporary unix socket " ; 00080 msg += _tempSocket + " is too long" ; 00081 throw( BESInternalError( msg, __FILE__, __LINE__ ) ) ; 00082 } 00083 if( _unixSocket.length() > max_len - 1 ) 00084 { 00085 string msg = "path to unix socket " ; 00086 msg += _unixSocket + " is too long" ; 00087 throw( BESInternalError( msg, __FILE__, __LINE__ ) ) ; 00088 } 00089 00090 strncpy(server_addr.sun_path, _unixSocket.c_str(), _unixSocket.size()); 00091 server_addr.sun_path[_unixSocket.size()] = '\0'; 00092 server_addr.sun_family = AF_UNIX ; 00093 00094 int descript = socket( AF_UNIX, SOCK_STREAM, 0 ) ; 00095 if( descript != -1 ) 00096 { 00097 strncpy( client_addr.sun_path, _tempSocket.c_str(), _tempSocket.size()); 00098 client_addr.sun_path[_tempSocket.size()] = '\0'; 00099 client_addr.sun_family = AF_UNIX ; 00100 00101 int clen = sizeof( client_addr.sun_family ) ; 00102 clen += strlen( client_addr.sun_path ) + 1; 00103 00104 if( bind( descript, (struct sockaddr*)&client_addr, clen + 1) != -1 ) 00105 { 00106 int slen = sizeof( server_addr.sun_family ) ; 00107 slen += strlen( server_addr.sun_path) + 1; 00108 00109 // we aren't setting the send and receive buffer sizes for a 00110 // unix socket. These will default to a set value 00111 00112 if( ::connect( descript, (struct sockaddr*)&server_addr, slen ) != -1) 00113 { 00114 _socket = descript ; 00115 _connected = true ; 00116 } 00117 else 00118 { 00119 ::close( descript ) ; 00120 string msg = "could not connect via " ; 00121 msg += _unixSocket ; 00122 char *err = strerror( errno ) ; 00123 if( err ) 00124 msg = msg + "\n" + err ; 00125 else 00126 msg = msg + "\nCould not retrieve error message" ; 00127 throw BESInternalError( msg, __FILE__, __LINE__ ) ; 00128 } 00129 } 00130 else 00131 { 00132 string msg = "could not bind to Unix socket " ; 00133 msg += _tempSocket ; 00134 char *err = strerror( errno ) ; 00135 if( err ) 00136 msg = msg + "\n" + err ; 00137 else 00138 msg = msg + "\nCould not retrieve error message" ; 00139 throw BESInternalError( msg, __FILE__, __LINE__ ) ; 00140 } 00141 } 00142 else 00143 { 00144 string msg = "could not create a Unix socket" ; 00145 char *err = strerror( errno ) ; 00146 if( err ) 00147 msg = msg + "\n" + err ; 00148 else 00149 msg = msg + "\nCould not retrieve error message" ; 00150 throw BESInternalError( msg, __FILE__, __LINE__ ) ; 00151 } 00152 } 00153 00154 void 00155 UnixSocket::listen() 00156 { 00157 if( _connected ) 00158 { 00159 string err( "Socket is already connected" ) ; 00160 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00161 } 00162 00163 if( _listening ) 00164 { 00165 string err( "Socket is already listening" ) ; 00166 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00167 } 00168 00169 int on = 1 ; 00170 static struct sockaddr_un server_add ; 00171 _socket = socket( AF_UNIX,SOCK_STREAM, 0 ) ; 00172 if( _socket >= 0 ) 00173 { 00174 server_add.sun_family = AF_UNIX; 00175 // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104] 00176 // on OS/X. jhrg 5/26/06 00177 strncpy( server_add.sun_path, _unixSocket.c_str(), 103) ; 00178 server_add.sun_path[103] = '\0'; 00179 00180 (void)unlink( _unixSocket.c_str() ) ; 00181 if( setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR, 00182 (char*)&on, sizeof( on ) ) ) 00183 { 00184 string error( "could not set SO_REUSEADDR on Unix socket" ) ; 00185 const char *error_info = strerror( errno ) ; 00186 if( error_info ) 00187 error += " " + (string)error_info ; 00188 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00189 } 00190 00191 // we aren't setting the send and receive buffer sizes for a unix 00192 // socket. These will default to a set value 00193 00194 // Added a +1 to the size computation. jhrg 5/26/05 00195 if( bind( _socket, (struct sockaddr*)&server_add, sizeof( server_add.sun_family ) + strlen( server_add.sun_path ) + 1) != -1) 00196 { 00197 if( ::listen( _socket, 5 ) == 0 ) 00198 { 00199 _listening = true ; 00200 } 00201 else 00202 { 00203 string error( "could not listen Unix socket" ) ; 00204 const char* error_info = strerror( errno ) ; 00205 if( error_info ) 00206 error += " " + (string)error_info ; 00207 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00208 } 00209 } 00210 else 00211 { 00212 string error( "could not bind Unix socket" ) ; 00213 const char* error_info = strerror( errno ) ; 00214 if( error_info ) 00215 error += " " + (string)error_info ; 00216 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00217 } 00218 } 00219 else 00220 { 00221 string error( "could not get Unix socket" ) ; 00222 const char *error_info = strerror( errno ) ; 00223 if( error_info ) 00224 error += " " + (string)error_info ; 00225 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00226 } 00227 } 00228 00229 void 00230 UnixSocket::close() 00231 { 00232 Socket::close() ; 00233 if( _tempSocket != "" ) 00234 { 00235 if( !access( _tempSocket.c_str(), F_OK ) ) 00236 { 00237 (void)remove( _tempSocket.c_str() ) ; 00238 } 00239 _connected = false ; 00240 } 00241 if( _listening && _unixSocket != "" ) 00242 { 00243 if( !access( _unixSocket.c_str(), F_OK ) ) 00244 { 00245 (void)remove( _unixSocket.c_str() ) ; 00246 } 00247 _listening = false ; 00248 } 00249 } 00250 00254 bool 00255 UnixSocket::allowConnection() 00256 { 00257 return true ; 00258 } 00259 00266 void 00267 UnixSocket::dump( ostream &strm ) const 00268 { 00269 strm << BESIndent::LMarg << "UnixSocket::dump - (" 00270 << (void *)this << ")" << endl ; 00271 BESIndent::Indent() ; 00272 strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl ; 00273 strm << BESIndent::LMarg << "temp socket: " << _tempSocket << endl ; 00274 Socket::dump( strm ) ; 00275 BESIndent::UnIndent() ; 00276 } 00277