Panda3D
 All Classes Functions Variables Enumerations
socket_tcp_ssl.h
1 #ifndef __SOCKET_TCP_SSL_H__
2 #define __SOCKET_TCP_SSL_H__
3 
4 #include "pandabase.h"
5 #include "config_nativenet.h"
6 #include "socket_ip.h"
7 #include "numeric_types.h"
8 
9 #ifdef HAVE_OPENSSL
10 
11 #include <openssl/rsa.h> /* SSLeay stuff */
12 #include <openssl/crypto.h>
13 #include <openssl/x509.h>
14 #include <openssl/pem.h>
15 #include <openssl/ssl.h>
16 #include <openssl/err.h>
17 
18 /////////////////////////////////////////////////////////////////////
19 // Class : Socket_TCP_SSL
20 //
21 // Description :
22 //
23 /////////////////////////////////////////////////////////////////////
24 
25 extern EXPCL_PANDA_NATIVENET SSL_CTX *global_ssl_ctx;
26 
27 
28 struct SSlStartup
29 {
30  SSlStartup()
31  {
32  const SSL_METHOD *meth;
33  SSLeay_add_ssl_algorithms();
34  //meth = SSLv23_server_method();
35  meth = SSLv23_method();
36  SSL_load_error_strings();
37  // I hate this cast, but older versions of OpenSSL need it.
38  global_ssl_ctx = SSL_CTX_new ((SSL_METHOD *) meth);
39  }
40 
41  ~SSlStartup()
42  {
43  SSL_CTX_free (global_ssl_ctx);
44  global_ssl_ctx = NULL;
45  }
46 
47 
48  bool isactive() { return global_ssl_ctx != NULL; };
49 };
50 
51 
52 class EXPCL_PANDA_NATIVENET Socket_TCP_SSL : public Socket_IP
53 {
54 public:
55 
56  inline Socket_TCP_SSL(SOCKET);
57  inline Socket_TCP_SSL() : _ssl(NULL) {}
58 
59  virtual inline ~Socket_TCP_SSL()
60  {
61  CleanSslUp();
62  }
63 
64  inline int SetNoDelay();
65  inline int SetLinger(int interval_seconds = 0);
66  inline int DontLinger();
67 
68  inline int SetSendBufferSize(int insize);
69  inline bool ActiveOpen(const Socket_Address & theaddress);
70  inline int SendData(const char * data, int size);
71  inline int RecvData(char * data, int size);
72  inline bool ErrorIs_WouldBlocking(int err);
73 
74  inline SSL * get_ssl() { return _ssl; };
75 
76  inline void DetailErrorFormat(void);
77 private:
78  SSL* _ssl;
79 
80  void CleanSslUp()
81  {
82  if(_ssl != NULL)
83  {
84  SSL_shutdown(_ssl);
85  SSL_free(_ssl);
86  _ssl = NULL;
87  }
88  }
89 
90 public:
91  static TypeHandle get_class_type() {
92  return _type_handle;
93  }
94  static void init_type() {
95  Socket_IP::init_type();
96  register_type(_type_handle, "Socket_TCP_SSL",
97  Socket_IP::get_class_type());
98  }
99  virtual TypeHandle get_type() const {
100  return get_class_type();
101  }
102  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
103 
104 private:
105  static TypeHandle _type_handle;
106 };
107 
108 //////////////////////////////////////////////////////////////
109 // Function name : Socket_TCP_SSL::Socket_TCP_SSL
110 // Description :
111 //////////////////////////////////////////////////////////////
112 // right know this will only work for a
113 // accepted ie a server socket ??
114 inline Socket_TCP_SSL::Socket_TCP_SSL(SOCKET sck) : ::Socket_IP(sck)
115 {
116  SetNonBlocking(); // maybe should be blocking?
117 
118  _ssl = SSL_new (global_ssl_ctx);
119  if(_ssl == NULL)
120  return;
121  SSL_set_fd (_ssl,(int)GetSocket() );
122 
123  SSL_accept(_ssl);
124  ERR_clear_error();
125 
126 // printf(" Ssl Accept = %d \n",err);
127 }
128 
129 ////////////////////////////////////////////////////////////////////
130 // Function name : SetNoDelay
131 // Description : Disable Nagle algorithm. Don't delay send to coalesce packets
132 ////////////////////////////////////////////////////////////////////
133 inline int Socket_TCP_SSL::SetNoDelay()
134 {
135  int nodel = 1;
136  int ret1;
137  ret1 = setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *) & nodel, sizeof(nodel));
138 
139  if (ret1 != 0)
140  return BASIC_ERROR;
141 
142  return ALL_OK;
143 }
144 
145 ////////////////////////////////////////////////////////////////////
146 // Function name : SetLinger
147 // Description : will control the behavior of SO_LINGER for a TCP socket
148 ////////////////////////////////////////////////////////////////////
149 int Socket_TCP_SSL::SetLinger(int interval_seconds)
150 {
151  linger ll;
152  ll.l_linger = interval_seconds;
153  ll.l_onoff = 1;
154  int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
155  if (ret1 != 0)
156  return BASIC_ERROR;
157  return ALL_OK;
158 }
159 
160 ////////////////////////////////////////////////////////////////////
161 // Function name : Socket_TCP_SSL::DontLinger
162 // Description : Turn off the linger flag. The socket will quickly release
163 // buffered items and free up OS resources. You may lose
164 // a stream if you use this flag and do not negotiate the close
165 // at the application layer.
166 ////////////////////////////////////////////////////////////////////
167 int Socket_TCP_SSL::DontLinger()
168 {
169  linger ll;
170  ll.l_linger = 0;
171  ll.l_onoff = 0;
172  int ret1 = setsockopt(_socket, SOL_SOCKET, SO_LINGER, (const char *) & ll, sizeof(linger));
173  if (ret1 != 0)
174  return BASIC_ERROR;
175  return ALL_OK;
176 }
177 
178 ////////////////////////////////////////////////////////////////////
179 // Function name : SetSendBufferSize
180 // Description : Just like it sounds. Sets a buffered socket recv buffer size.
181 // This function does not refuse ranges outside hard-coded OS
182 // limits
183 ////////////////////////////////////////////////////////////////////
184 int Socket_TCP_SSL::SetSendBufferSize(int insize)
185 {
186  if (setsockopt(_socket, (int) SOL_SOCKET, (int) SO_SNDBUF, (char *) &insize, sizeof(int)))
187  return BASIC_ERROR;
188  return ALL_OK;
189 }
190 
191 ////////////////////////////////////////////////////////////////////
192 // Function name : ActiveOpen
193 // Description : This function will try and set the socket up for active open to a specified
194 // address and port provided by the input parameter
195 ////////////////////////////////////////////////////////////////////
196 bool Socket_TCP_SSL::ActiveOpen(const Socket_Address & theaddress)
197 {
198  _socket = DO_NEWTCP();
199  if (_socket == BAD_SOCKET)
200  return false;
201 
202  if (DO_CONNECT(_socket, &theaddress.GetAddressInfo()) != 0)
203  return ErrorClose();
204 
205 
206  _ssl = SSL_new (global_ssl_ctx);
207  if(_ssl == NULL)
208  return false;
209  SSL_set_fd (_ssl,(int)GetSocket() );
210  if(SSL_connect(_ssl) == -1)
211  return false;
212  return true;
213 
214  //return SetSslUp();
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function name : Socket_TCP_SSL::SendData
219 // Description : Ok Lets Send the Data
220 //
221 // Return type : int
222 // - if error
223 // 0 if socket closed for write or lengh is 0
224 // + bytes writen ( May be smaller than requested)
225 ////////////////////////////////////////////////////////////////////
226 inline int Socket_TCP_SSL::SendData(const char * data, int size)
227 {
228  if(_ssl == NULL)
229  return -1;
230 
231 // ERR_clear_error();
232 
233  return SSL_write(_ssl, data, size);
234 }
235 
236 ////////////////////////////////////////////////////////////////////
237 // Function name : Socket_TCP_SSL::RecvData
238 // Description : Read the data from the connection
239 //
240 // Return type : int
241 // - if error
242 // 0 if socket closed for read or length is 0
243 // + bytes read ( May be smaller than requested)
244 ////////////////////////////////////////////////////////////////////
245 inline int Socket_TCP_SSL::RecvData(char * data, int len)
246 {
247  if(_ssl == NULL)
248  return -1;
249 
250  ERR_clear_error();
251 
252  return SSL_read(_ssl, data, len);
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function name : ErrorIs_WouldBlocking
257 // Description : Is last error a blocking error ??
258 //
259 // Return type : Bool
260 // True is last error was a blocking error
261 ////////////////////////////////////////////////////////////////////
262 inline bool Socket_TCP_SSL::ErrorIs_WouldBlocking(int err)
263 {
264  if(_ssl == NULL || err >= 0)
265  {
266  nativenet_cat.warning()
267  << "Socket_TCP_SSL::ErrorIs_WouldBlocking->Called With Error number "
268  << err << " or _ssl is NULL\n";
269  return false;
270  }
271 
272  int ssl_error_code = SSL_get_error(_ssl,err);
273  bool answer = false;
274 
275  switch(ssl_error_code)
276  {
277  case SSL_ERROR_WANT_READ:
278  case SSL_ERROR_WANT_WRITE:
279  case SSL_ERROR_WANT_CONNECT:
280 // case SSL_ERROR_WANT_ACCEPT:
281  answer = true;
282  break;
283 // hmm not sure we need this .. hmmmm
284  case SSL_ERROR_SYSCALL:
285  if(GETERROR() == LOCAL_BLOCKING_ERROR)
286  answer = true;
287  else
288  {
289  DetailErrorFormat();
290 // LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error1 SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
291  }
292  break;
293  default:
294  DetailErrorFormat();
295 // LOGWARNING("Socket_TCP_SSL::ErrorIs_WouldBlocking-> Not A blocking Error2 SSl_CODe=[%d] OS=[%d]",ssl_error_code,GETERROR());
296  answer = false;
297  break;
298  }
299 
300 // ERR_clear_error();
301  return answer;
302 }
303 
304 inline void Socket_TCP_SSL::DetailErrorFormat(void)
305 {
306  return; // turn on fir debuging
307 
308  PN_uint32 l;
309  char buf[256];
310  char buf2[4096];
311  const char *file,*data;
312  int line,flags;
313  PN_uint32 es;
314 
315  es=CRYPTO_thread_id();
316  while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
317  {
318  ERR_error_string_n(l, buf, sizeof( buf) );
319  BIO_snprintf(buf2, sizeof(buf2), "***%lu:%s:%s:%d:%s\n", (unsigned long) es, buf,file, line, (flags & ERR_TXT_STRING) ? data : "NoText");
320  nativenet_cat.warning()
321  << "Socket_TCP_SSL::DetailErrorFormat->[" << buf2 << "]\n";
322  }
323 }
324 
325 #endif // HAVE_OPENSSL
326 
327 #endif //__SOCKET_TCP_SSL_H__
328 
Base functionality for a INET domain Socket this call should be the starting point for all other unix...
Definition: socket_ip.h:34
int SetNonBlocking()
this function will throw a socket into non-blocking mode
Definition: socket_ip.h:183
A simple place to store and munipulate tcp and port address for communication layer.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
SOCKET GetSocket()
Gets the base socket type.
Definition: socket_ip.h:240