[IOMultiplexer] initial commit
[NeonServV5.git] / src / IOHandler_SSL.c
1 /* IOHandler_SSL.c - IOMultiplexer
2  * Copyright (C) 2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #include "IOEngine.h"
18 #include "IOHandler_SSL.h"
19
20 void iohandler_ssl_init() {
21 #ifdef HAVE_SSL
22     SSL_library_init();
23     SSL_load_error_strings();
24 #endif
25 }
26
27 void iohandler_ssl_connect(struct IODescriptor *iofd) {
28 #ifdef HAVE_SSL
29     iofd->state = IO_SSLWAIT;
30     struct IOSSLNode *sslnode = malloc(sizeof(*sslnode));
31     sslnode->sslContext = SSL_CTX_new(SSLv23_client_method());
32     if(!sslnode->sslContext)
33         goto ssl_connect_err;
34     sslnode->sslHandle = SSL_new(sslnode->sslContext);
35     if(!sslnode->sslHandle) 
36         goto ssl_connect_err;
37     if(!SSL_set_fd(sslnode->sslHandle, iofd->fd))
38         goto ssl_connect_err;
39     SSL_set_connect_state(sslnode->sslHandle);
40     iofd->sslnode = sslnode;
41     iohandler_ssl_client_handshake(iofd);
42     return;
43 ssl_connect_err:
44     free(sslnode);
45     iohandler_events(iofd, 0, 0);
46 #endif    
47 }
48
49 void iohandler_ssl_client_handshake(struct IODescriptor *iofd) {
50 #ifdef HAVE_SSL
51     // Perform an SSL handshake.
52     int ret = SSL_do_handshake(iofd->sslnode->sslHandle);
53     iofd->ssl_hs_read = 0;
54     iofd->ssl_hs_write = 0;
55     switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
56         case SSL_ERROR_NONE:
57             iofd->state = IO_CONNECTING;
58             iofd->ssl_active = 1;
59             iohandler_log(IOLOG_DEBUG, "SSL handshake for %s (fd: %d) successful", iohandler_iotype_name(iofd->type), iofd->fd);
60             iohandler_events(iofd, 0, 1); //perform IOEVENT_CONNECTED event
61             break;
62         case SSL_ERROR_WANT_READ:
63             iofd->ssl_hs_read = 1;
64             iohandler_log(IOLOG_DEBUG, "SSL_do_handshake for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
65             break;
66         case SSL_ERROR_WANT_WRITE:
67             iofd->ssl_hs_write = 1;
68             iohandler_log(IOLOG_DEBUG, "SSL_do_handshake for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
69             break;
70         default:
71             iohandler_log(IOLOG_ERROR, "SSL_do_handshake for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
72             iohandler_events(iofd, 0, 0);
73             break;
74     }
75 #endif
76 }
77
78 void iohandler_ssl_disconnect(struct IODescriptor *iofd) {
79 #ifdef HAVE_SSL
80     if(!iofd->sslnode) return;
81     SSL_shutdown(iofd->sslnode->sslHandle);
82     SSL_free(iofd->sslnode->sslHandle);
83     SSL_CTX_free(iofd->sslnode->sslContext);
84     free(iofd->sslnode);
85     iofd->sslnode = NULL;
86     iofd->ssl_active = 0;
87 #endif
88 }
89
90 int iohandler_ssl_read(struct IODescriptor *iofd, char *buffer, int len) {
91 #ifdef HAVE_SSL
92     if(!iofd->sslnode) return 0;
93     int ret = SSL_read(iofd->sslnode->sslHandle, buffer, len);
94     int update = (iofd->ssl_hs_read || iofd->ssl_hs_write);
95     iofd->ssl_hs_read = 0;
96     iofd->ssl_hs_write = 0;
97     switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
98         case SSL_ERROR_NONE:
99         case SSL_ERROR_ZERO_RETURN:
100             if(update)
101                 iohandler_update(iofd);
102             return ret;
103             break;
104         case SSL_ERROR_WANT_READ:
105             iofd->ssl_hs_read = 1;
106             iohandler_update(iofd);
107             iohandler_log(IOLOG_DEBUG, "SSL_read for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
108             errno = EAGAIN;
109             return -1;
110             break;
111         case SSL_ERROR_WANT_WRITE:
112             iofd->ssl_hs_write = 1;
113             iohandler_update(iofd);
114             iohandler_log(IOLOG_DEBUG, "SSL_read for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
115             errno = EAGAIN;
116             return -1;
117             break;
118         default:
119             iohandler_log(IOLOG_ERROR, "SSL_read for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
120             return -1;
121             break;
122     }
123 #endif
124     return 0;
125 }
126
127 int iohandler_ssl_write(struct IODescriptor *iofd, char *buffer, int len) {
128 #ifdef HAVE_SSL
129     if(!iofd->sslnode) return 0;
130     int ret = SSL_write(iofd->sslnode->sslHandle, buffer, len);
131     int update = (iofd->ssl_hs_read || iofd->ssl_hs_write);
132     iofd->ssl_hs_read = 0;
133     iofd->ssl_hs_write = 0;
134     switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
135         case SSL_ERROR_NONE:
136         case SSL_ERROR_ZERO_RETURN:
137             if(update)
138                 iohandler_update(iofd);
139             return ret;
140             break;
141         case SSL_ERROR_WANT_READ:
142             iofd->ssl_hs_read = 1;
143             iohandler_update(iofd);
144             iohandler_log(IOLOG_DEBUG, "SSL_write for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
145             errno = EAGAIN;
146             return -1;
147             break;
148         case SSL_ERROR_WANT_WRITE:
149             iofd->ssl_hs_write = 1;
150             iohandler_update(iofd);
151             iohandler_log(IOLOG_DEBUG, "SSL_write for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
152             errno = EAGAIN;
153             return -1;
154             break;
155         default:
156             iohandler_log(IOLOG_ERROR, "SSL_write for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
157             return -1;
158             break;
159     }
160 #endif
161     return 0;
162 }