OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
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                 ::close( descript ) ;
00133             string msg = "could not bind to Unix socket " ;
00134             msg += _tempSocket ;
00135             char *err = strerror( errno ) ;
00136             if( err )
00137                 msg = msg + "\n" + err ;
00138             else
00139                 msg = msg + "\nCould not retrieve error message" ;
00140             throw BESInternalError( msg, __FILE__, __LINE__ ) ;
00141         }
00142     }
00143     else
00144     {
00145         string msg = "could not create a Unix socket" ;
00146         char *err = strerror( errno ) ;
00147         if( err )
00148             msg = msg + "\n" + err ;
00149         else
00150             msg = msg + "\nCould not retrieve error message" ;
00151         throw BESInternalError( msg, __FILE__, __LINE__ ) ;
00152     }
00153 }
00154 
00155 void
00156 UnixSocket::listen()
00157 {
00158     if( _connected )
00159     {
00160         string err( "Socket is already connected" ) ;
00161         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00162     }
00163 
00164     if( _listening )
00165     {
00166         string err( "Socket is already listening" ) ;
00167         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00168     }
00169 
00170     int on = 1 ;
00171     static struct sockaddr_un server_add ;
00172     _socket = socket( AF_UNIX,SOCK_STREAM, 0 ) ;
00173     if( _socket >= 0 )
00174     {
00175         server_add.sun_family = AF_UNIX;
00176         // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104]
00177         // on OS/X. jhrg 5/26/06
00178         strncpy( server_add.sun_path, _unixSocket.c_str(), 103) ;
00179         server_add.sun_path[103] = '\0';
00180 
00181         (void)unlink( _unixSocket.c_str() ) ;
00182         if( setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR,
00183                          (char*)&on, sizeof( on ) ) )
00184         {
00185             string error( "could not set SO_REUSEADDR on Unix socket" ) ;
00186             const char *error_info = strerror( errno ) ;
00187             if( error_info )
00188                 error += " " + (string)error_info ;
00189             throw BESInternalError( error, __FILE__, __LINE__ ) ;
00190         }
00191 
00192         // we aren't setting the send and receive buffer sizes for a unix
00193         // socket. These will default to a set value
00194 
00195         // Added a +1 to the size computation. jhrg 5/26/05
00196         if( bind( _socket, (struct sockaddr*)&server_add, sizeof( server_add.sun_family ) + strlen( server_add.sun_path ) + 1) != -1)
00197         {
00198             if( ::listen( _socket, 5 ) == 0 )
00199             {
00200                 _listening = true ;
00201             }
00202             else
00203             {
00204                 string error( "could not listen Unix socket" ) ;
00205                 const char* error_info = strerror( errno ) ;
00206                 if( error_info )
00207                     error += " " + (string)error_info ;
00208                 throw BESInternalError( error, __FILE__, __LINE__ ) ;
00209             }
00210         }
00211         else
00212         {
00213             string error( "could not bind Unix socket" ) ;
00214             const char* error_info = strerror( errno ) ;
00215             if( error_info )
00216                 error += " " + (string)error_info ;
00217             throw BESInternalError( error, __FILE__, __LINE__ ) ;
00218         }
00219     }
00220     else
00221     {
00222         string error( "could not get Unix socket" ) ;
00223         const char *error_info = strerror( errno ) ;
00224         if( error_info )
00225             error += " " + (string)error_info ;
00226         throw BESInternalError( error, __FILE__, __LINE__ ) ;
00227     }
00228 }
00229 
00230 void
00231 UnixSocket::close()
00232 {
00233     Socket::close() ;
00234     if( _tempSocket != "" )
00235     {
00236         if( !access( _tempSocket.c_str(), F_OK ) )
00237         {
00238             (void)remove( _tempSocket.c_str() ) ;
00239         }
00240         _connected = false ;
00241     }
00242     if( _listening && _unixSocket != "" )
00243     {
00244         if( !access( _unixSocket.c_str(), F_OK ) )
00245         {
00246             (void)remove( _unixSocket.c_str() ) ;
00247         }
00248         _listening = false ;
00249     }
00250 }
00251 
00255 bool
00256 UnixSocket::allowConnection()
00257 {
00258     return true ;
00259 }
00260 
00267 void
00268 UnixSocket::dump( ostream &strm ) const
00269 {
00270     strm << BESIndent::LMarg << "UnixSocket::dump - ("
00271                              << (void *)this << ")" << endl ;
00272     BESIndent::Indent() ;
00273     strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl ;
00274     strm << BESIndent::LMarg << "temp socket: " << _tempSocket << endl ;
00275     Socket::dump( strm ) ;
00276     BESIndent::UnIndent() ;
00277 }
00278