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