Panda3D
 All Classes Functions Variables Enumerations
socket_tcp_ssl.h
00001 #ifndef __SOCKET_TCP_SSL_H__
00002 #define __SOCKET_TCP_SSL_H__ 
00003 
00004 #include "pandabase.h"
00005 #include "socket_ip.h"
00006 #include "numeric_types.h"
00007 
00008 #ifdef HAVE_OPENSSL
00009 
00010 #include <openssl/rsa.h>       /* SSLeay stuff */
00011 #include <openssl/crypto.h>
00012 #include <openssl/x509.h>
00013 #include <openssl/pem.h>
00014 #include <openssl/ssl.h>
00015 #include <openssl/err.h>
00016 
00017 /////////////////////////////////////////////////////////////////////
00018 // Class : Socket_TCP_SSL
00019 //
00020 // Description : 
00021 //
00022 /////////////////////////////////////////////////////////////////////
00023 
00024 extern EXPCL_PANDA_NATIVENET SSL_CTX *global_ssl_ctx;
00025 
00026 
00027 struct SSlStartup
00028 {
00029    SSlStartup()
00030    {
00031         const SSL_METHOD *meth;
00032         SSLeay_add_ssl_algorithms();
00033         //meth = SSLv23_server_method();
00034         meth = SSLv23_method();
00035         SSL_load_error_strings();
00036         // I hate this cast, but older versions of OpenSSL need it.
00037         global_ssl_ctx = SSL_CTX_new ((SSL_METHOD *) meth);                        
00038    }
00039 
00040    ~SSlStartup()
00041    {
00042         SSL_CTX_free (global_ssl_ctx);    
00043         global_ssl_ctx = NULL;
00044    }
00045    
00046 
00047    bool isactive() { return global_ssl_ctx != NULL; };
00048 };
00049 
00050 
00051 class EXPCL_PANDA_NATIVENET Socket_TCP_SSL : public Socket_IP
00052 {
00053 public:
00054     
00055     inline Socket_TCP_SSL(SOCKET);
00056     inline Socket_TCP_SSL() : _ssl(NULL) {}
00057 
00058     virtual inline ~Socket_TCP_SSL()
00059     {
00060         CleanSslUp();
00061     }
00062     
00063     inline int SetNoDelay();
00064     inline int SetLinger(int interval_seconds = 0);
00065     inline int DontLinger();
00066     
00067     inline int SetSendBufferSize(int insize);
00068     inline bool ActiveOpen(const Socket_Address & theaddress);
00069     inline int SendData(const char * data, int size);
00070     inline int RecvData(char * data, int size);
00071     inline bool ErrorIs_WouldBlocking(int err);
00072 
00073     inline SSL * get_ssl() { return _ssl; };
00074 
00075     inline void DetailErrorFormat(void);
00076 private:
00077       SSL*     _ssl;
00078 
00079         void CleanSslUp()
00080         {
00081             if(_ssl != NULL)
00082             {
00083                 SSL_shutdown(_ssl);
00084                 SSL_free(_ssl);
00085                 _ssl = NULL;
00086             }
00087         }
00088   
00089 public:
00090   static TypeHandle get_class_type() {
00091     return _type_handle;
00092   }
00093   static void init_type() {
00094     Socket_IP::init_type();
00095     register_type(_type_handle, "Socket_TCP_SSL",
00096                   Socket_IP::get_class_type());
00097   }
00098   virtual TypeHandle get_type() const {
00099     return get_class_type();
00100   }
00101   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
00102 
00103 private:
00104   static TypeHandle _type_handle;
00105 };
00106 
00107 //////////////////////////////////////////////////////////////
00108 // Function name : Socket_TCP_SSL::Socket_TCP_SSL
00109 // Description   :
00110 //////////////////////////////////////////////////////////////
00111 // right know this will only work for a 
00112 // accepted ie a server socket ??
00113 inline Socket_TCP_SSL::Socket_TCP_SSL(SOCKET sck) : ::Socket_IP(sck)
00114 { 
00115     SetNonBlocking(); // maybe should be blocking?
00116   
00117     _ssl = SSL_new (global_ssl_ctx);                         
00118     if(_ssl == NULL) 
00119         return;
00120     SSL_set_fd (_ssl,(int)GetSocket() );
00121 
00122     SSL_accept(_ssl);
00123     ERR_clear_error();
00124 
00125 //    printf(" Ssl Accept = %d \n",err);
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 // Function name : SetNoDelay
00130 // Description   : Disable Nagle algorithm. Don't delay send to coalesce packets
00131 ////////////////////////////////////////////////////////////////////
00132 inline int Socket_TCP_SSL::SetNoDelay()
00133 {
00134     int nodel = 1;
00135     int ret1;
00136     ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel));
00137     
00138     if (ret1 != 0)
00139         return BASIC_ERROR;
00140     
00141     return ALL_OK;
00142 }
00143 
00144 ////////////////////////////////////////////////////////////////////
00145 // Function name : SetLinger
00146 // Description   : will control the behavior of SO_LINGER for a TCP socket
00147 ////////////////////////////////////////////////////////////////////
00148 int Socket_TCP_SSL::SetLinger(int interval_seconds)
00149 {
00150     linger ll;
00151     ll.l_linger = interval_seconds;
00152     ll.l_onoff = 1;
00153     int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
00154     if (ret1 != 0)
00155         return BASIC_ERROR;
00156     return ALL_OK;
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 // Function name : Socket_TCP_SSL::DontLinger
00161 // Description   : Turn off the linger flag. The socket will quickly release
00162 //        buffered items and free up OS resources. You may lose
00163 //        a stream if you use this flag and do not negotiate the close
00164 //        at the application layer.
00165 ////////////////////////////////////////////////////////////////////
00166 int Socket_TCP_SSL::DontLinger()
00167 {
00168     linger ll;
00169     ll.l_linger = 0;
00170     ll.l_onoff = 0;
00171     int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
00172     if (ret1 != 0)
00173         return BASIC_ERROR;
00174     return ALL_OK;
00175 }
00176 
00177 ////////////////////////////////////////////////////////////////////
00178 // Function name : SetSendBufferSize
00179 // Description   : Just like it sounds. Sets a buffered socket recv buffer size.
00180 //      This function does not refuse ranges outside hard-coded OS
00181 //      limits
00182 ////////////////////////////////////////////////////////////////////
00183 int Socket_TCP_SSL::SetSendBufferSize(int insize)
00184 {
00185     if (setsockopt(_socket, (int) SOL_SOCKET, (int) SO_SNDBUF, (char *) &insize, sizeof(int)))
00186         return BASIC_ERROR;
00187     return ALL_OK;
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 // Function name : ActiveOpen
00192 // Description   : This function will try and set the socket up for active open to a specified
00193 //       address and port provided by the input parameter
00194 ////////////////////////////////////////////////////////////////////
00195 bool Socket_TCP_SSL::ActiveOpen(const Socket_Address & theaddress)
00196 {
00197     _socket = DO_NEWTCP();
00198     if (_socket == BAD_SOCKET)
00199         return false;
00200     
00201     if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0)
00202         return ErrorClose();
00203     
00204 
00205     _ssl = SSL_new (global_ssl_ctx);                         
00206     if(_ssl == NULL) 
00207         return false;
00208     SSL_set_fd (_ssl,(int)GetSocket() );
00209     if(SSL_connect(_ssl) == -1)
00210         return false;
00211     return true;
00212 
00213     //return SetSslUp();
00214 }
00215 
00216 ////////////////////////////////////////////////////////////////////
00217 // Function name : Socket_TCP_SSL::SendData
00218 // Description   : Ok Lets Send the Data
00219 //
00220 // Return type  : int
00221 //      - if error
00222 //      0 if socket closed for write or lengh is 0
00223 //      + bytes writen ( May be smaller than requested)
00224 ////////////////////////////////////////////////////////////////////
00225 inline int Socket_TCP_SSL::SendData(const char * data, int size)
00226 {
00227     if(_ssl == NULL)
00228         return -1;
00229 
00230 //    ERR_clear_error();
00231 
00232     return SSL_write(_ssl, data, size);
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 // Function name : Socket_TCP_SSL::RecvData
00237 // Description   : Read the data from the connection
00238 //
00239 // Return type  : int
00240 //      - if error
00241 //      0 if socket closed for read or length is 0
00242 //      + bytes read ( May be smaller than requested)
00243 ////////////////////////////////////////////////////////////////////
00244 inline int Socket_TCP_SSL::RecvData(char * data, int len)
00245 {
00246     if(_ssl == NULL)
00247         return -1;
00248 
00249     ERR_clear_error();
00250 
00251     return SSL_read(_ssl, data, len);
00252 }
00253 
00254 ////////////////////////////////////////////////////////////////////
00255 // Function name : ErrorIs_WouldBlocking
00256 // Description   : Is last error a blocking error ??
00257 //
00258 // Return type  : Bool
00259 //      True is last error was a blocking error
00260 ////////////////////////////////////////////////////////////////////
00261 inline bool Socket_TCP_SSL::ErrorIs_WouldBlocking(int err)
00262 {
00263     if(_ssl == NULL || err >= 0)
00264     {
00265       nativenet_cat.warning()
00266         << "Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error number "
00267         << err << " or _ssl is NULL\n";
00268         return false;
00269     }
00270 
00271     int ssl_error_code = SSL_get_error(_ssl,err);
00272     bool answer = false;
00273     
00274     switch(ssl_error_code)
00275     {
00276         case SSL_ERROR_WANT_READ:
00277         case SSL_ERROR_WANT_WRITE:
00278         case SSL_ERROR_WANT_CONNECT:
00279 //        case SSL_ERROR_WANT_ACCEPT:
00280             answer = true;
00281             break;
00282 // hmm not sure we need this .. hmmmm
00283         case SSL_ERROR_SYSCALL:
00284             if(GETERROR() == LOCAL_BLOCKING_ERROR)
00285                 answer = true;
00286             else
00287             {
00288                 DetailErrorFormat();
00289 //                LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error1 SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
00290             }
00291             break;
00292         default:
00293             DetailErrorFormat();
00294 //          LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error2 SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
00295             answer = false;
00296             break;
00297     }
00298 
00299 //    ERR_clear_error();
00300     return answer;
00301 }
00302 
00303 inline void Socket_TCP_SSL::DetailErrorFormat(void)
00304 {
00305     return; // turn on fir debuging
00306 
00307     PN_uint32 l;
00308     char buf[256];
00309     char buf2[4096];
00310     const char *file,*data;
00311     int line,flags;
00312     PN_uint32 es;
00313 
00314     es=CRYPTO_thread_id();
00315     while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
00316     {
00317         ERR_error_string_n(l, buf, sizeof( buf) );
00318         BIO_snprintf(buf2, sizeof(buf2), "***%lu:%s:%s:%d:%s\n", (unsigned long) es, buf,file, line, (flags & ERR_TXT_STRING) ? data : "NoText");
00319         nativenet_cat.warning()
00320           << "Socket_TCP_SSL::DetailErrorFormat->[" << buf2 << "]\n";
00321     }
00322 }
00323 
00324 #endif  // HAVE_OPENSSL
00325 
00326 #endif //__SOCKET_TCP_SSL_H__
00327 
 All Classes Functions Variables Enumerations