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