added some code
[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     
138     connection->parent = listener;
139     new_client->data = connection;
140     sockets_append_list(connection);
141     
142     auth_new(connection);
143 }
144
145 static CONFRELOAD_CALLBACK(sockets_config_reload) {
146         struct ConfigPortObject *conf_port;
147         char *certfile, *keyfile;
148         
149         sockets_close_listening();
150         
151         certfile = NULL; /* to be continued */
152         keyfile = NULL;
153         
154         for(conf_port = global_config.ports; conf_port; conf_port = conf_port->next) {
155         printf("port: %d\n", conf_port->port); // @debug
156         
157         //add 2 listeners (IPv4 & IPv6) here
158                 if(!conf_port->ip4only) {
159             char *bind_addr = conf_port->bind_addr;
160             if(!bind_addr)
161                 bind_addr = "::1";
162             sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV6);
163         }
164         
165                 if(!conf_port->ip6only) {
166             char *bind_addr = conf_port->bind_addr;
167             if(!bind_addr)
168                 bind_addr = "0.0.0.0";
169             sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV4);
170         }
171         }
172 }
173
174 static IOSOCKET_CALLBACK(sockets_iohandler_callback) {
175         struct Connection *connection = event->socket->data;
176     
177     switch(event->type) {
178     case IOSOCKETEVENT_ACCEPT:
179         sockets_accept_client(event->data.accept_socket, connection);
180         break;
181     
182     case IOSOCKETEVENT_NOTCONNECTED:
183     case IOSOCKETEVENT_CLOSED:
184         sockets_remove_list(connection);
185         if(connection->server) {
186         
187         } else if(connection->authed) {
188                         connection->data.client->conn = NULL;
189             client_exit(connection->data.client, "Client disconnected.");
190         } else {
191                         connection->data.auth->conn = NULL;
192                         auth_abort(connection->data.auth);
193                 }
194         sockets_free_connection(connection);
195         break;
196     
197     case IOSOCKETEVENT_DNSFAILED:
198         if(connection->listening) {
199             // listening socket could not be opened
200         } else {
201             sockets_remove_list(connection);
202             sockets_free_connection(connection);
203         }
204         break;
205     
206     case IOSOCKETEVENT_RECV:
207         if(connection->server)
208             parse_server_data(connection->data.server, event->data.recv_buf);
209         else if(connection->authed)
210             parse_client_data(connection->data.client, event->data.recv_str);
211         else
212                         parse_unauth_data(connection->data.auth, event->data.recv_str);
213         break;
214     
215     default:
216         break;
217     }
218 }
219
220 void socket_send(struct Connection *conn, char *data, int len) {
221     iosocket_send(conn->socket, data, len);
222 }
223
224 void socket_printf(struct Connection *conn, const char *text, ...) {
225     va_list arg_list;
226         char sendBuf[512];
227         int pos;
228         sendBuf[0] = '\0';
229         va_start(arg_list, text);
230         pos = vsnprintf(sendBuf, 512 - 2, text, arg_list);
231         va_end(arg_list);
232         if (pos < 0 || pos > (512 - 2)) pos = 512 - 2;
233         sendBuf[pos] = '\n';
234     sendBuf[pos+1] = '\0';
235         iosocket_send(conn->socket, sendBuf, pos+1);
236 }
237
238 void socket_close(struct Connection *conn) {
239     iosocket_close(conn->socket);
240     sockets_free_connection(conn);
241 }
242
243 void socket_set_server(struct Connection *conn) {
244         struct IOSocket *iosock = conn->socket;
245         iosock->parse_delimiter = 0;
246         conn->server = 1;
247 }