source: sources/src/ioNetworkSslServer.cc @ 1464:3f6711617be1

Revision 1464:3f6711617be1, 17.8 KB checked in by niam, 22 months ago (diff)

{issue #58[resolved]} support for non-c++ exceptions

Line 
1/***************************************************************************
2 *            ioNetworkSslServer.cc
3 *  Tue Jun 10 2008
4 *  Copyright  2008  Dmytro Milinevskyy
5
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#ifdef OPENSSL_EXT
33#include <sys/socket.h>
34#include <sys/un.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <openssl/ssl.h>
38#include <openssl/err.h>
39#include <sys/stat.h>
40#include <unistd.h>
41
42#include "ioSsl.inline"
43
44#include <libdodo/ioNetworkSslServer.h>
45#include <libdodo/ioNetworkSslClient.h>
46#include <libdodo/pcSyncProtector.h>
47#include <libdodo/toolsFilesystem.h>
48#include <libdodo/ioNetworkSslServerEx.h>
49#include <libdodo/ioNetworkServer.h>
50#include <libdodo/ioSsl.h>
51#include <libdodo/types.h>
52#include <libdodo/ioNetworkSslExchange.h>
53#include <libdodo/xexec.h>
54
55using namespace dodo::io::network::ssl;
56
57server::server(server &fs) : network::server(fs)
58{
59}
60
61//-------------------------------------------------------------------
62
63server::server(short a_family,
64               short a_type) : network::server(a_family,
65                                               a_type),
66                               ctx(new io::ssl::__context__)
67{
68#ifndef IO_WO_XEXEC
69    collectedData.setExecObject(xexec::OBJECT_IONETWORKSSLSERVER);
70#endif
71}
72
73//-------------------------------------------------------------------
74
75server::~server()
76{
77    if (ctx->ctx != NULL)
78        SSL_CTX_free(ctx->ctx);
79
80    delete ctx;
81}
82
83//-------------------------------------------------------------------
84
85void
86server::removeSertificates()
87{
88    if (ctx->ctx != NULL) {
89        SSL_CTX_free(ctx->ctx);
90
91        ctx->ctx = NULL;
92    }
93
94    ctx->ctx = SSL_CTX_new(SSLv23_server_method());
95    if (ctx->ctx == NULL)
96        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_REMOVESERTIFICATES, exception::ERRNO_LIBDODO, SERVEREX_UNABLETOINITCONTEXT, IONETWORKSSLSERVEREX_UNABLETOINITCONTEXT_STR, __LINE__, __FILE__);
97}
98
99//-------------------------------------------------------------------
100
101void
102server::setSertificates(const io::ssl::__certificates__ &certs)
103{
104    if (ctx->ctx != NULL)
105        SSL_CTX_free(ctx->ctx);
106
107    ctx->ctx = SSL_CTX_new(SSLv23_server_method());
108    if (ctx->ctx == NULL)
109        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_LIBDODO, SERVEREX_UNABLETOINITCONTEXT, IONETWORKSSLSERVEREX_UNABLETOINITCONTEXT_STR, __LINE__, __FILE__);
110
111    if (certs.cipher.size() > 0 && SSL_CTX_set_cipher_list(ctx->ctx, certs.cipher.data()) != 1) {
112        unsigned long nerr = ERR_get_error();
113        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
114    }
115
116    if (certs.ca.size() > 0 && SSL_CTX_use_certificate_chain_file(ctx->ctx, certs.ca.data()) != 1) {
117        unsigned long nerr = ERR_get_error();
118        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
119    }
120
121    if (certs.cert.size() > 0 && SSL_CTX_use_certificate_file(ctx->ctx, certs.cert.data(), SSL_FILETYPE_PEM) != 1) {
122        unsigned long nerr = ERR_get_error();
123        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
124    }
125
126    if (certs.keyPassword.size() > 0)
127        SSL_CTX_set_default_passwd_cb_userdata(ctx->ctx, (void *)certs.keyPassword.data());
128
129    bool keySet = false;
130
131    if (certs.key.size() > 0) {
132        switch (certs.keyType) {
133            case io::ssl::KEY_PKEY:
134
135                if (SSL_CTX_use_PrivateKey_file(ctx->ctx, certs.key.data(), SSL_FILETYPE_PEM) != 1) {
136                    unsigned long nerr = ERR_get_error();
137                    dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
138                }
139
140                keySet = true;
141
142                break;
143
144            case io::ssl::KEY_RSA:
145
146                if (SSL_CTX_use_RSAPrivateKey_file(ctx->ctx, certs.key.data(), SSL_FILETYPE_PEM) != 1) {
147                    unsigned long nerr = ERR_get_error();
148                    dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
149                }
150
151                keySet = true;
152
153                break;
154
155            default:
156
157                dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_LIBDODO, SERVEREX_UNKNOWNKEYTYPE, IONETWORKSSLSERVEREX_UNKNOWNKEY_STR, __LINE__, __FILE__);
158        }
159    } else {
160        if (certs.ca.size() > 0) {
161            if (SSL_CTX_use_PrivateKey_file(ctx->ctx, certs.ca.data(), SSL_FILETYPE_PEM) != 1) {
162                unsigned long nerr = ERR_get_error();
163                dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
164            }
165
166            keySet = true;
167        }
168    }
169
170    if (certs.caPath.size() > 0) {
171        if (tools::filesystem::file(certs.caPath).type == tools::filesystem::FILE_DIRECTORY) {
172            if (SSL_CTX_load_verify_locations(ctx->ctx, NULL, certs.caPath.data()) != 1) {
173                unsigned long nerr = ERR_get_error();
174                dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
175            }
176        } else {
177            if (SSL_CTX_load_verify_locations(ctx->ctx, certs.caPath.data(), NULL) != 1) {
178                unsigned long nerr = ERR_get_error();
179                dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
180            }
181        }
182    }
183
184    if (keySet && SSL_CTX_check_private_key(ctx->ctx) != 1) {
185        unsigned long nerr = ERR_get_error();
186        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_SETSERTIFICATES, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
187    }
188}
189
190//-------------------------------------------------------------------
191
192void
193server::initSsl()
194{
195    if (ctx->ctx == NULL) {
196        ctx->ctx = SSL_CTX_new(SSLv23_server_method());
197        if (ctx->ctx == NULL)
198            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_INITSSL, exception::ERRNO_LIBDODO, SERVEREX_UNABLETOINITCONTEXT, IONETWORKSSLSERVEREX_UNABLETOINITCONTEXT_STR, __LINE__, __FILE__);
199    }
200}
201
202//-------------------------------------------------------------------
203
204void
205server::acceptSsl(exchange::__init__ &init)
206{
207    io::ssl::__openssl___init_object__.addEntropy();
208
209    init.handle->handle = SSL_new(ctx->ctx);
210    if (init.handle->handle == NULL)
211        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_INITSSL, exception::ERRNO_LIBDODO, SERVEREX_UNABLETOINITSSL, IONETWORKSSLSERVEREX_UNABLETOINITSSL_STR, __LINE__, __FILE__);
212
213    if (SSL_set_fd(init.handle->handle, init.socket) == 0) {
214        unsigned long nerr = ERR_get_error();
215        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPTSSL, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
216    }
217
218    int res = SSL_accept(init.handle->handle);
219    switch (res) {
220        case 1:
221            break;
222
223        case 0:
224        {
225            unsigned long nerr = ERR_get_error();
226            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPTSSL, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
227        }
228
229        case - 1:
230        {
231            int nerr = SSL_get_error(init.handle->handle, res);
232            if (nerr == SSL_ERROR_WANT_READ || nerr == SSL_ERROR_WANT_WRITE || nerr == SSL_ERROR_WANT_X509_LOOKUP)
233                break;
234        }
235
236        default:
237        {
238            unsigned long nerr = ERR_get_error();
239
240            int err = SSL_shutdown(init.handle->handle);
241            if (err < 0) {
242                nerr = ERR_get_error();
243                dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPTSSL, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
244            }
245            if (err == 0) {
246                err = SSL_shutdown(init.handle->handle);
247                if (err < 0) {
248                    nerr = ERR_get_error();
249                    dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPTSSL, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
250                }
251            }
252
253            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPTSSL, exception::ERRNO_OPENSSL, nerr, ERR_error_string(nerr, NULL), __LINE__, __FILE__);
254        }
255    }
256}
257
258//-------------------------------------------------------------------
259
260void
261server::serve(const dodo::string &host,
262              int              port,
263              int              numberOfConnections)
264{
265#ifndef IO_WO_XEXEC
266    performPreExec(OPERATION_BINDNLISTEN);
267#endif
268
269    initSsl();
270    makeSocket();
271
272    int sockFlag(1);
273    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &sockFlag, sizeof(int)) == 1)
274        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
275
276    addFlag(socketOpts, 1 << OPTION_REUSE_ADDRESS);
277
278    setLingerOption(IONETWORKCONNECTION_SOCKET_LINGER_OPTION, IONETWORKCONNECTION_SOCKET_LINGER_PERIOD);
279
280    if (family == PROTOCOL_FAMILY_IPV6) {
281        struct sockaddr_in6 sa;
282        sa.sin6_family = AF_INET6;
283        sa.sin6_port = htons(port);
284        sa.sin6_flowinfo = 0;
285        sa.sin6_scope_id = 0;
286        if (host == "*")
287            sa.sin6_addr = in6addr_any;
288        else
289            inet_pton(AF_INET6, host.data(), &sa.sin6_addr);
290
291        if (::bind(socket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
292            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
293    } else {
294        struct sockaddr_in sa;
295
296        sa.sin_family = AF_INET;
297        sa.sin_port = htons(port);
298        if (host == "*")
299            sa.sin_addr.s_addr = htonl(INADDR_ANY);
300        else
301            inet_pton(AF_INET, host.data(), &sa.sin_addr);
302
303        if (::bind(socket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
304            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
305    }
306
307    if (type == TRANSFER_STREAM)
308        if (::listen(socket, numberOfConnections) == -1)
309            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
310
311#ifndef IO_WO_XEXEC
312    performPostExec(OPERATION_BINDNLISTEN);
313#endif
314}
315
316//-------------------------------------------------------------------
317
318void
319server::serve(const dodo::string &path,
320              int              numberOfConnections,
321              bool             force)
322{
323#ifndef IO_WO_XEXEC
324    performPreExec(OPERATION_SERVE);
325#endif
326
327    initSsl();
328    makeSocket();
329
330    if (force) {
331        struct stat st;
332        if (::lstat(path.data(), &st) != -1) {
333            if (S_ISSOCK(st.st_mode))
334                ::unlink(path.data());
335            else
336                dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_LIBDODO, SERVEREX_WRONGFILENAME, IONETWORKSSLSERVEREX_WRONGFILENAME_STR, __LINE__, __FILE__);
337        }
338    }
339
340    int sockFlag(1);
341    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &sockFlag, sizeof(int)) == -1)
342        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
343
344    addFlag(socketOpts, 1 << OPTION_REUSE_ADDRESS);
345
346    setLingerOption(IONETWORKCONNECTION_SOCKET_LINGER_OPTION, IONETWORKCONNECTION_SOCKET_LINGER_PERIOD);
347
348    struct sockaddr_un sa;
349
350    unsigned long size = path.size();
351
352    if (size >= 108)
353        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_LIBDODO, SERVEREX_LONGPATH, IONETWORKSSLSERVEREX_LONGPATH_STR, __LINE__, __FILE__);
354
355    strncpy(sa.sun_path, path.data(), size);
356    sa.sun_family = AF_UNIX;
357
358    if (::bind(socket, (struct sockaddr *)&sa, path.size() + sizeof(sa.sun_family)) == -1)
359        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
360
361    if (::listen(socket, numberOfConnections) == -1)
362        dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
363
364    unixSock = path;
365
366#ifndef IO_WO_XEXEC
367    performPostExec(OPERATION_SERVE);
368#endif
369}
370
371//-------------------------------------------------------------------
372
373bool
374server::accept(network::exchange::__init__ &init,
375               __peer__                    &info)
376{
377#ifndef IO_WO_XEXEC
378    performPreExec(OPERATION_ACCEPT);
379#endif
380
381    if (type != TRANSFER_STREAM) {
382        init.socket = socket;
383        init.blocked = blocked;
384        init.blockInherited = blockInherited;
385
386        return true;
387    }
388
389    int sock(-1);
390    info.host.clear();
391
392    switch (family) {
393        case PROTOCOL_FAMILY_IPV4:
394        {
395            struct sockaddr_in sa;
396            socklen_t len = sizeof(sockaddr_in);
397            sock = ::accept(socket, (sockaddr *)&sa, &len);
398
399            if (sock == -1) {
400                if (errno == EAGAIN)
401                    return false;
402                else
403                    dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
404            }
405
406            char temp[INET_ADDRSTRLEN];
407            if (inet_ntop(AF_INET, &(sa.sin_addr), temp, INET_ADDRSTRLEN) != NULL)
408                info.host = temp;
409            info.port = ntohs(sa.sin_port);
410
411            break;
412        }
413
414        case PROTOCOL_FAMILY_IPV6:
415        {
416            struct sockaddr_in6 sa;
417            socklen_t len = sizeof(sockaddr_in6);
418
419            sock = ::accept(socket, (sockaddr *)&sa, &len);
420
421            if (sock == -1) {
422                if (errno == EAGAIN)
423                    return false;
424                else
425                    dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
426            }
427
428            char temp[INET6_ADDRSTRLEN];
429            if (inet_ntop(AF_INET6, &(sa.sin6_addr), temp, INET6_ADDRSTRLEN) != NULL)
430                info.host = temp;
431            info.port = ntohs(sa.sin6_port);
432
433            break;
434        }
435
436        case PROTOCOL_FAMILY_UNIX_SOCKET:
437
438            sock = ::accept(socket, NULL, NULL);
439            if (sock == -1) {
440                if (errno == EAGAIN)
441                    return false;
442                else
443                    dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
444            }
445
446            break;
447
448        default:
449
450            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPT, exception::ERRNO_LIBDODO, SERVEREX_WRONGPARAMETER, IONETWORKSSLSERVEREX_WRONGPARAMETER_STR, __LINE__, __FILE__);
451    }
452
453    init.socket = sock;
454    init.blocked = blocked;
455    init.blockInherited = blockInherited;
456
457    acceptSsl(dynamic_cast<exchange::__init__ &>(init));
458
459#ifndef IO_WO_XEXEC
460    performPostExec(OPERATION_ACCEPT);
461#endif
462
463    return true;
464}
465
466//-------------------------------------------------------------------
467
468bool
469server::accept(network::exchange::__init__ &init)
470{
471#ifndef IO_WO_XEXEC
472    performPreExec(OPERATION_ACCEPT);
473#endif
474
475    if (type != TRANSFER_STREAM) {
476        init.socket = socket;
477        init.blocked = blocked;
478        init.blockInherited = blockInherited;
479
480        return true;
481    }
482
483    int sock = ::accept(socket, NULL, NULL);
484    if (sock == -1) {
485        if (errno == EAGAIN)
486            return false;
487        else
488            dodo_throw exception::basic(exception::MODULE_IONETWORKSSLSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
489    }
490
491    init.socket = sock;
492    init.blocked = blocked;
493    init.blockInherited = blockInherited;
494
495    acceptSsl(dynamic_cast<exchange::__init__ &>(init));
496
497#ifndef IO_WO_XEXEC
498    performPostExec(OPERATION_ACCEPT);
499#endif
500
501    return true;
502}
503
504//-------------------------------------------------------------------
505#endif
506
Note: See TracBrowser for help on using the repository browser.