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