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