mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Support listening on multiple sockets.
svn path=/trunk/icecast/; revision=4454
This commit is contained in:
parent
5565b331da
commit
eba22526aa
3
News
3
News
@ -1,4 +1,7 @@
|
|||||||
2003-03-09
|
2003-03-09
|
||||||
|
Support listening on multiple sockets.
|
||||||
|
|
||||||
|
2003-03-08
|
||||||
Support for shoutcast source protocol added.
|
Support for shoutcast source protocol added.
|
||||||
|
|
||||||
2003-03-08
|
2003-03-08
|
||||||
|
@ -31,9 +31,22 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<hostname>localhost</hostname>
|
<hostname>localhost</hostname>
|
||||||
<port>8000</port>
|
|
||||||
|
|
||||||
|
<!-- You can use these two if you only want a single listener -->
|
||||||
|
<!--<port>8000</port> -->
|
||||||
<!--<bind-address>127.0.0.1</bind-address>-->
|
<!--<bind-address>127.0.0.1</bind-address>-->
|
||||||
|
|
||||||
|
<!-- You may have multiple <listener> elements -->
|
||||||
|
<listen-socket>
|
||||||
|
<port>8000</port>
|
||||||
|
<!-- <bind-address>127.0.0.1</bind-address> -->
|
||||||
|
</listen-socket>
|
||||||
|
<!--
|
||||||
|
<listen-socket>
|
||||||
|
<port>8001</port>
|
||||||
|
</listen-socket>
|
||||||
|
-->
|
||||||
|
|
||||||
<!--<master-server>127.0.0.1</master-server>-->
|
<!--<master-server>127.0.0.1</master-server>-->
|
||||||
<!--<master-server-port>8001</master-server-port>-->
|
<!--<master-server-port>8001</master-server-port>-->
|
||||||
<!--<master-update-interval>120</master-update-interval>-->
|
<!--<master-update-interval>120</master-update-interval>-->
|
||||||
|
59
src/config.c
59
src/config.c
@ -26,7 +26,6 @@
|
|||||||
#define CONFIG_DEFAULT_FILESERVE 1
|
#define CONFIG_DEFAULT_FILESERVE 1
|
||||||
#define CONFIG_DEFAULT_TOUCH_FREQ 5
|
#define CONFIG_DEFAULT_TOUCH_FREQ 5
|
||||||
#define CONFIG_DEFAULT_HOSTNAME "localhost"
|
#define CONFIG_DEFAULT_HOSTNAME "localhost"
|
||||||
#define CONFIG_DEFAULT_PORT 8888
|
|
||||||
#define CONFIG_DEFAULT_ACCESS_LOG "access.log"
|
#define CONFIG_DEFAULT_ACCESS_LOG "access.log"
|
||||||
#define CONFIG_DEFAULT_ERROR_LOG "error.log"
|
#define CONFIG_DEFAULT_ERROR_LOG "error.log"
|
||||||
#define CONFIG_DEFAULT_LOG_LEVEL 4
|
#define CONFIG_DEFAULT_LOG_LEVEL 4
|
||||||
@ -61,6 +60,8 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
ice_config_t *c);
|
ice_config_t *c);
|
||||||
static void _parse_relay(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_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 _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
|
||||||
|
|
||||||
static void create_locks() {
|
static void create_locks() {
|
||||||
@ -97,6 +98,7 @@ void config_clear(ice_config_t *c)
|
|||||||
ice_config_dir_t *dirnode, *nextdirnode;
|
ice_config_dir_t *dirnode, *nextdirnode;
|
||||||
relay_server *relay, *nextrelay;
|
relay_server *relay, *nextrelay;
|
||||||
mount_proxy *mount, *nextmount;
|
mount_proxy *mount, *nextmount;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (c->config_filename)
|
if (c->config_filename)
|
||||||
free(c->config_filename);
|
free(c->config_filename);
|
||||||
@ -125,7 +127,9 @@ void config_clear(ice_config_t *c)
|
|||||||
xmlFree(c->access_log);
|
xmlFree(c->access_log);
|
||||||
if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG)
|
if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG)
|
||||||
xmlFree(c->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_server) xmlFree(c->master_server);
|
||||||
if (c->master_password) xmlFree(c->master_password);
|
if (c->master_password) xmlFree(c->master_password);
|
||||||
if (c->user) xmlFree(c->user);
|
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->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
|
||||||
configuration->dir_list = NULL;
|
configuration->dir_list = NULL;
|
||||||
configuration->hostname = CONFIG_DEFAULT_HOSTNAME;
|
configuration->hostname = CONFIG_DEFAULT_HOSTNAME;
|
||||||
configuration->port = CONFIG_DEFAULT_PORT;
|
configuration->port = 0;
|
||||||
configuration->bind_address = NULL;
|
configuration->listeners[0].port = 0;
|
||||||
|
configuration->listeners[0].bind_address = NULL;
|
||||||
configuration->master_server = 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_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
|
||||||
configuration->master_password = NULL;
|
configuration->master_password = NULL;
|
||||||
configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
|
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) {
|
} else if (strcmp(node->name, "hostname") == 0) {
|
||||||
if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname);
|
if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname);
|
||||||
configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
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);
|
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);
|
if (tmp) xmlFree(tmp);
|
||||||
} else if (strcmp(node->name, "bind-address") == 0) {
|
} else if (strcmp(node->name, "bind-address") == 0) {
|
||||||
if (configuration->bind_address) xmlFree(configuration->bind_address);
|
if (configuration->listeners[0].bind_address)
|
||||||
configuration->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
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) {
|
} else if (strcmp(node->name, "master-server") == 0) {
|
||||||
if (configuration->master_server) xmlFree(configuration->master_server);
|
if (configuration->master_server) xmlFree(configuration->master_server);
|
||||||
configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
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));
|
} 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,
|
static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
|
||||||
ice_config_t *configuration)
|
ice_config_t *configuration)
|
||||||
{
|
{
|
||||||
|
14
src/config.h
14
src/config.h
@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
#define MAX_YP_DIRECTORIES 25
|
#define MAX_YP_DIRECTORIES 25
|
||||||
|
|
||||||
|
|
||||||
#include "thread/thread.h"
|
#include "thread/thread.h"
|
||||||
|
#include "avl/avl.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
typedef struct ice_config_dir_tag
|
typedef struct ice_config_dir_tag
|
||||||
{
|
{
|
||||||
@ -40,6 +43,11 @@ typedef struct _mount_proxy {
|
|||||||
struct _mount_proxy *next;
|
struct _mount_proxy *next;
|
||||||
} mount_proxy;
|
} mount_proxy;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int port;
|
||||||
|
char *bind_address;
|
||||||
|
} listener_t;
|
||||||
|
|
||||||
typedef struct ice_config_tag
|
typedef struct ice_config_tag
|
||||||
{
|
{
|
||||||
char *config_filename;
|
char *config_filename;
|
||||||
@ -66,8 +74,10 @@ typedef struct ice_config_tag
|
|||||||
ice_config_dir_t *dir_list;
|
ice_config_dir_t *dir_list;
|
||||||
|
|
||||||
char *hostname;
|
char *hostname;
|
||||||
int port;
|
int port;
|
||||||
char *bind_address;
|
|
||||||
|
listener_t listeners[MAX_LISTEN_SOCKETS];
|
||||||
|
|
||||||
char *master_server;
|
char *master_server;
|
||||||
int master_server_port;
|
int master_server_port;
|
||||||
int master_update_interval;
|
int master_update_interval;
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -121,20 +124,84 @@ connection_t *create_connection(sock_t sock, char *ip) {
|
|||||||
return con;
|
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)
|
static connection_t *_accept_connection(void)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
connection_t *con;
|
connection_t *con;
|
||||||
char *ip;
|
char *ip;
|
||||||
|
int serversock;
|
||||||
|
|
||||||
if (util_timed_wait_for_fd(global.serversock, 100) <= 0) {
|
serversock = wait_for_serversock(100);
|
||||||
return NULL;
|
if(serversock < 0)
|
||||||
}
|
return NULL;
|
||||||
|
|
||||||
/* malloc enough room for a full IP address (including ipv6) */
|
/* malloc enough room for a full IP address (including ipv6) */
|
||||||
ip = (char *)malloc(MAX_ADDR_LEN);
|
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) {
|
if (sock >= 0) {
|
||||||
con = create_connection(sock, ip);
|
con = create_connection(sock, ip);
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "avl.h"
|
#include "avl.h"
|
||||||
|
|
||||||
@ -17,7 +19,8 @@ static mutex_t _global_mutex;
|
|||||||
|
|
||||||
void global_initialize(void)
|
void global_initialize(void)
|
||||||
{
|
{
|
||||||
global.serversock = -1;
|
memset(global.serversock, 0, sizeof(int)*MAX_LISTEN_SOCKETS);
|
||||||
|
global.server_sockets = 0;
|
||||||
global.running = 0;
|
global.running = 0;
|
||||||
global.clients = 0;
|
global.clients = 0;
|
||||||
global.sources = 0;
|
global.sources = 0;
|
||||||
|
@ -8,11 +8,14 @@
|
|||||||
|
|
||||||
#define ICECAST_VERSION_STRING "Icecast 2.0-alpha2/cvs"
|
#define ICECAST_VERSION_STRING "Icecast 2.0-alpha2/cvs"
|
||||||
|
|
||||||
|
#define MAX_LISTEN_SOCKETS 10
|
||||||
|
|
||||||
#include "thread/thread.h"
|
#include "thread/thread.h"
|
||||||
|
|
||||||
typedef struct ice_global_tag
|
typedef struct ice_global_tag
|
||||||
{
|
{
|
||||||
int serversock;
|
int serversock[MAX_LISTEN_SOCKETS];
|
||||||
|
int server_sockets;
|
||||||
|
|
||||||
int running;
|
int running;
|
||||||
|
|
||||||
|
47
src/main.c
47
src/main.c
@ -153,26 +153,47 @@ static int _start_logging(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _setup_socket(void)
|
static int _setup_sockets(void)
|
||||||
{
|
{
|
||||||
ice_config_t *config;
|
ice_config_t *config;
|
||||||
|
int i = 0;
|
||||||
|
int ret = 0;
|
||||||
|
int successful = 0;
|
||||||
|
|
||||||
config = config_get_config_unlocked();
|
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)
|
global.serversock[i] = sock_get_server_socket(
|
||||||
return 0;
|
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)
|
static int _start_listening(void)
|
||||||
{
|
{
|
||||||
if (sock_listen(global.serversock, ICE_LISTEN_QUEUE) == SOCK_ERROR)
|
int i;
|
||||||
return 0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -180,11 +201,8 @@ static int _start_listening(void)
|
|||||||
/* bind the socket and start listening */
|
/* bind the socket and start listening */
|
||||||
static int _server_proc_init(void)
|
static int _server_proc_init(void)
|
||||||
{
|
{
|
||||||
if (!_setup_socket()) {
|
if (!_setup_sockets())
|
||||||
fprintf(stderr, "Could not create listener socket on port %d\n",
|
|
||||||
config_get_config_unlocked()->port);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (!_start_listening()) {
|
if (!_start_listening()) {
|
||||||
fprintf(stderr, "Failed trying to listen on server socket\n");
|
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 */
|
/* this is the heart of the beast */
|
||||||
static void _server_proc(void)
|
static void _server_proc(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
connection_accept_loop();
|
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
|
/* chroot the process. Watch out - we need to do this before starting other
|
||||||
|
Loading…
Reference in New Issue
Block a user