328 lines
9.3 KiB
C++
Executable File
328 lines
9.3 KiB
C++
Executable File
#ifndef __SOCKET_TCP_SSL_H__
|
|
#define __SOCKET_TCP_SSL_H__
|
|
|
|
#include "pandabase.h"
|
|
#include "socket_ip.h"
|
|
#include "numeric_types.h"
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
#include <openssl/rsa.h> /* SSLeay stuff */
|
|
#include <openssl/crypto.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/err.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Class : Socket_TCP_SSL
|
|
//
|
|
// Description :
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
extern EXPCL_PANDA_NATIVENET SSL_CTX *global_ssl_ctx;
|
|
|
|
|
|
struct SSlStartup
|
|
{
|
|
SSlStartup()
|
|
{
|
|
const SSL_METHOD *meth;
|
|
SSLeay_add_ssl_algorithms();
|
|
//meth = SSLv23_server_method();
|
|
meth = SSLv23_method();
|
|
SSL_load_error_strings();
|
|
// I hate this cast, but older versions of OpenSSL need it.
|
|
global_ssl_ctx = SSL_CTX_new ((SSL_METHOD *) meth);
|
|
}
|
|
|
|
~SSlStartup()
|
|
{
|
|
SSL_CTX_free (global_ssl_ctx);
|
|
global_ssl_ctx = NULL;
|
|
}
|
|
|
|
|
|
bool isactive() { return global_ssl_ctx != NULL; };
|
|
};
|
|
|
|
|
|
class EXPCL_PANDA_NATIVENET Socket_TCP_SSL : public Socket_IP
|
|
{
|
|
public:
|
|
|
|
inline Socket_TCP_SSL(SOCKET);
|
|
inline Socket_TCP_SSL() : _ssl(NULL) {}
|
|
|
|
virtual inline ~Socket_TCP_SSL()
|
|
{
|
|
CleanSslUp();
|
|
}
|
|
|
|
inline int SetNoDelay();
|
|
inline int SetLinger(int interval_seconds = 0);
|
|
inline int DontLinger();
|
|
|
|
inline int SetSendBufferSize(int insize);
|
|
inline bool ActiveOpen(const Socket_Address & theaddress);
|
|
inline int SendData(const char * data, int size);
|
|
inline int RecvData(char * data, int size);
|
|
inline bool ErrorIs_WouldBlocking(int err);
|
|
|
|
inline SSL * get_ssl() { return _ssl; };
|
|
|
|
inline void DetailErrorFormat(void);
|
|
private:
|
|
SSL* _ssl;
|
|
|
|
void CleanSslUp()
|
|
{
|
|
if(_ssl != NULL)
|
|
{
|
|
SSL_shutdown(_ssl);
|
|
SSL_free(_ssl);
|
|
_ssl = NULL;
|
|
}
|
|
}
|
|
|
|
public:
|
|
static TypeHandle get_class_type() {
|
|
return _type_handle;
|
|
}
|
|
static void init_type() {
|
|
Socket_IP::init_type();
|
|
register_type(_type_handle, "Socket_TCP_SSL",
|
|
Socket_IP::get_class_type());
|
|
}
|
|
virtual TypeHandle get_type() const {
|
|
return get_class_type();
|
|
}
|
|
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
|
|
|
private:
|
|
static TypeHandle _type_handle;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Function name : Socket_TCP_SSL::Socket_TCP_SSL
|
|
// Description :
|
|
//////////////////////////////////////////////////////////////
|
|
// right know this will only work for a
|
|
// accepted ie a server socket ??
|
|
inline Socket_TCP_SSL::Socket_TCP_SSL(SOCKET sck) : ::Socket_IP(sck)
|
|
{
|
|
SetNonBlocking(); // maybe should be blocking?
|
|
|
|
_ssl = SSL_new (global_ssl_ctx);
|
|
if(_ssl == NULL)
|
|
return;
|
|
SSL_set_fd (_ssl,(int)GetSocket() );
|
|
|
|
SSL_accept(_ssl);
|
|
ERR_clear_error();
|
|
|
|
// printf(" Ssl Accept = %d \n",err);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : SetNoDelay
|
|
// Description : Disable Nagle algorithm. Don't delay send to coalesce packets
|
|
////////////////////////////////////////////////////////////////////
|
|
inline int Socket_TCP_SSL::SetNoDelay()
|
|
{
|
|
int nodel = 1;
|
|
int ret1;
|
|
ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel));
|
|
|
|
if (ret1 != 0)
|
|
return BASIC_ERROR;
|
|
|
|
return ALL_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : SetLinger
|
|
// Description : will control the behavior of SO_LINGER for a TCP socket
|
|
////////////////////////////////////////////////////////////////////
|
|
int Socket_TCP_SSL::SetLinger(int interval_seconds)
|
|
{
|
|
linger ll;
|
|
ll.l_linger = interval_seconds;
|
|
ll.l_onoff = 1;
|
|
int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
|
|
if (ret1 != 0)
|
|
return BASIC_ERROR;
|
|
return ALL_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : Socket_TCP_SSL::DontLinger
|
|
// Description : Turn off the linger flag. The socket will quickly release
|
|
// buffered items and free up OS resources. You may lose
|
|
// a stream if you use this flag and do not negotiate the close
|
|
// at the application layer.
|
|
////////////////////////////////////////////////////////////////////
|
|
int Socket_TCP_SSL::DontLinger()
|
|
{
|
|
linger ll;
|
|
ll.l_linger = 0;
|
|
ll.l_onoff = 0;
|
|
int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
|
|
if (ret1 != 0)
|
|
return BASIC_ERROR;
|
|
return ALL_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : SetSendBufferSize
|
|
// Description : Just like it sounds. Sets a buffered socket recv buffer size.
|
|
// This function does not refuse ranges outside hard-coded OS
|
|
// limits
|
|
////////////////////////////////////////////////////////////////////
|
|
int Socket_TCP_SSL::SetSendBufferSize(int insize)
|
|
{
|
|
if (setsockopt(_socket, (int) SOL_SOCKET, (int) SO_SNDBUF, (char *) &insize, sizeof(int)))
|
|
return BASIC_ERROR;
|
|
return ALL_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : ActiveOpen
|
|
// Description : This function will try and set the socket up for active open to a specified
|
|
// address and port provided by the input parameter
|
|
////////////////////////////////////////////////////////////////////
|
|
bool Socket_TCP_SSL::ActiveOpen(const Socket_Address & theaddress)
|
|
{
|
|
_socket = DO_NEWTCP();
|
|
if (_socket == BAD_SOCKET)
|
|
return false;
|
|
|
|
if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0)
|
|
return ErrorClose();
|
|
|
|
|
|
_ssl = SSL_new (global_ssl_ctx);
|
|
if(_ssl == NULL)
|
|
return false;
|
|
SSL_set_fd (_ssl,(int)GetSocket() );
|
|
if(SSL_connect(_ssl) == -1)
|
|
return false;
|
|
return true;
|
|
|
|
//return SetSslUp();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : Socket_TCP_SSL::SendData
|
|
// Description : Ok Lets Send the Data
|
|
//
|
|
// Return type : int
|
|
// - if error
|
|
// 0 if socket closed for write or lengh is 0
|
|
// + bytes writen ( May be smaller than requested)
|
|
////////////////////////////////////////////////////////////////////
|
|
inline int Socket_TCP_SSL::SendData(const char * data, int size)
|
|
{
|
|
if(_ssl == NULL)
|
|
return -1;
|
|
|
|
// ERR_clear_error();
|
|
|
|
return SSL_write(_ssl, data, size);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : Socket_TCP_SSL::RecvData
|
|
// Description : Read the data from the connection
|
|
//
|
|
// Return type : int
|
|
// - if error
|
|
// 0 if socket closed for read or length is 0
|
|
// + bytes read ( May be smaller than requested)
|
|
////////////////////////////////////////////////////////////////////
|
|
inline int Socket_TCP_SSL::RecvData(char * data, int len)
|
|
{
|
|
if(_ssl == NULL)
|
|
return -1;
|
|
|
|
ERR_clear_error();
|
|
|
|
return SSL_read(_ssl, data, len);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function name : ErrorIs_WouldBlocking
|
|
// Description : Is last error a blocking error ??
|
|
//
|
|
// Return type : Bool
|
|
// True is last error was a blocking error
|
|
////////////////////////////////////////////////////////////////////
|
|
inline bool Socket_TCP_SSL::ErrorIs_WouldBlocking(int err)
|
|
{
|
|
if(_ssl == NULL || err >= 0)
|
|
{
|
|
nativenet_cat.warning()
|
|
<< "Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error number "
|
|
<< err << " or _ssl is NULL\n";
|
|
return false;
|
|
}
|
|
|
|
int ssl_error_code = SSL_get_error(_ssl,err);
|
|
bool answer = false;
|
|
|
|
switch(ssl_error_code)
|
|
{
|
|
case SSL_ERROR_WANT_READ:
|
|
case SSL_ERROR_WANT_WRITE:
|
|
case SSL_ERROR_WANT_CONNECT:
|
|
// case SSL_ERROR_WANT_ACCEPT:
|
|
answer = true;
|
|
break;
|
|
// hmm not sure we need this .. hmmmm
|
|
case SSL_ERROR_SYSCALL:
|
|
if(GETERROR() == LOCAL_BLOCKING_ERROR)
|
|
answer = true;
|
|
else
|
|
{
|
|
DetailErrorFormat();
|
|
// LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error1 SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
|
|
}
|
|
break;
|
|
default:
|
|
DetailErrorFormat();
|
|
// LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error2 SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
|
|
answer = false;
|
|
break;
|
|
}
|
|
|
|
// ERR_clear_error();
|
|
return answer;
|
|
}
|
|
|
|
inline void Socket_TCP_SSL::DetailErrorFormat(void)
|
|
{
|
|
return; // turn on fir debuging
|
|
|
|
PN_uint32 l;
|
|
char buf[256];
|
|
char buf2[4096];
|
|
const char *file,*data;
|
|
int line,flags;
|
|
PN_uint32 es;
|
|
|
|
es=CRYPTO_thread_id();
|
|
while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
|
|
{
|
|
ERR_error_string_n(l, buf, sizeof( buf) );
|
|
BIO_snprintf(buf2, sizeof(buf2), "***%lu:%s:%s:%d:%s\n", (unsigned long) es, buf,file, line, (flags & ERR_TXT_STRING) ? data : "NoText");
|
|
nativenet_cat.warning()
|
|
<< "Socket_TCP_SSL::DetailErrorFormat->[" << buf2 << "]\n";
|
|
}
|
|
}
|
|
|
|
#endif // HAVE_OPENSSL
|
|
|
|
#endif //__SOCKET_TCP_SSL_H__
|
|
|