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