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-2009 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 <cstdio>
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     // what is the max size of the path to the unix socket
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     // maximum path for struct sockaddr_un.sun_path is 108
00075     // get sure we will not exceed to max for creating sockets
00076     // 107 characters in pathname + '\0'
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             // we aren't setting the send and receive buffer sizes for a
00110             // unix socket. These will default to a set value
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         // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104]
00176         // on OS/X. jhrg 5/26/06
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         // we aren't setting the send and receive buffer sizes for a unix
00192         // socket. These will default to a set value
00193 
00194         // Added a +1 to the size computation. jhrg 5/26/05
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 

Generated on Wed May 12 09:53:08 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7