1 /* ircd_sock.c - NextIRCd
2 * Copyright (C) 2012-2013 Philipp Kreil (pk910)
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.
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.
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/>.
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"
27 #include "IOHandler/IOSockets.h"
32 #include <stdio.h> // @debug
34 static struct Connection *sockets_listening = NULL;
35 static struct Connection *sockets_first = NULL;
36 static struct Connection *sockets_last = NULL;
38 static CONFRELOAD_CALLBACK(sockets_config_reload);
39 static IOSOCKET_CALLBACK(sockets_iohandler_callback);
40 static void sockets_free_connection(struct Connection *sock);
43 reload_config_callback(sockets_config_reload);
44 sockets_config_reload(); /* open all listening sockets */
48 static void sockets_append_list(struct Connection *conn) {
50 conn->next = sockets_listening;
51 sockets_listening = conn;
54 conn->prev = sockets_last;
56 sockets_last->next = conn;
63 static void sockets_remove_list(struct Connection *conn) {
65 struct Connection *prev;
66 if(sockets_listening == conn)
67 sockets_listening = conn->next;
69 for(prev = sockets_listening; prev; prev = prev->next) {
70 if(prev->next == conn)
74 prev->next = conn->next;
78 conn->next->prev = conn->prev;
80 sockets_last = conn->prev;
82 conn->prev->next = conn->next;
84 sockets_first = conn->next;
88 static void sockets_free_connection(struct Connection *conn) {
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);
101 static int sockets_add_listening(struct ConfigPortObject *conf_port, char *bind_addr, char *certfile, char *keyfile, int socket_flags) {
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);
116 printf("Added Listener Socket to Port %d.\n", conf_port->port); // @debug
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);
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;
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;
139 connection->parent = listener;
140 new_client->data = connection;
141 sockets_append_list(connection);
143 auth_new(connection);
146 static CONFRELOAD_CALLBACK(sockets_config_reload) {
147 struct ConfigPortObject *conf_port;
148 char *certfile, *keyfile;
150 sockets_close_listening();
152 certfile = NULL; /* to be continued */
155 for(conf_port = global_config.ports; conf_port; conf_port = conf_port->next) {
156 printf("port: %d\n", conf_port->port); // @debug
158 //add 2 listeners (IPv4 & IPv6) here
159 if(!conf_port->ip4only) {
160 char *bind_addr = conf_port->bind_addr;
163 sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV6);
166 if(!conf_port->ip6only) {
167 char *bind_addr = conf_port->bind_addr;
169 bind_addr = "0.0.0.0";
170 sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV4);
175 static IOSOCKET_CALLBACK(sockets_iohandler_callback) {
176 struct Connection *connection = event->socket->data;
178 switch(event->type) {
179 case IOSOCKETEVENT_ACCEPT:
180 sockets_accept_client(event->data.accept_socket, connection);
183 case IOSOCKETEVENT_NOTCONNECTED:
184 case IOSOCKETEVENT_CLOSED:
185 sockets_remove_list(connection);
186 if(connection->server) {
188 } else if(connection->authed) {
189 connection->data.client->conn = NULL;
190 client_exit(connection->data.client, "Client disconnected.");
192 connection->data.auth->conn = NULL;
193 auth_abort(connection->data.auth);
195 sockets_free_connection(connection);
198 case IOSOCKETEVENT_DNSFAILED:
199 if(connection->listening) {
200 // listening socket could not be opened
202 sockets_remove_list(connection);
203 sockets_free_connection(connection);
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);
213 parse_unauth_data(connection->data.auth, event->data.recv_str);
221 void socket_send(struct Connection *conn, char *data, int len) {
222 iosocket_send(conn->socket, data, len);
225 void socket_printf(struct Connection *conn, const char *text, ...) {
230 va_start(arg_list, text);
231 pos = vsnprintf(sendBuf, 512 - 2, text, arg_list);
233 if (pos < 0 || pos > (512 - 2)) pos = 512 - 2;
235 sendBuf[pos+1] = '\0';
236 iosocket_send(conn->socket, sendBuf, pos+1);
239 void socket_close(struct Connection *conn) {
240 iosocket_close(conn->socket);
241 sockets_free_connection(conn);
244 void socket_set_server(struct Connection *conn) {
245 struct IOSocket *iosock = conn->socket;
246 iosock->parse_delimiter = 0;