diff --git a/News b/News index 56e1f125..88d1d226 100644 --- a/News +++ b/News @@ -1,4 +1,7 @@ 2003-03-09 + Support listening on multiple sockets. + +2003-03-08 Support for shoutcast source protocol added. 2003-03-08 diff --git a/conf/icecast.xml b/conf/icecast.xml index 868907e3..e7c12cf5 100644 --- a/conf/icecast.xml +++ b/conf/icecast.xml @@ -31,9 +31,22 @@ --> localhost - 8000 + + + + + + 8000 + + + + diff --git a/src/config.c b/src/config.c index 12fa9144..8d6a39a4 100644 --- a/src/config.c +++ b/src/config.c @@ -26,7 +26,6 @@ #define CONFIG_DEFAULT_FILESERVE 1 #define CONFIG_DEFAULT_TOUCH_FREQ 5 #define CONFIG_DEFAULT_HOSTNAME "localhost" -#define CONFIG_DEFAULT_PORT 8888 #define CONFIG_DEFAULT_ACCESS_LOG "access.log" #define CONFIG_DEFAULT_ERROR_LOG "error.log" #define CONFIG_DEFAULT_LOG_LEVEL 4 @@ -61,6 +60,8 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); +static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *c); static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void create_locks() { @@ -97,6 +98,7 @@ void config_clear(ice_config_t *c) ice_config_dir_t *dirnode, *nextdirnode; relay_server *relay, *nextrelay; mount_proxy *mount, *nextmount; + int i; if (c->config_filename) free(c->config_filename); @@ -125,7 +127,9 @@ void config_clear(ice_config_t *c) xmlFree(c->access_log); if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(c->error_log); - if (c->bind_address) xmlFree(c->bind_address); + for(i=0; i < MAX_LISTEN_SOCKETS; i++) { + if (c->listeners[i].bind_address) xmlFree(c->listeners[i].bind_address); + } if (c->master_server) xmlFree(c->master_server); if (c->master_password) xmlFree(c->master_password); if (c->user) xmlFree(c->user); @@ -262,10 +266,11 @@ static void _set_defaults(ice_config_t *configuration) configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ; configuration->dir_list = NULL; configuration->hostname = CONFIG_DEFAULT_HOSTNAME; - configuration->port = CONFIG_DEFAULT_PORT; - configuration->bind_address = NULL; + configuration->port = 0; + configuration->listeners[0].port = 0; + configuration->listeners[0].bind_address = NULL; configuration->master_server = NULL; - configuration->master_server_port = CONFIG_DEFAULT_PORT; + configuration->master_server_port = 0; configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL; configuration->master_password = NULL; configuration->base_dir = CONFIG_DEFAULT_BASE_DIR; @@ -324,13 +329,17 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node, } else if (strcmp(node->name, "hostname") == 0) { if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname); configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - } else if (strcmp(node->name, "port") == 0) { + } else if (strcmp(node->name, "listen-socket") == 0) { + _parse_listen_socket(doc, node->xmlChildrenNode, configuration); + } else if (strcmp(node->name, "port") == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - configuration->port = atoi(tmp); + configuration->port = atoi(tmp); + configuration->listeners[0].port = atoi(tmp); if (tmp) xmlFree(tmp); } else if (strcmp(node->name, "bind-address") == 0) { - if (configuration->bind_address) xmlFree(configuration->bind_address); - configuration->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (configuration->listeners[0].bind_address) + xmlFree(configuration->listeners[0].bind_address); + configuration->listeners[0].bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "master-server") == 0) { if (configuration->master_server) xmlFree(configuration->master_server); configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); @@ -501,6 +510,38 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, } while ((node = node->next)); } +static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, + ice_config_t *configuration) +{ + listener_t *listener = NULL; + int i; + char *tmp; + + for(i=0; i < MAX_LISTEN_SOCKETS; i++) { + if(configuration->listeners[i].port <= 0) { + listener = &(configuration->listeners[i]); + break; + } + } + + do { + if (node == NULL) break; + if (xmlIsBlankNode(node)) continue; + + if (strcmp(node->name, "port") == 0) { + tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if(configuration->port == 0) + configuration->port = atoi(tmp); + listener->port = atoi(tmp); + if(tmp) xmlFree(tmp); + } + else if (strcmp(node->name, "bind-address") == 0) { + listener->bind_address = (char *)xmlNodeListGetString(doc, + node->xmlChildrenNode, 1); + } + } while ((node = node->next)); +} + static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { diff --git a/src/config.h b/src/config.h index 99216173..1d8fa40c 100644 --- a/src/config.h +++ b/src/config.h @@ -8,7 +8,10 @@ #define MAX_YP_DIRECTORIES 25 + #include "thread/thread.h" +#include "avl/avl.h" +#include "global.h" typedef struct ice_config_dir_tag { @@ -40,6 +43,11 @@ typedef struct _mount_proxy { struct _mount_proxy *next; } mount_proxy; +typedef struct { + int port; + char *bind_address; +} listener_t; + typedef struct ice_config_tag { char *config_filename; @@ -66,8 +74,10 @@ typedef struct ice_config_tag ice_config_dir_t *dir_list; char *hostname; - int port; - char *bind_address; + int port; + + listener_t listeners[MAX_LISTEN_SOCKETS]; + char *master_server; int master_server_port; int master_update_interval; diff --git a/src/connection.c b/src/connection.c index ca8c64e4..2c9c128c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -4,6 +4,9 @@ #include #include #include +#ifdef HAVE_POLL +#include +#endif #ifndef _WIN32 #include @@ -121,20 +124,84 @@ connection_t *create_connection(sock_t sock, char *ip) { return con; } +static int wait_for_serversock(int timeout) +{ +#ifdef HAVE_POLL + struct pollfd ufds[MAX_LISTEN_SOCKETS]; + int i, ret; + + for(i=0; i < global.server_sockets; i++) { + ufds[i].fd = global.serversock[i]; + ufds[i].events = POLLIN; + ufds[i].revents = 0; + } + + ret = poll(ufds, global.server_sockets, timeout); + if(ret < 0) { + return -2; + } + else if(ret == 0) { + return -1; + } + else { + for(i=0; i < global.server_sockets; i++) { + if(ufds[i].revents == POLLIN) + return ufds[i].fd; + } + return -1; /* Shouldn't happen */ + } +#else + fd_set rfds; + struct timeval tv, *p=NULL; + int i, ret; + int max = -1; + + FD_ZERO(&rfds); + + for(i=0; i < global.server_sockets; i++) { + FD_SET(global.serversock[i], &rfds); + if(global.serversock[i] > max) + max = global.serversock[i]; + } + + if(timeout >= 0) { + tv.tv_sec = timeout/1000; + tv.tv_usec = (timeout % 1000)/1000; + p = &tv; + } + + ret = select(max+1, &rfds, NULL, NULL, p); + if(ret < 0) { + return -2; + } + else if(ret == 0) { + return -1; + } + else { + for(i=0; i < global.server_sockets; i++) { + if(FD_ISSET(global.serversock[i], &rfds)) + return global.serversock[i]; + } + return -1; /* Should be impossible, stop compiler warnings */ + } +#endif +} + static connection_t *_accept_connection(void) { int sock; connection_t *con; char *ip; + int serversock; - if (util_timed_wait_for_fd(global.serversock, 100) <= 0) { - return NULL; - } + serversock = wait_for_serversock(100); + if(serversock < 0) + return NULL; /* malloc enough room for a full IP address (including ipv6) */ ip = (char *)malloc(MAX_ADDR_LEN); - sock = sock_accept(global.serversock, ip, MAX_ADDR_LEN); + sock = sock_accept(serversock, ip, MAX_ADDR_LEN); if (sock >= 0) { con = create_connection(sock, ip); diff --git a/src/global.c b/src/global.c index 7293f27f..e9545890 100644 --- a/src/global.c +++ b/src/global.c @@ -1,3 +1,5 @@ +#include + #include "thread.h" #include "avl.h" @@ -17,7 +19,8 @@ static mutex_t _global_mutex; void global_initialize(void) { - global.serversock = -1; + memset(global.serversock, 0, sizeof(int)*MAX_LISTEN_SOCKETS); + global.server_sockets = 0; global.running = 0; global.clients = 0; global.sources = 0; diff --git a/src/global.h b/src/global.h index b2b3b210..215a845b 100644 --- a/src/global.h +++ b/src/global.h @@ -8,11 +8,14 @@ #define ICECAST_VERSION_STRING "Icecast 2.0-alpha2/cvs" +#define MAX_LISTEN_SOCKETS 10 + #include "thread/thread.h" typedef struct ice_global_tag { - int serversock; + int serversock[MAX_LISTEN_SOCKETS]; + int server_sockets; int running; diff --git a/src/main.c b/src/main.c index ed1ddd3c..09f0a32e 100644 --- a/src/main.c +++ b/src/main.c @@ -153,26 +153,47 @@ static int _start_logging(void) return 0; } -static int _setup_socket(void) +static int _setup_sockets(void) { ice_config_t *config; + int i = 0; + int ret = 0; + int successful = 0; config = config_get_config_unlocked(); - global.serversock = sock_get_server_socket(config->port, config->bind_address); + for(i = 0; i < MAX_LISTEN_SOCKETS; i++) { + if(config->listeners[i].port <= 0) + break; - if (global.serversock == SOCK_ERROR) - return 0; + global.serversock[i] = sock_get_server_socket( + config->listeners[i].port, config->listeners[i].bind_address); + + if (global.serversock[i] == SOCK_ERROR) { + fprintf(stderr, "Could not create listener socket on port %d\n", + config->listeners[i].port); + return 0; + } + else { + ret = 1; + successful++; + } + } + + global.server_sockets = successful; - return 1; + return ret; } static int _start_listening(void) { - if (sock_listen(global.serversock, ICE_LISTEN_QUEUE) == SOCK_ERROR) - return 0; + int i; + for(i=0; i < global.server_sockets; i++) { + if (sock_listen(global.serversock[i], ICE_LISTEN_QUEUE) == SOCK_ERROR) + return 0; - sock_set_blocking(global.serversock, SOCK_NONBLOCK); + sock_set_blocking(global.serversock[i], SOCK_NONBLOCK); + } return 1; } @@ -180,11 +201,8 @@ static int _start_listening(void) /* bind the socket and start listening */ static int _server_proc_init(void) { - if (!_setup_socket()) { - fprintf(stderr, "Could not create listener socket on port %d\n", - config_get_config_unlocked()->port); + if (!_setup_sockets()) return 0; - } if (!_start_listening()) { fprintf(stderr, "Failed trying to listen on server socket\n"); @@ -197,9 +215,12 @@ static int _server_proc_init(void) /* this is the heart of the beast */ static void _server_proc(void) { + int i; + connection_accept_loop(); - sock_close(global.serversock); + for(i=0; i < MAX_LISTEN_SOCKETS; i++) + sock_close(global.serversock[i]); } /* chroot the process. Watch out - we need to do this before starting other