push
[NextIRCd.git] / src / ircd_sock.c
1 /* ircd_sock.c - NextIRCd
2  * Copyright (C) 2012-2013  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
18 #include "ircd_config.h"
19 #include "ircd_sock.h"
20 #include "ircd_client.h"
21 #include "ircd_parse.h"
22 #include "ircd_auth.h"
23 #include "struct_connection.h"
24 #include "struct_client.h"
25 #include "struct_auth.h"
26
27 #include "IOHandler/IOSockets.h"
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <stdio.h> // @debug
33
34 static struct Connection *sockets_listening = NULL;
35 static struct Connection *sockets_first = NULL;
36 static struct Connection *sockets_last = NULL;
37
38 static CONFRELOAD_CALLBACK(sockets_config_reload);
39 static IOSOCKET_CALLBACK(sockets_iohandler_callback);
40 static void sockets_free_connection(struct Connection *sock);
41
42 void init_sockets() {
43         reload_config_callback(sockets_config_reload);
44         sockets_config_reload(); /* open all listening sockets */
45 }
46
47
48 static void sockets_append_list(struct Connection *conn) {
49         if(conn->listening) {
50                 conn->next = sockets_listening;
51                 sockets_listening = conn;
52         } else {
53                 conn->next = NULL;
54                 conn->prev = sockets_last;
55                 if(sockets_last)
56                         sockets_last->next = conn;
57                 sockets_last = conn;
58                 if(!sockets_first)
59                         sockets_first = conn;
60         }
61 }
62
63 static void sockets_remove_list(struct Connection *conn) {
64         if(conn->listening) {
65                 struct Connection *prev;
66                 if(sockets_listening == conn)
67                         sockets_listening = conn->next;
68                 else {
69                         for(prev = sockets_listening; prev; prev = prev->next) {
70                                 if(prev->next == conn)
71                                         break;
72                         }
73                         if(prev)
74                                 prev->next = conn->next;
75                 }
76         } else {
77                 if(conn->next)
78                         conn->next->prev = conn->prev;
79                 else
80                         sockets_last = conn->prev;
81                 if(conn->prev)
82                         conn->prev->next = conn->next;
83                 else
84                         sockets_first = conn->next;
85         }
86 }
87
88 static void sockets_free_connection(struct Connection *conn) {
89     free(conn);
90 }
91
92 static void sockets_close_listening() {
93         struct Connection *conn;
94         while((conn = sockets_listening)) {
95                 sockets_remove_list(conn);
96                 iosocket_close(conn->socket);
97                 sockets_free_connection(conn);
98         }
99 }
100
101 static int sockets_add_listening(struct ConfigPortObject *conf_port, char *bind_addr, char *certfile, char *keyfile, int socket_flags) {
102     if(!conf_port)
103         return -1;
104     
105     struct IOSocket *iosock;
106     if(!conf_port->secure)
107         iosock = iosocket_listen_flags(bind_addr, conf_port->port, sockets_iohandler_callback, socket_flags);
108     else if(certfile && keyfile)
109         iosock = iosocket_listen_ssl_flags(bind_addr, conf_port->port, certfile, keyfile, sockets_iohandler_callback, socket_flags);
110     else 
111         return -1;
112     
113     if(!iosock)
114         return -1;
115     
116     printf("Added Listener Socket to Port %d.\n", conf_port->port); // @debug
117     
118     struct Connection *connection;
119     connection = calloc(1, sizeof(*connection));
120     connection->listening = 1;
121     connection->socket = iosock;
122     connection->server = conf_port->server;
123     iosock->data = connection;
124     sockets_append_list(connection);
125     return 0;
126 }
127
128 static void sockets_accept_client(struct IOSocket *new_client, struct Connection *listener) {
129     struct Connection *connection;
130     connection = calloc(1, sizeof(*connection));
131     connection->socket = new_client;
132     connection->ssl = new_client->ssl;
133     
134     new_client->parse_delimiter = 1;
135     new_client->parse_empty = 0;
136     strcpy((char*) new_client->delimiters, "\r\n");
137         new_client->callback = sockets_iohandler_callback;
138     
139     connection->parent = listener;
140     new_client->data = connection;
141     sockets_append_list(connection);
142     
143     auth_new(connection);
144 }
145
146 static CONFRELOAD_CALLBACK(sockets_config_reload) {
147         struct ConfigPortObject *conf_port;
148         char *certfile, *keyfile;
149         
150         sockets_close_listening();
151         
152         certfile = NULL; /* to be continued */
153         keyfile = NULL;
154         
155         for(conf_port = global_config.ports; conf_port; conf_port = conf_port->next) {
156         printf("port: %d\n", conf_port->port); // @debug
157         
158         //add 2 listeners (IPv4 & IPv6) here
159                 if(!conf_port->ip4only) {
160             char *bind_addr = conf_port->bind_addr;
161             if(!bind_addr)
162                 bind_addr = "::1";
163             sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV6);
164         }
165         
166                 if(!conf_port->ip6only) {
167             char *bind_addr = conf_port->bind_addr;
168             if(!bind_addr)
169                 bind_addr = "0.0.0.0";
170             sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV4);
171         }
172         }
173 }
174
175 static IOSOCKET_CALLBACK(sockets_iohandler_callback) {
176         struct Connection *connection = event->socket->data;
177     
178     switch(event->type) {
179     case IOSOCKETEVENT_ACCEPT:
180         sockets_accept_client(event->data.accept_socket, connection);
181         break;
182     
183     case IOSOCKETEVENT_NOTCONNECTED:
184     case IOSOCKETEVENT_CLOSED:
185         sockets_remove_list(connection);
186         if(connection->server) {
187         
188         } else if(connection->authed) {
189                         connection->data.client->conn = NULL;
190             client_exit(connection->data.client, "Client disconnected.");
191         } else {
192                         connection->data.auth->conn = NULL;
193                         auth_abort(connection->data.auth);
194                 }
195         sockets_free_connection(connection);
196         break;
197     
198     case IOSOCKETEVENT_DNSFAILED:
199         if(connection->listening) {
200             // listening socket could not be opened
201         } else {
202             sockets_remove_list(connection);
203             sockets_free_connection(connection);
204         }
205         break;
206     
207     case IOSOCKETEVENT_RECV:
208         if(connection->server)
209             parse_server_data(connection->data.server, event->data.recv_buf);
210         else if(connection->authed)
211             parse_client_data(connection->data.client, event->data.recv_str);
212         else
213                         parse_unauth_data(connection->data.auth, event->data.recv_str);
214         break;
215     
216     default:
217         break;
218     }
219 }
220
221 void socket_send(struct Connection *conn, char *data, int len) {
222     iosocket_send(conn->socket, data, len);
223 }
224
225 void socket_printf(struct Connection *conn, const char *text, ...) {
226     va_list arg_list;
227         char sendBuf[512];
228         int pos;
229         sendBuf[0] = '\0';
230         va_start(arg_list, text);
231         pos = vsnprintf(sendBuf, 512 - 2, text, arg_list);
232         va_end(arg_list);
233         if (pos < 0 || pos > (512 - 2)) pos = 512 - 2;
234         sendBuf[pos] = '\n';
235     sendBuf[pos+1] = '\0';
236         iosocket_send(conn->socket, sendBuf, pos+1);
237 }
238
239 void socket_close(struct Connection *conn) {
240     iosocket_close(conn->socket);
241     sockets_free_connection(conn);
242 }
243
244 void socket_set_server(struct Connection *conn) {
245         struct IOSocket *iosock = conn->socket;
246         iosock->parse_delimiter = 0;
247         conn->server = 1;
248 }