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