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