UnixSocket.cc

Go to the documentation of this file.
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,2005 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>
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     // maximum path for struct sockaddr_un.sun_path is 108
00066     // get sure we will not exceed to max for creating sockets
00067     // 107 characters in pathname + '\0'
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         // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104]
00160         // on OS/X. jhrg 5/26/06
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             // Added a +1 to the size computation. jhrg 5/26/05
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 

Generated on Wed Aug 29 03:24:05 2007 for OPeNDAP Back End Server (BES) by  doxygen 1.5.2