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>   // for unlink
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     // what is the max size of the path to the unix socket
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     // maximum path for struct sockaddr_un.sun_path is 108
00074     // get sure we will not exceed to max for creating sockets
00075     // 107 characters in pathname + '\0'
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         // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104]
00171         // on OS/X. jhrg 5/26/06
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             // Added a +1 to the size computation. jhrg 5/26/05
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 

Generated on Tue Mar 4 23:13:37 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1