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 ::close( descript ) ; 00133 string msg = "could not bind to Unix socket " ; 00134 msg += _tempSocket ; 00135 char *err = strerror( errno ) ; 00136 if( err ) 00137 msg = msg + "\n" + err ; 00138 else 00139 msg = msg + "\nCould not retrieve error message" ; 00140 throw BESInternalError( msg, __FILE__, __LINE__ ) ; 00141 } 00142 } 00143 else 00144 { 00145 string msg = "could not create a Unix socket" ; 00146 char *err = strerror( errno ) ; 00147 if( err ) 00148 msg = msg + "\n" + err ; 00149 else 00150 msg = msg + "\nCould not retrieve error message" ; 00151 throw BESInternalError( msg, __FILE__, __LINE__ ) ; 00152 } 00153 } 00154 00155 void 00156 UnixSocket::listen() 00157 { 00158 if( _connected ) 00159 { 00160 string err( "Socket is already connected" ) ; 00161 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00162 } 00163 00164 if( _listening ) 00165 { 00166 string err( "Socket is already listening" ) ; 00167 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00168 } 00169 00170 int on = 1 ; 00171 static struct sockaddr_un server_add ; 00172 _socket = socket( AF_UNIX,SOCK_STREAM, 0 ) ; 00173 if( _socket >= 0 ) 00174 { 00175 server_add.sun_family = AF_UNIX; 00176 // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104] 00177 // on OS/X. jhrg 5/26/06 00178 strncpy( server_add.sun_path, _unixSocket.c_str(), 103) ; 00179 server_add.sun_path[103] = '\0'; 00180 00181 (void)unlink( _unixSocket.c_str() ) ; 00182 if( setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR, 00183 (char*)&on, sizeof( on ) ) ) 00184 { 00185 string error( "could not set SO_REUSEADDR on Unix socket" ) ; 00186 const char *error_info = strerror( errno ) ; 00187 if( error_info ) 00188 error += " " + (string)error_info ; 00189 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00190 } 00191 00192 // we aren't setting the send and receive buffer sizes for a unix 00193 // socket. These will default to a set value 00194 00195 // Added a +1 to the size computation. jhrg 5/26/05 00196 if( bind( _socket, (struct sockaddr*)&server_add, sizeof( server_add.sun_family ) + strlen( server_add.sun_path ) + 1) != -1) 00197 { 00198 if( ::listen( _socket, 5 ) == 0 ) 00199 { 00200 _listening = true ; 00201 } 00202 else 00203 { 00204 string error( "could not listen Unix socket" ) ; 00205 const char* error_info = strerror( errno ) ; 00206 if( error_info ) 00207 error += " " + (string)error_info ; 00208 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00209 } 00210 } 00211 else 00212 { 00213 string error( "could not bind Unix socket" ) ; 00214 const char* error_info = strerror( errno ) ; 00215 if( error_info ) 00216 error += " " + (string)error_info ; 00217 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00218 } 00219 } 00220 else 00221 { 00222 string error( "could not get Unix socket" ) ; 00223 const char *error_info = strerror( errno ) ; 00224 if( error_info ) 00225 error += " " + (string)error_info ; 00226 throw BESInternalError( error, __FILE__, __LINE__ ) ; 00227 } 00228 } 00229 00230 void 00231 UnixSocket::close() 00232 { 00233 Socket::close() ; 00234 if( _tempSocket != "" ) 00235 { 00236 if( !access( _tempSocket.c_str(), F_OK ) ) 00237 { 00238 (void)remove( _tempSocket.c_str() ) ; 00239 } 00240 _connected = false ; 00241 } 00242 if( _listening && _unixSocket != "" ) 00243 { 00244 if( !access( _unixSocket.c_str(), F_OK ) ) 00245 { 00246 (void)remove( _unixSocket.c_str() ) ; 00247 } 00248 _listening = false ; 00249 } 00250 } 00251 00255 bool 00256 UnixSocket::allowConnection() 00257 { 00258 return true ; 00259 } 00260 00267 void 00268 UnixSocket::dump( ostream &strm ) const 00269 { 00270 strm << BESIndent::LMarg << "UnixSocket::dump - (" 00271 << (void *)this << ")" << endl ; 00272 BESIndent::Indent() ; 00273 strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl ; 00274 strm << BESIndent::LMarg << "temp socket: " << _tempSocket << endl ; 00275 Socket::dump( strm ) ; 00276 BESIndent::UnIndent() ; 00277 } 00278