--- /dev/null
+/* ircd_sock.c - NextIRCd
+ * Copyright (C) 2012-2013 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "ircd_sock.h"
+#include "ircd_client.h"
+#include "struct_connection.h"
+
+#include "IOHandler/IOSockets.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h> // @debug
+
+static struct Connection *sockets_listening = NULL;
+static struct Connection *sockets_first = NULL;
+static struct Connection *sockets_last = NULL;
+
+static CONFRELOAD_CALLBACK(sockets_config_reload);
+static IOSOCKET_CALLBACK(sockets_iohandler_callback);
+static void sockets_free_connection(struct Connection *sock);
+
+void init_sockets() {
+ reload_config_callback(sockets_config_reload);
+ sockets_config_reload(); /* open all listening sockets */
+}
+
+
+static void sockets_append_list(struct Connection *conn) {
+ if(conn->listening) {
+ conn->next = sockets_listening;
+ sockets_listening = conn;
+ } else {
+ conn->next = NULL;
+ conn->prev = sockets_last;
+ if(sockets_last)
+ sockets_last->next = conn;
+ sockets_last = conn;
+ if(!sockets_first)
+ sockets_first = conn;
+ }
+}
+
+static void sockets_remove_list(struct Connection *conn) {
+ if(conn->listening) {
+ struct Connection *prev;
+ if(sockets_listening == conn)
+ sockets_listening = conn->next;
+ else {
+ for(prev = sockets_listening; prev; prev = prev->next) {
+ if(prev->next == conn)
+ break;
+ }
+ if(prev)
+ prev->next = conn->next;
+ }
+ } else {
+ if(conn->next)
+ conn->next->prev = conn->prev;
+ else
+ sockets_last = conn->prev;
+ if(conn->prev)
+ conn->prev->next = conn->next;
+ else
+ sockets_first = conn->next;
+ }
+}
+
+static void sockets_free_connection(struct Connection *conn) {
+ free(conn);
+}
+
+static void sockets_close_listening() {
+ struct Connection *conn;
+ while((conn = sockets_listening)) {
+ sockets_remove_list(conn);
+ iosocket_close(conn->socket);
+ sockets_free_connection(conn);
+ }
+}
+
+static int sockets_add_listening(struct ConfigPortObject *conf_port, char *bind_addr, char *certfile, char *keyfile, int socket_flags) {
+ if(!conf_port)
+ return -1;
+
+ struct IOSocket *iosock;
+ if(!conf_port->secure)
+ iosock = iosocket_listen_flags(bind_addr, conf_port->port, sockets_iohandler_callback, socket_flags);
+ else if(certfile && keyfile)
+ iosock = iosocket_listen_ssl_flags(bind_addr, conf_port->port, certfile, keyfile, sockets_iohandler_callback, socket_flags);
+ else
+ return -1;
+
+ if(!iosock)
+ return -1;
+
+ printf("Added Listener Socket to Port %d.\n", conf_port->port); // @debug
+
+ struct Connection *connection;
+ connection = calloc(1, sizeof(*connection));
+ connection->listening = 1;
+ connection->socket = iosock;
+ connection->server = conf_port->server;
+ iosock->data = connection;
+ sockets_append_list(connection);
+ return 0;
+}
+
+static void sockets_accept_client(struct IOSocket *new_client, struct Connection *listener) {
+ struct Connection *connection;
+ connection = calloc(1, sizeof(*connection));
+ connection->socket = new_client;
+ connection->ssl = new_client->ssl;
+
+ new_client->parse_delimiter = 1;
+ new_client->parse_empty = 0;
+ strcpy((char*) new_client->delimiters, "\r\n");
+
+ connection->parent = listener;
+ new_client->data = connection;
+ sockets_append_list(connection);
+
+ client_connected(connection);
+}
+
+static CONFRELOAD_CALLBACK(sockets_config_reload) {
+ struct ConfigPortObject *conf_port;
+ char *certfile, *keyfile;
+
+ sockets_close_listening();
+
+ certfile = NULL; /* to be continued */
+ keyfile = NULL;
+
+ for(conf_port = global_config.ports; conf_port; conf_port = conf_port->next) {
+ printf("port: %d\n", conf_port->port); // @debug
+
+ //add 2 listeners (IPv4 & IPv6) here
+ if(!conf_port->ip4only) {
+ char *bind_addr = conf_port->bind_addr;
+ if(!bind_addr)
+ bind_addr = "::1";
+ sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV6);
+ }
+
+ if(!conf_port->ip6only) {
+ char *bind_addr = conf_port->bind_addr;
+ if(!bind_addr)
+ bind_addr = "0.0.0.0";
+ sockets_add_listening(conf_port, bind_addr, certfile, keyfile, IOSOCKET_ADDR_IPV4);
+ }
+ }
+}
+
+static IOSOCKET_CALLBACK(sockets_iohandler_callback) {
+ struct Connection *connection = event->socket->data;
+
+ switch(event->type) {
+ case IOSOCKETEVENT_ACCEPT:
+ sockets_accept_client(event->data.accept_socket, connection);
+ break;
+
+ case IOSOCKETEVENT_NOTCONNECTED:
+ case IOSOCKETEVENT_CLOSED:
+ sockets_remove_list(connection);
+ if(connection->server) {
+
+ } else {
+ client_disconnected(connection);
+ }
+ sockets_free_connection(connection);
+ break;
+
+ case IOSOCKETEVENT_DNSFAILED:
+ if(connection->listening) {
+ // listening socket could not be opened
+ } else {
+ sockets_remove_list(connection);
+ client_disconnected(connection);
+ sockets_free_connection(connection);
+ }
+ break;
+
+ case IOSOCKETEVENT_RECV:
+ if(connection->server) {
+
+ } else {
+ client_recv(connection, event->data.recv_str);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void socket_send(struct Connection *conn, char *data, int len) {
+ iosocket_send(conn->socket, data, len);
+}
+