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
00034 #include <unistd.h>
00035 #include <stdio.h>
00036 #include <sys/un.h>
00037 #include <sys/socket.h>
00038 #include <sys/types.h>
00039
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
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
00075
00076
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
00110
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
00176
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
00192
00193
00194
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