mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-02-02 15:07:36 -05:00
Brendan was getting pissed off about inconsistent indentation styles.
Convert all tabs to 4 spaces. All code must now use 4 space indents. svn path=/trunk/avl/; revision=4492
This commit is contained in:
parent
bd9c2383c5
commit
3b2df1d0d9
@ -96,7 +96,7 @@ void admin_handle_request(client_t *client, char *uri)
|
||||
/* This is a mount request, handle it as such */
|
||||
if(!connection_check_admin_pass(client->parser)) {
|
||||
if(!connection_check_source_pass(client->parser, mount)) {
|
||||
INFO1("Bad or missing password on mount modification admin "
|
||||
INFO1("Bad or missing password on mount modification admin "
|
||||
"request (command: %s)", command_string);
|
||||
client_send_401(client);
|
||||
return;
|
||||
@ -122,7 +122,7 @@ void admin_handle_request(client_t *client, char *uri)
|
||||
else {
|
||||
|
||||
if(!connection_check_admin_pass(client->parser)) {
|
||||
INFO1("Bad or missing password on admin command "
|
||||
INFO1("Bad or missing password on admin command "
|
||||
"request (command: %s)", command_string);
|
||||
client_send_401(client);
|
||||
return;
|
||||
|
758
src/avl/avl.c
758
src/avl/avl.c
File diff suppressed because it is too large
Load Diff
108
src/avl/avl.h
108
src/avl/avl.h
@ -2,7 +2,7 @@
|
||||
* Copyright (C) 1995 by Sam Rushing <rushing@nightmare.com>
|
||||
*/
|
||||
|
||||
/* $Id: avl.h,v 1.5 2003/03/09 22:56:46 karl Exp $ */
|
||||
/* $Id: avl.h,v 1.6 2003/03/15 02:10:18 msmith Exp $ */
|
||||
|
||||
#ifndef __AVL_H
|
||||
#define __AVL_H
|
||||
@ -22,24 +22,24 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct avl_node_tag {
|
||||
void * key;
|
||||
struct avl_node_tag * left;
|
||||
struct avl_node_tag * right;
|
||||
struct avl_node_tag * parent;
|
||||
void * key;
|
||||
struct avl_node_tag * left;
|
||||
struct avl_node_tag * right;
|
||||
struct avl_node_tag * parent;
|
||||
/*
|
||||
* The lower 2 bits of <rank_and_balance> specify the balance
|
||||
* factor: 00==-1, 01==0, 10==+1.
|
||||
* The rest of the bits are used for <rank>
|
||||
*/
|
||||
unsigned long rank_and_balance;
|
||||
unsigned long rank_and_balance;
|
||||
#ifndef NO_THREAD
|
||||
rwlock_t rwlock;
|
||||
#endif
|
||||
} avl_node;
|
||||
|
||||
#define AVL_GET_BALANCE(n) ((int)(((n)->rank_and_balance & 3) - 1))
|
||||
#define AVL_GET_BALANCE(n) ((int)(((n)->rank_and_balance & 3) - 1))
|
||||
|
||||
#define AVL_GET_RANK(n) (((n)->rank_and_balance >> 2))
|
||||
#define AVL_GET_RANK(n) (((n)->rank_and_balance >> 2))
|
||||
|
||||
#define AVL_SET_BALANCE(n,b) \
|
||||
((n)->rank_and_balance) = \
|
||||
@ -51,11 +51,11 @@ typedef struct avl_node_tag {
|
||||
|
||||
struct _avl_tree;
|
||||
|
||||
typedef int (*avl_key_compare_fun_type) (void * compare_arg, void * a, void * b);
|
||||
typedef int (*avl_iter_fun_type) (void * key, void * iter_arg);
|
||||
typedef int (*avl_iter_index_fun_type) (unsigned long index, void * key, void * iter_arg);
|
||||
typedef int (*avl_free_key_fun_type) (void * key);
|
||||
typedef int (*avl_key_printer_fun_type) (char *, void *);
|
||||
typedef int (*avl_key_compare_fun_type) (void * compare_arg, void * a, void * b);
|
||||
typedef int (*avl_iter_fun_type) (void * key, void * iter_arg);
|
||||
typedef int (*avl_iter_index_fun_type) (unsigned long index, void * key, void * iter_arg);
|
||||
typedef int (*avl_free_key_fun_type) (void * key);
|
||||
typedef int (*avl_key_printer_fun_type) (char *, void *);
|
||||
|
||||
/*
|
||||
* <compare_fun> and <compare_arg> let us associate a particular compare
|
||||
@ -63,11 +63,11 @@ typedef int (*avl_key_printer_fun_type) (char *, void *);
|
||||
*/
|
||||
|
||||
typedef struct _avl_tree {
|
||||
avl_node * root;
|
||||
unsigned long height;
|
||||
unsigned long length;
|
||||
avl_key_compare_fun_type compare_fun;
|
||||
void * compare_arg;
|
||||
avl_node * root;
|
||||
unsigned long height;
|
||||
unsigned long length;
|
||||
avl_key_compare_fun_type compare_fun;
|
||||
void * compare_arg;
|
||||
#ifndef NO_THREAD
|
||||
rwlock_t rwlock;
|
||||
#endif
|
||||
@ -77,66 +77,66 @@ avl_tree * avl_tree_new (avl_key_compare_fun_type compare_fun, void * compare_ar
|
||||
avl_node * avl_node_new (void * key, avl_node * parent);
|
||||
|
||||
void avl_tree_free (
|
||||
avl_tree * tree,
|
||||
avl_free_key_fun_type free_key_fun
|
||||
avl_tree * tree,
|
||||
avl_free_key_fun_type free_key_fun
|
||||
);
|
||||
|
||||
int avl_insert (
|
||||
avl_tree * ob,
|
||||
void * key
|
||||
avl_tree * ob,
|
||||
void * key
|
||||
);
|
||||
|
||||
int avl_delete (
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
avl_free_key_fun_type free_key_fun
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
avl_free_key_fun_type free_key_fun
|
||||
);
|
||||
|
||||
int avl_get_by_index (
|
||||
avl_tree * tree,
|
||||
unsigned long index,
|
||||
void ** value_address
|
||||
avl_tree * tree,
|
||||
unsigned long index,
|
||||
void ** value_address
|
||||
);
|
||||
|
||||
int avl_get_by_key (
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
void ** value_address
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
void ** value_address
|
||||
);
|
||||
|
||||
int avl_iterate_inorder (
|
||||
avl_tree * tree,
|
||||
avl_iter_fun_type iter_fun,
|
||||
void * iter_arg
|
||||
avl_tree * tree,
|
||||
avl_iter_fun_type iter_fun,
|
||||
void * iter_arg
|
||||
);
|
||||
|
||||
int avl_iterate_index_range (
|
||||
avl_tree * tree,
|
||||
avl_tree * tree,
|
||||
avl_iter_index_fun_type iter_fun,
|
||||
unsigned long low,
|
||||
unsigned long high,
|
||||
void * iter_arg
|
||||
unsigned long low,
|
||||
unsigned long high,
|
||||
void * iter_arg
|
||||
);
|
||||
|
||||
int avl_get_span_by_key (
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
unsigned long * low,
|
||||
unsigned long * high
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
unsigned long * low,
|
||||
unsigned long * high
|
||||
);
|
||||
|
||||
int avl_get_span_by_two_keys (
|
||||
avl_tree * tree,
|
||||
void * key_a,
|
||||
void * key_b,
|
||||
unsigned long * low,
|
||||
unsigned long * high
|
||||
avl_tree * tree,
|
||||
void * key_a,
|
||||
void * key_b,
|
||||
unsigned long * low,
|
||||
unsigned long * high
|
||||
);
|
||||
|
||||
int avl_verify (avl_tree * tree);
|
||||
|
||||
void avl_print_tree (
|
||||
avl_tree * tree,
|
||||
avl_tree * tree,
|
||||
avl_key_printer_fun_type key_printer
|
||||
);
|
||||
|
||||
@ -149,15 +149,15 @@ avl_node *avl_get_next(avl_node * node);
|
||||
/* These two are from David Ascher <david_ascher@brown.edu> */
|
||||
|
||||
int avl_get_item_by_key_most (
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
void ** value_address
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
void ** value_address
|
||||
);
|
||||
|
||||
int avl_get_item_by_key_least (
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
void ** value_address
|
||||
avl_tree * tree,
|
||||
void * key,
|
||||
void ** value_address
|
||||
);
|
||||
|
||||
/* optional locking stuff */
|
||||
|
@ -11,75 +11,75 @@ int _printer(char *buff, void *key);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, max_nodes;
|
||||
avl_tree *tree;
|
||||
avl_node *node;
|
||||
int i, max_nodes;
|
||||
avl_tree *tree;
|
||||
avl_node *node;
|
||||
|
||||
max_nodes = 25;
|
||||
max_nodes = 25;
|
||||
|
||||
if (argc == 2) {
|
||||
max_nodes = atoi(argv[1]);
|
||||
if (max_nodes == 0)
|
||||
max_nodes = 10;
|
||||
}
|
||||
if (argc == 2) {
|
||||
max_nodes = atoi(argv[1]);
|
||||
if (max_nodes == 0)
|
||||
max_nodes = 10;
|
||||
}
|
||||
|
||||
printf("avl test... max_nodes = %d...\n", max_nodes);
|
||||
printf("avl test... max_nodes = %d...\n", max_nodes);
|
||||
|
||||
tree = avl_tree_new(_compare, NULL);
|
||||
tree = avl_tree_new(_compare, NULL);
|
||||
|
||||
printf("Filling tree...\n");
|
||||
for (i = 0; i < max_nodes; i++) {
|
||||
avl_insert(tree, (void *)rand());
|
||||
}
|
||||
|
||||
printf("Traversing tree...\n");
|
||||
node = avl_get_first(tree);
|
||||
while (node) {
|
||||
i = (int)node->key;
|
||||
printf("Filling tree...\n");
|
||||
for (i = 0; i < max_nodes; i++) {
|
||||
avl_insert(tree, (void *)rand());
|
||||
}
|
||||
|
||||
printf("Traversing tree...\n");
|
||||
node = avl_get_first(tree);
|
||||
while (node) {
|
||||
i = (int)node->key;
|
||||
|
||||
printf("...%5d\n", i);
|
||||
printf("...%5d\n", i);
|
||||
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
|
||||
printf("Trying to go backwards...\n");
|
||||
node = tree->root->right;
|
||||
while (node) {
|
||||
i = (int)node->key;
|
||||
printf("...%5d\n", i);
|
||||
node = avl_get_prev(node);
|
||||
}
|
||||
printf("Trying to go backwards...\n");
|
||||
node = tree->root->right;
|
||||
while (node) {
|
||||
i = (int)node->key;
|
||||
printf("...%5d\n", i);
|
||||
node = avl_get_prev(node);
|
||||
}
|
||||
|
||||
printf("Printing tree...\n");
|
||||
avl_print_tree(tree, _printer);
|
||||
printf("Printing tree...\n");
|
||||
avl_print_tree(tree, _printer);
|
||||
|
||||
avl_tree_free(tree, _free);
|
||||
|
||||
return 0;
|
||||
avl_tree_free(tree, _free);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _compare(void *compare_arg, void *a, void *b)
|
||||
{
|
||||
int i, j;
|
||||
int i, j;
|
||||
|
||||
i = (int)a;
|
||||
j = (int)b;
|
||||
i = (int)a;
|
||||
j = (int)b;
|
||||
|
||||
if (i > j)
|
||||
return 1;
|
||||
if (j > i)
|
||||
return -1;
|
||||
return 0;
|
||||
if (i > j)
|
||||
return 1;
|
||||
if (j > i)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _free(void *key)
|
||||
{
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _printer(char *buff, void *key)
|
||||
{
|
||||
return snprintf(buff, 25, "%d", (int)key);
|
||||
return snprintf(buff, 25, "%d", (int)key);
|
||||
}
|
||||
|
||||
|
||||
|
36
src/client.c
36
src/client.c
@ -19,33 +19,33 @@
|
||||
|
||||
client_t *client_create(connection_t *con, http_parser_t *parser)
|
||||
{
|
||||
client_t *client = (client_t *)calloc(1, sizeof(client_t));
|
||||
client_t *client = (client_t *)calloc(1, sizeof(client_t));
|
||||
|
||||
client->con = con;
|
||||
client->parser = parser;
|
||||
client->queue = NULL;
|
||||
client->pos = 0;
|
||||
client->con = con;
|
||||
client->parser = parser;
|
||||
client->queue = NULL;
|
||||
client->pos = 0;
|
||||
|
||||
return client;
|
||||
return client;
|
||||
}
|
||||
|
||||
void client_destroy(client_t *client)
|
||||
{
|
||||
refbuf_t *refbuf;
|
||||
refbuf_t *refbuf;
|
||||
|
||||
/* write log entry if ip is set (some things don't set it, like outgoing
|
||||
/* write log entry if ip is set (some things don't set it, like outgoing
|
||||
* slave requests
|
||||
*/
|
||||
if(client->con->ip)
|
||||
logging_access(client);
|
||||
|
||||
connection_close(client->con);
|
||||
httpp_destroy(client->parser);
|
||||
logging_access(client);
|
||||
|
||||
connection_close(client->con);
|
||||
httpp_destroy(client->parser);
|
||||
|
||||
while ((refbuf = refbuf_queue_remove(&client->queue)))
|
||||
refbuf_release(refbuf);
|
||||
while ((refbuf = refbuf_queue_remove(&client->queue)))
|
||||
refbuf_release(refbuf);
|
||||
|
||||
free(client);
|
||||
free(client);
|
||||
}
|
||||
|
||||
void client_send_400(client_t *client, char *message) {
|
||||
@ -72,12 +72,12 @@ void client_send_404(client_t *client, char *message) {
|
||||
void client_send_504(client_t *client, char *message) {
|
||||
int bytes;
|
||||
client->respcode = 504;
|
||||
bytes = sock_write(client->con->sock,
|
||||
bytes = sock_write(client->con->sock,
|
||||
"HTTP/1.0 504 Server Full\r\n"
|
||||
"Content-Type: text/html\r\n\r\n"
|
||||
"<b>%s</b>\r\n", message);
|
||||
if (bytes > 0) client->con->sent_bytes = bytes;
|
||||
client_destroy(client);
|
||||
if (bytes > 0) client->con->sent_bytes = bytes;
|
||||
client_destroy(client);
|
||||
}
|
||||
|
||||
void client_send_401(client_t *client) {
|
||||
|
20
src/client.h
20
src/client.h
@ -10,18 +10,18 @@
|
||||
|
||||
typedef struct _client_tag
|
||||
{
|
||||
/* the clients connection */
|
||||
connection_t *con;
|
||||
/* the clients http headers */
|
||||
http_parser_t *parser;
|
||||
/* the clients connection */
|
||||
connection_t *con;
|
||||
/* the clients http headers */
|
||||
http_parser_t *parser;
|
||||
|
||||
/* http response code for this client */
|
||||
int respcode;
|
||||
/* http response code for this client */
|
||||
int respcode;
|
||||
|
||||
/* buffer queue */
|
||||
refbuf_queue_t *queue;
|
||||
/* position in first buffer */
|
||||
unsigned long pos;
|
||||
/* buffer queue */
|
||||
refbuf_queue_t *queue;
|
||||
/* position in first buffer */
|
||||
unsigned long pos;
|
||||
|
||||
/* Format-handler-specific data for this client */
|
||||
void *format_data;
|
||||
|
516
src/config.c
516
src/config.c
@ -89,13 +89,13 @@ void config_shutdown(void) {
|
||||
|
||||
void config_init_configuration(ice_config_t *configuration)
|
||||
{
|
||||
memset(configuration, 0, sizeof(ice_config_t));
|
||||
_set_defaults(configuration);
|
||||
memset(configuration, 0, sizeof(ice_config_t));
|
||||
_set_defaults(configuration);
|
||||
}
|
||||
|
||||
void config_clear(ice_config_t *c)
|
||||
{
|
||||
ice_config_dir_t *dirnode, *nextdirnode;
|
||||
ice_config_dir_t *dirnode, *nextdirnode;
|
||||
relay_server *relay, *nextrelay;
|
||||
mount_proxy *mount, *nextmount;
|
||||
int i;
|
||||
@ -103,27 +103,27 @@ void config_clear(ice_config_t *c)
|
||||
if (c->config_filename)
|
||||
free(c->config_filename);
|
||||
|
||||
if (c->location && c->location != CONFIG_DEFAULT_LOCATION)
|
||||
if (c->location && c->location != CONFIG_DEFAULT_LOCATION)
|
||||
xmlFree(c->location);
|
||||
if (c->admin && c->admin != CONFIG_DEFAULT_ADMIN)
|
||||
if (c->admin && c->admin != CONFIG_DEFAULT_ADMIN)
|
||||
xmlFree(c->admin);
|
||||
if (c->source_password && c->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD)
|
||||
if (c->source_password && c->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD)
|
||||
xmlFree(c->source_password);
|
||||
if (c->admin_username)
|
||||
if (c->admin_username)
|
||||
xmlFree(c->admin_username);
|
||||
if (c->admin_password)
|
||||
if (c->admin_password)
|
||||
xmlFree(c->admin_password);
|
||||
if (c->hostname && c->hostname != CONFIG_DEFAULT_HOSTNAME)
|
||||
if (c->hostname && c->hostname != CONFIG_DEFAULT_HOSTNAME)
|
||||
xmlFree(c->hostname);
|
||||
if (c->base_dir && c->base_dir != CONFIG_DEFAULT_BASE_DIR)
|
||||
if (c->base_dir && c->base_dir != CONFIG_DEFAULT_BASE_DIR)
|
||||
xmlFree(c->base_dir);
|
||||
if (c->log_dir && c->log_dir != CONFIG_DEFAULT_LOG_DIR)
|
||||
if (c->log_dir && c->log_dir != CONFIG_DEFAULT_LOG_DIR)
|
||||
xmlFree(c->log_dir);
|
||||
if (c->webroot_dir && c->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR)
|
||||
xmlFree(c->webroot_dir);
|
||||
if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG)
|
||||
if (c->access_log && c->access_log != CONFIG_DEFAULT_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);
|
||||
for(i=0; i < MAX_LISTEN_SOCKETS; i++) {
|
||||
if (c->listeners[i].bind_address) xmlFree(c->listeners[i].bind_address);
|
||||
@ -179,45 +179,45 @@ int config_initial_parse_file(const char *filename)
|
||||
|
||||
int config_parse_file(const char *filename, ice_config_t *configuration)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node;
|
||||
|
||||
if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE;
|
||||
|
||||
if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE;
|
||||
|
||||
xmlInitParser();
|
||||
doc = xmlParseFile(filename);
|
||||
if (doc == NULL) {
|
||||
return CONFIG_EPARSE;
|
||||
}
|
||||
doc = xmlParseFile(filename);
|
||||
if (doc == NULL) {
|
||||
return CONFIG_EPARSE;
|
||||
}
|
||||
|
||||
node = xmlDocGetRootElement(doc);
|
||||
if (node == NULL) {
|
||||
xmlFreeDoc(doc);
|
||||
node = xmlDocGetRootElement(doc);
|
||||
if (node == NULL) {
|
||||
xmlFreeDoc(doc);
|
||||
xmlCleanupParser();
|
||||
return CONFIG_ENOROOT;
|
||||
}
|
||||
return CONFIG_ENOROOT;
|
||||
}
|
||||
|
||||
if (strcmp(node->name, "icecast") != 0) {
|
||||
xmlFreeDoc(doc);
|
||||
if (strcmp(node->name, "icecast") != 0) {
|
||||
xmlFreeDoc(doc);
|
||||
xmlCleanupParser();
|
||||
return CONFIG_EBADROOT;
|
||||
}
|
||||
return CONFIG_EBADROOT;
|
||||
}
|
||||
|
||||
config_init_configuration(configuration);
|
||||
|
||||
configuration->config_filename = (char *)strdup(filename);
|
||||
configuration->config_filename = (char *)strdup(filename);
|
||||
|
||||
_parse_root(doc, node->xmlChildrenNode, configuration);
|
||||
_parse_root(doc, node->xmlChildrenNode, configuration);
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeDoc(doc);
|
||||
xmlCleanupParser();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_cmdline(int arg, char **argv)
|
||||
{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ice_config_locks *config_locks(void)
|
||||
@ -233,7 +233,7 @@ void config_release_config(void)
|
||||
ice_config_t *config_get_config(void)
|
||||
{
|
||||
thread_mutex_lock(&(_locks.config_lock));
|
||||
return &_current_configuration;
|
||||
return &_current_configuration;
|
||||
}
|
||||
|
||||
/* MUST be called with the lock held! */
|
||||
@ -243,39 +243,39 @@ void config_set_config(ice_config_t *config) {
|
||||
|
||||
ice_config_t *config_get_config_unlocked(void)
|
||||
{
|
||||
return &_current_configuration;
|
||||
return &_current_configuration;
|
||||
}
|
||||
|
||||
static void _set_defaults(ice_config_t *configuration)
|
||||
{
|
||||
configuration->location = CONFIG_DEFAULT_LOCATION;
|
||||
configuration->admin = CONFIG_DEFAULT_ADMIN;
|
||||
configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT;
|
||||
configuration->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT;
|
||||
configuration->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT;
|
||||
configuration->threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE;
|
||||
configuration->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT;
|
||||
configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
|
||||
configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
|
||||
configuration->source_password = CONFIG_DEFAULT_SOURCE_PASSWORD;
|
||||
configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
|
||||
configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
|
||||
configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
|
||||
configuration->dir_list = NULL;
|
||||
configuration->hostname = CONFIG_DEFAULT_HOSTNAME;
|
||||
configuration->location = CONFIG_DEFAULT_LOCATION;
|
||||
configuration->admin = CONFIG_DEFAULT_ADMIN;
|
||||
configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT;
|
||||
configuration->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT;
|
||||
configuration->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT;
|
||||
configuration->threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE;
|
||||
configuration->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT;
|
||||
configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
|
||||
configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
|
||||
configuration->source_password = CONFIG_DEFAULT_SOURCE_PASSWORD;
|
||||
configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
|
||||
configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
|
||||
configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
|
||||
configuration->dir_list = NULL;
|
||||
configuration->hostname = CONFIG_DEFAULT_HOSTNAME;
|
||||
configuration->port = 0;
|
||||
configuration->listeners[0].port = 0;
|
||||
configuration->listeners[0].bind_address = NULL;
|
||||
configuration->master_server = NULL;
|
||||
configuration->master_server_port = 0;
|
||||
configuration->listeners[0].port = 0;
|
||||
configuration->listeners[0].bind_address = NULL;
|
||||
configuration->master_server = NULL;
|
||||
configuration->master_server_port = 0;
|
||||
configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
|
||||
configuration->master_password = NULL;
|
||||
configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
|
||||
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
|
||||
configuration->master_password = NULL;
|
||||
configuration->base_dir = CONFIG_DEFAULT_BASE_DIR;
|
||||
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
|
||||
configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
|
||||
configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
|
||||
configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
|
||||
configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
|
||||
configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
|
||||
configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
|
||||
configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
|
||||
configuration->chroot = CONFIG_DEFAULT_CHROOT;
|
||||
configuration->chuid = CONFIG_DEFAULT_CHUID;
|
||||
configuration->user = CONFIG_DEFAULT_USER;
|
||||
@ -286,20 +286,20 @@ static void _set_defaults(ice_config_t *configuration)
|
||||
static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
char *tmp;
|
||||
char *tmp;
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "location") == 0) {
|
||||
if (configuration->location && configuration->location != CONFIG_DEFAULT_LOCATION) xmlFree(configuration->location);
|
||||
configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "admin") == 0) {
|
||||
if (configuration->admin && configuration->admin != CONFIG_DEFAULT_ADMIN) xmlFree(configuration->admin);
|
||||
configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if(strcmp(node->name, "authentication") == 0) {
|
||||
_parse_authentication(doc, node->xmlChildrenNode, configuration);
|
||||
if (strcmp(node->name, "location") == 0) {
|
||||
if (configuration->location && configuration->location != CONFIG_DEFAULT_LOCATION) xmlFree(configuration->location);
|
||||
configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "admin") == 0) {
|
||||
if (configuration->admin && configuration->admin != CONFIG_DEFAULT_ADMIN) xmlFree(configuration->admin);
|
||||
configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if(strcmp(node->name, "authentication") == 0) {
|
||||
_parse_authentication(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "source-password") == 0) {
|
||||
/* TODO: This is the backwards-compatibility location */
|
||||
char *mount, *pass;
|
||||
@ -308,100 +308,100 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
|
||||
/* FIXME: This is a placeholder for per-mount passwords */
|
||||
}
|
||||
else {
|
||||
if (configuration->source_password && configuration->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) xmlFree(configuration->source_password);
|
||||
configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if (configuration->source_password && configuration->source_password != CONFIG_DEFAULT_SOURCE_PASSWORD) xmlFree(configuration->source_password);
|
||||
configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
} else if (strcmp(node->name, "icelogin") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->ice_login = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "fileserve") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->fileserve = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} 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, "listen-socket") == 0) {
|
||||
} else if (strcmp(node->name, "icelogin") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->ice_login = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "fileserve") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->fileserve = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} 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, "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->listeners[0].port = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "bind-address") == 0) {
|
||||
if (configuration->listeners[0].bind_address)
|
||||
configuration->listeners[0].port = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "bind-address") == 0) {
|
||||
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);
|
||||
} else if (strcmp(node->name, "master-password") == 0) {
|
||||
if (configuration->master_password) xmlFree(configuration->master_password);
|
||||
configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "master-server-port") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->master_server_port = atoi(tmp);
|
||||
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);
|
||||
} else if (strcmp(node->name, "master-password") == 0) {
|
||||
if (configuration->master_password) xmlFree(configuration->master_password);
|
||||
configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "master-server-port") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->master_server_port = atoi(tmp);
|
||||
} else if (strcmp(node->name, "master-update-interval") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->master_update_interval = atoi(tmp);
|
||||
} else if (strcmp(node->name, "limits") == 0) {
|
||||
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "relay") == 0) {
|
||||
_parse_relay(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "mount") == 0) {
|
||||
_parse_mount(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "directory") == 0) {
|
||||
_parse_directory(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "paths") == 0) {
|
||||
_parse_paths(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "logging") == 0) {
|
||||
_parse_logging(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "limits") == 0) {
|
||||
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "relay") == 0) {
|
||||
_parse_relay(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "mount") == 0) {
|
||||
_parse_mount(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "directory") == 0) {
|
||||
_parse_directory(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "paths") == 0) {
|
||||
_parse_paths(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "logging") == 0) {
|
||||
_parse_logging(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "security") == 0) {
|
||||
_parse_security(doc, node->xmlChildrenNode, configuration);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
}
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_limits(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
char *tmp;
|
||||
char *tmp;
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "clients") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->client_limit = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "sources") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->source_limit = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "queue-size") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->queue_size_limit = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "threadpool") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->threadpool_size = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "client-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->client_timeout = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "header-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->header_timeout = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "source-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->source_timeout = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
if (strcmp(node->name, "clients") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->client_limit = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "sources") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->source_limit = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "queue-size") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->queue_size_limit = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "threadpool") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->threadpool_size = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "client-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->client_timeout = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "header-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->header_timeout = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
} else if (strcmp(node->name, "source-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->source_timeout = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
|
||||
@ -424,11 +424,11 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
|
||||
|
||||
mount->max_listeners = -1;
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "mount-name") == 0) {
|
||||
if (strcmp(node->name, "mount-name") == 0) {
|
||||
mount->mountname = (char *)xmlNodeListGetString(
|
||||
doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
@ -453,7 +453,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
|
||||
mount->max_listeners = atoi(tmp);
|
||||
if(tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
|
||||
@ -474,12 +474,12 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
|
||||
else
|
||||
configuration->relay = relay;
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "server") == 0) {
|
||||
relay->server = (char *)xmlNodeListGetString(
|
||||
if (strcmp(node->name, "server") == 0) {
|
||||
relay->server = (char *)xmlNodeListGetString(
|
||||
doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
else if (strcmp(node->name, "port") == 0) {
|
||||
@ -488,11 +488,11 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
|
||||
if(tmp) xmlFree(tmp);
|
||||
}
|
||||
else if (strcmp(node->name, "mount") == 0) {
|
||||
relay->mount = (char *)xmlNodeListGetString(
|
||||
relay->mount = (char *)xmlNodeListGetString(
|
||||
doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
else if (strcmp(node->name, "local-mount") == 0) {
|
||||
relay->localmount = (char *)xmlNodeListGetString(
|
||||
relay->localmount = (char *)xmlNodeListGetString(
|
||||
doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
else if (strcmp(node->name, "relay-shoutcast-metadata") == 0) {
|
||||
@ -500,7 +500,7 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
|
||||
relay->mp3metadata = atoi(tmp);
|
||||
if(tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
|
||||
@ -517,11 +517,11 @@ static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "port") == 0) {
|
||||
if (strcmp(node->name, "port") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if(configuration->port == 0)
|
||||
configuration->port = atoi(tmp);
|
||||
@ -532,119 +532,119 @@ static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
|
||||
listener->bind_address = (char *)xmlNodeListGetString(doc,
|
||||
node->xmlChildrenNode, 1);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "source-password") == 0) {
|
||||
if (strcmp(node->name, "source-password") == 0) {
|
||||
char *mount, *pass;
|
||||
if ((mount = (char *)xmlGetProp(node, "mount")) != NULL) {
|
||||
pass = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
/* FIXME: This is a placeholder for per-mount passwords */
|
||||
}
|
||||
else {
|
||||
if (configuration->source_password &&
|
||||
if (configuration->source_password &&
|
||||
configuration->source_password !=
|
||||
CONFIG_DEFAULT_SOURCE_PASSWORD)
|
||||
xmlFree(configuration->source_password);
|
||||
configuration->source_password =
|
||||
configuration->source_password =
|
||||
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
} else if (strcmp(node->name, "admin-password") == 0) {
|
||||
} else if (strcmp(node->name, "admin-password") == 0) {
|
||||
if(configuration->admin_password)
|
||||
xmlFree(configuration->admin_password);
|
||||
configuration->admin_password =
|
||||
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "admin-user") == 0) {
|
||||
} else if (strcmp(node->name, "admin-user") == 0) {
|
||||
if(configuration->admin_username)
|
||||
xmlFree(configuration->admin_username);
|
||||
configuration->admin_username =
|
||||
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_directory(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
char *tmp;
|
||||
char *tmp;
|
||||
|
||||
if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
|
||||
ERROR0("Maximum number of yp directories exceeded!");
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) {
|
||||
ERROR0("Maximum number of yp directories exceeded!");
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "yp-url") == 0) {
|
||||
if (configuration->yp_url[configuration->num_yp_directories])
|
||||
if (strcmp(node->name, "yp-url") == 0) {
|
||||
if (configuration->yp_url[configuration->num_yp_directories])
|
||||
xmlFree(configuration->yp_url[configuration->num_yp_directories]);
|
||||
configuration->yp_url[configuration->num_yp_directories] =
|
||||
configuration->yp_url[configuration->num_yp_directories] =
|
||||
(char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "yp-url-timeout") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->yp_url_timeout[configuration->num_yp_directories] =
|
||||
atoi(tmp);
|
||||
} else if (strcmp(node->name, "server") == 0) {
|
||||
_add_server(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "touch-interval") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->touch_interval = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
configuration->num_yp_directories++;
|
||||
} else if (strcmp(node->name, "server") == 0) {
|
||||
_add_server(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "touch-interval") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->touch_interval = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
configuration->num_yp_directories++;
|
||||
}
|
||||
|
||||
static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "basedir") == 0) {
|
||||
if (configuration->base_dir && configuration->base_dir != CONFIG_DEFAULT_BASE_DIR) xmlFree(configuration->base_dir);
|
||||
configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "logdir") == 0) {
|
||||
if (configuration->log_dir && configuration->log_dir != CONFIG_DEFAULT_LOG_DIR) xmlFree(configuration->log_dir);
|
||||
configuration->log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "webroot") == 0) {
|
||||
if (configuration->webroot_dir && configuration->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(configuration->webroot_dir);
|
||||
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if (strcmp(node->name, "basedir") == 0) {
|
||||
if (configuration->base_dir && configuration->base_dir != CONFIG_DEFAULT_BASE_DIR) xmlFree(configuration->base_dir);
|
||||
configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "logdir") == 0) {
|
||||
if (configuration->log_dir && configuration->log_dir != CONFIG_DEFAULT_LOG_DIR) xmlFree(configuration->log_dir);
|
||||
configuration->log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "webroot") == 0) {
|
||||
if (configuration->webroot_dir && configuration->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(configuration->webroot_dir);
|
||||
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
|
||||
configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
|
||||
|
||||
}
|
||||
} while ((node = node->next));
|
||||
}
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "accesslog") == 0) {
|
||||
if (configuration->access_log && configuration->access_log != CONFIG_DEFAULT_ACCESS_LOG) xmlFree(configuration->access_log);
|
||||
configuration->access_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "errorlog") == 0) {
|
||||
if (configuration->error_log && configuration->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(configuration->error_log);
|
||||
configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "loglevel") == 0) {
|
||||
if (strcmp(node->name, "accesslog") == 0) {
|
||||
if (configuration->access_log && configuration->access_log != CONFIG_DEFAULT_ACCESS_LOG) xmlFree(configuration->access_log);
|
||||
configuration->access_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "errorlog") == 0) {
|
||||
if (configuration->error_log && configuration->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(configuration->error_log);
|
||||
configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "loglevel") == 0) {
|
||||
char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->loglevel = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
} while ((node = node->next));
|
||||
} while ((node = node->next));
|
||||
}
|
||||
|
||||
static void _parse_security(xmlDocPtr doc, xmlNodePtr node,
|
||||
@ -684,45 +684,45 @@ static void _parse_security(xmlDocPtr doc, xmlNodePtr node,
|
||||
static void _add_server(xmlDocPtr doc, xmlNodePtr node,
|
||||
ice_config_t *configuration)
|
||||
{
|
||||
ice_config_dir_t *dirnode, *server;
|
||||
int addnode;
|
||||
char *tmp;
|
||||
ice_config_dir_t *dirnode, *server;
|
||||
int addnode;
|
||||
char *tmp;
|
||||
|
||||
server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t));
|
||||
server->touch_interval = configuration->touch_interval;
|
||||
server->host = NULL;
|
||||
addnode = 0;
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t));
|
||||
server->touch_interval = configuration->touch_interval;
|
||||
server->host = NULL;
|
||||
addnode = 0;
|
||||
|
||||
do {
|
||||
if (node == NULL) break;
|
||||
if (xmlIsBlankNode(node)) continue;
|
||||
|
||||
if (strcmp(node->name, "host") == 0) {
|
||||
server->host = (char *)xmlNodeListGetString(doc,
|
||||
if (strcmp(node->name, "host") == 0) {
|
||||
server->host = (char *)xmlNodeListGetString(doc,
|
||||
node->xmlChildrenNode, 1);
|
||||
addnode = 1;
|
||||
} else if (strcmp(node->name, "touch-interval") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
server->touch_interval = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
server->next = NULL;
|
||||
} while ((node = node->next));
|
||||
addnode = 1;
|
||||
} else if (strcmp(node->name, "touch-interval") == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
server->touch_interval = atoi(tmp);
|
||||
if (tmp) xmlFree(tmp);
|
||||
}
|
||||
server->next = NULL;
|
||||
} while ((node = node->next));
|
||||
|
||||
if (addnode) {
|
||||
dirnode = configuration->dir_list;
|
||||
if (dirnode == NULL) {
|
||||
configuration->dir_list = server;
|
||||
} else {
|
||||
while (dirnode->next) dirnode = dirnode->next;
|
||||
|
||||
dirnode->next = server;
|
||||
}
|
||||
|
||||
server = NULL;
|
||||
addnode = 0;
|
||||
}
|
||||
|
||||
if (addnode) {
|
||||
dirnode = configuration->dir_list;
|
||||
if (dirnode == NULL) {
|
||||
configuration->dir_list = server;
|
||||
} else {
|
||||
while (dirnode->next) dirnode = dirnode->next;
|
||||
|
||||
dirnode->next = server;
|
||||
}
|
||||
|
||||
server = NULL;
|
||||
addnode = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
46
src/config.h
46
src/config.h
@ -15,9 +15,9 @@
|
||||
|
||||
typedef struct ice_config_dir_tag
|
||||
{
|
||||
char *host;
|
||||
int touch_interval;
|
||||
struct ice_config_dir_tag *next;
|
||||
char *host;
|
||||
int touch_interval;
|
||||
struct ice_config_dir_tag *next;
|
||||
} ice_config_dir_t;
|
||||
|
||||
typedef struct _relay_server {
|
||||
@ -52,33 +52,33 @@ typedef struct ice_config_tag
|
||||
{
|
||||
char *config_filename;
|
||||
|
||||
char *location;
|
||||
char *admin;
|
||||
char *location;
|
||||
char *admin;
|
||||
|
||||
int client_limit;
|
||||
int source_limit;
|
||||
int client_limit;
|
||||
int source_limit;
|
||||
long queue_size_limit;
|
||||
int threadpool_size;
|
||||
int client_timeout;
|
||||
int header_timeout;
|
||||
int source_timeout;
|
||||
int threadpool_size;
|
||||
int client_timeout;
|
||||
int header_timeout;
|
||||
int source_timeout;
|
||||
int ice_login;
|
||||
int fileserve;
|
||||
|
||||
char *source_password;
|
||||
char *source_password;
|
||||
char *admin_username;
|
||||
char *admin_password;
|
||||
|
||||
int touch_interval;
|
||||
ice_config_dir_t *dir_list;
|
||||
int touch_interval;
|
||||
ice_config_dir_t *dir_list;
|
||||
|
||||
char *hostname;
|
||||
char *hostname;
|
||||
int port;
|
||||
|
||||
listener_t listeners[MAX_LISTEN_SOCKETS];
|
||||
|
||||
char *master_server;
|
||||
int master_server_port;
|
||||
char *master_server;
|
||||
int master_server_port;
|
||||
int master_update_interval;
|
||||
char *master_password;
|
||||
|
||||
@ -86,12 +86,12 @@ typedef struct ice_config_tag
|
||||
|
||||
mount_proxy *mounts;
|
||||
|
||||
char *base_dir;
|
||||
char *log_dir;
|
||||
char *webroot_dir;
|
||||
char *base_dir;
|
||||
char *log_dir;
|
||||
char *webroot_dir;
|
||||
|
||||
char *access_log;
|
||||
char *error_log;
|
||||
char *access_log;
|
||||
char *error_log;
|
||||
int loglevel;
|
||||
|
||||
int chroot;
|
||||
@ -99,7 +99,7 @@ typedef struct ice_config_tag
|
||||
char *user;
|
||||
char *group;
|
||||
char *yp_url[MAX_YP_DIRECTORIES];
|
||||
int yp_url_timeout[MAX_YP_DIRECTORIES];
|
||||
int yp_url_timeout[MAX_YP_DIRECTORIES];
|
||||
int num_yp_directories;
|
||||
} ice_config_t;
|
||||
|
||||
|
@ -5,52 +5,52 @@ void _dump_config(ice_config_t *config);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ice_config_t *config;
|
||||
ice_config_t *config;
|
||||
|
||||
config_initialize();
|
||||
|
||||
config_parse_file("icecast.xml");
|
||||
config_initialize();
|
||||
|
||||
config_parse_file("icecast.xml");
|
||||
|
||||
config = config_get_config_unlocked();
|
||||
config = config_get_config_unlocked();
|
||||
|
||||
_dump_config(config);
|
||||
_dump_config(config);
|
||||
|
||||
config_shutdown();
|
||||
config_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _dump_config(ice_config_t *config)
|
||||
{
|
||||
ice_config_dir_t *node;
|
||||
ice_config_dir_t *node;
|
||||
|
||||
printf("-----\n");
|
||||
printf("location = %s\n", config->location);
|
||||
printf("admin = %s\n", config->admin);
|
||||
printf("client_limit = %d\n", config->client_limit);
|
||||
printf("source_limit = %d\n", config->source_limit);
|
||||
printf("threadpool_size = %d\n", config->threadpool_size);
|
||||
printf("client_timeout = %d\n", config->client_timeout);
|
||||
printf("source_password = %s\n", config->source_password);
|
||||
printf("touch_interval = %d\n", config->touch_interval);
|
||||
printf("-----\n");
|
||||
printf("location = %s\n", config->location);
|
||||
printf("admin = %s\n", config->admin);
|
||||
printf("client_limit = %d\n", config->client_limit);
|
||||
printf("source_limit = %d\n", config->source_limit);
|
||||
printf("threadpool_size = %d\n", config->threadpool_size);
|
||||
printf("client_timeout = %d\n", config->client_timeout);
|
||||
printf("source_password = %s\n", config->source_password);
|
||||
printf("touch_interval = %d\n", config->touch_interval);
|
||||
|
||||
node = config->dir_list;
|
||||
while (node) {
|
||||
printf("directory.touch_interval = %d\n", node->touch_interval);
|
||||
printf("directory.host = %s\n", node->host);
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
node = config->dir_list;
|
||||
while (node) {
|
||||
printf("directory.touch_interval = %d\n", node->touch_interval);
|
||||
printf("directory.host = %s\n", node->host);
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
printf("hostname = %s\n", config->hostname);
|
||||
printf("port = %d\n", config->port);
|
||||
printf("bind_address = %s\n", config->bind_address);
|
||||
printf("base_dir = %s\n", config->base_dir);
|
||||
printf("log_dir = %s\n", config->log_dir);
|
||||
printf("access_log = %s\n", config->access_log);
|
||||
printf("error_log = %s\n", config->error_log);
|
||||
printf("loglevel = %d\n", config->loglevel);
|
||||
printf("-----\n");
|
||||
printf("hostname = %s\n", config->hostname);
|
||||
printf("port = %d\n", config->port);
|
||||
printf("bind_address = %s\n", config->bind_address);
|
||||
printf("base_dir = %s\n", config->base_dir);
|
||||
printf("log_dir = %s\n", config->log_dir);
|
||||
printf("access_log = %s\n", config->access_log);
|
||||
printf("error_log = %s\n", config->error_log);
|
||||
printf("loglevel = %d\n", config->loglevel);
|
||||
printf("-----\n");
|
||||
}
|
||||
|
||||
|
||||
|
620
src/connection.c
620
src/connection.c
@ -49,13 +49,13 @@
|
||||
#define CATMODULE "connection"
|
||||
|
||||
typedef struct con_queue_tag {
|
||||
connection_t *con;
|
||||
struct con_queue_tag *next;
|
||||
connection_t *con;
|
||||
struct con_queue_tag *next;
|
||||
} con_queue_t;
|
||||
|
||||
typedef struct _thread_queue_tag {
|
||||
thread_type *thread_id;
|
||||
struct _thread_queue_tag *next;
|
||||
thread_type *thread_id;
|
||||
struct _thread_queue_tag *next;
|
||||
} thread_queue_t;
|
||||
|
||||
static mutex_t _connection_mutex;
|
||||
@ -74,54 +74,54 @@ static void *_handle_connection(void *arg);
|
||||
|
||||
void connection_initialize(void)
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
thread_mutex_create(&_connection_mutex);
|
||||
thread_mutex_create(&_queue_mutex);
|
||||
thread_rwlock_create(&_source_shutdown_rwlock);
|
||||
thread_cond_create(&_pool_cond);
|
||||
if (_initialized) return;
|
||||
|
||||
thread_mutex_create(&_connection_mutex);
|
||||
thread_mutex_create(&_queue_mutex);
|
||||
thread_rwlock_create(&_source_shutdown_rwlock);
|
||||
thread_cond_create(&_pool_cond);
|
||||
thread_cond_create(&global.shutdown_cond);
|
||||
|
||||
_initialized = 1;
|
||||
_initialized = 1;
|
||||
}
|
||||
|
||||
void connection_shutdown(void)
|
||||
{
|
||||
if (!_initialized) return;
|
||||
|
||||
if (!_initialized) return;
|
||||
|
||||
thread_cond_destroy(&global.shutdown_cond);
|
||||
thread_cond_destroy(&_pool_cond);
|
||||
thread_rwlock_destroy(&_source_shutdown_rwlock);
|
||||
thread_mutex_destroy(&_queue_mutex);
|
||||
thread_mutex_destroy(&_connection_mutex);
|
||||
thread_cond_destroy(&_pool_cond);
|
||||
thread_rwlock_destroy(&_source_shutdown_rwlock);
|
||||
thread_mutex_destroy(&_queue_mutex);
|
||||
thread_mutex_destroy(&_connection_mutex);
|
||||
|
||||
_initialized = 0;
|
||||
_initialized = 0;
|
||||
}
|
||||
|
||||
static unsigned long _next_connection_id(void)
|
||||
{
|
||||
unsigned long id;
|
||||
unsigned long id;
|
||||
|
||||
thread_mutex_lock(&_connection_mutex);
|
||||
id = _current_id++;
|
||||
thread_mutex_unlock(&_connection_mutex);
|
||||
thread_mutex_lock(&_connection_mutex);
|
||||
id = _current_id++;
|
||||
thread_mutex_unlock(&_connection_mutex);
|
||||
|
||||
return id;
|
||||
return id;
|
||||
}
|
||||
|
||||
connection_t *create_connection(sock_t sock, char *ip) {
|
||||
connection_t *con;
|
||||
con = (connection_t *)malloc(sizeof(connection_t));
|
||||
memset(con, 0, sizeof(connection_t));
|
||||
con->sock = sock;
|
||||
con->con_time = time(NULL);
|
||||
con->id = _next_connection_id();
|
||||
con->ip = ip;
|
||||
connection_t *con;
|
||||
con = (connection_t *)malloc(sizeof(connection_t));
|
||||
memset(con, 0, sizeof(connection_t));
|
||||
con->sock = sock;
|
||||
con->con_time = time(NULL);
|
||||
con->id = _next_connection_id();
|
||||
con->ip = ip;
|
||||
|
||||
con->event_number = EVENT_NO_EVENT;
|
||||
con->event = NULL;
|
||||
|
||||
return con;
|
||||
return con;
|
||||
}
|
||||
|
||||
static int wait_for_serversock(int timeout)
|
||||
@ -189,181 +189,181 @@ static int wait_for_serversock(int timeout)
|
||||
|
||||
static connection_t *_accept_connection(void)
|
||||
{
|
||||
int sock;
|
||||
connection_t *con;
|
||||
char *ip;
|
||||
int sock;
|
||||
connection_t *con;
|
||||
char *ip;
|
||||
int serversock;
|
||||
|
||||
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);
|
||||
/* malloc enough room for a full IP address (including ipv6) */
|
||||
ip = (char *)malloc(MAX_ADDR_LEN);
|
||||
|
||||
sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
|
||||
if (sock >= 0) {
|
||||
con = create_connection(sock, ip);
|
||||
sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
|
||||
if (sock >= 0) {
|
||||
con = create_connection(sock, ip);
|
||||
|
||||
return con;
|
||||
}
|
||||
return con;
|
||||
}
|
||||
|
||||
if (!sock_recoverable(sock_error()))
|
||||
WARN2("accept() failed with error %d: %s", sock_error(), strerror(sock_error()));
|
||||
|
||||
free(ip);
|
||||
if (!sock_recoverable(sock_error()))
|
||||
WARN2("accept() failed with error %d: %s", sock_error(), strerror(sock_error()));
|
||||
|
||||
free(ip);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _add_connection(connection_t *con)
|
||||
{
|
||||
con_queue_t *node;
|
||||
con_queue_t *node;
|
||||
|
||||
node = (con_queue_t *)malloc(sizeof(con_queue_t));
|
||||
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
node->con = con;
|
||||
node->next = _queue;
|
||||
_queue = node;
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
node = (con_queue_t *)malloc(sizeof(con_queue_t));
|
||||
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
node->con = con;
|
||||
node->next = _queue;
|
||||
_queue = node;
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
|
||||
}
|
||||
|
||||
static void _signal_pool(void)
|
||||
{
|
||||
thread_cond_signal(&_pool_cond);
|
||||
thread_cond_signal(&_pool_cond);
|
||||
}
|
||||
|
||||
static void _push_thread(thread_queue_t **queue, thread_type *thread_id)
|
||||
{
|
||||
/* create item */
|
||||
thread_queue_t *item = (thread_queue_t *)malloc(sizeof(thread_queue_t));
|
||||
item->thread_id = thread_id;
|
||||
item->next = NULL;
|
||||
/* create item */
|
||||
thread_queue_t *item = (thread_queue_t *)malloc(sizeof(thread_queue_t));
|
||||
item->thread_id = thread_id;
|
||||
item->next = NULL;
|
||||
|
||||
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
if (*queue == NULL) {
|
||||
*queue = item;
|
||||
} else {
|
||||
item->next = *queue;
|
||||
*queue = item;
|
||||
}
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
if (*queue == NULL) {
|
||||
*queue = item;
|
||||
} else {
|
||||
item->next = *queue;
|
||||
*queue = item;
|
||||
}
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
}
|
||||
|
||||
static thread_type *_pop_thread(thread_queue_t **queue)
|
||||
{
|
||||
thread_type *id;
|
||||
thread_queue_t *item;
|
||||
thread_type *id;
|
||||
thread_queue_t *item;
|
||||
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
|
||||
item = *queue;
|
||||
if (item == NULL) {
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
return NULL;
|
||||
}
|
||||
item = *queue;
|
||||
if (item == NULL) {
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*queue = item->next;
|
||||
item->next = NULL;
|
||||
id = item->thread_id;
|
||||
free(item);
|
||||
*queue = item->next;
|
||||
item->next = NULL;
|
||||
id = item->thread_id;
|
||||
free(item);
|
||||
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
|
||||
return id;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void _build_pool(void)
|
||||
{
|
||||
ice_config_t *config;
|
||||
int i;
|
||||
ice_config_t *config;
|
||||
int i;
|
||||
thread_type *tid;
|
||||
char buff[64];
|
||||
char buff[64];
|
||||
int threadpool_size;
|
||||
|
||||
config = config_get_config();
|
||||
config = config_get_config();
|
||||
threadpool_size = config->threadpool_size;
|
||||
config_release_config();
|
||||
|
||||
for (i = 0; i < threadpool_size; i++) {
|
||||
snprintf(buff, 64, "Connection Thread #%d", i);
|
||||
tid = thread_create(buff, _handle_connection, NULL, THREAD_ATTACHED);
|
||||
_push_thread(&_conhands, tid);
|
||||
}
|
||||
for (i = 0; i < threadpool_size; i++) {
|
||||
snprintf(buff, 64, "Connection Thread #%d", i);
|
||||
tid = thread_create(buff, _handle_connection, NULL, THREAD_ATTACHED);
|
||||
_push_thread(&_conhands, tid);
|
||||
}
|
||||
}
|
||||
|
||||
static void _destroy_pool(void)
|
||||
{
|
||||
thread_type *id;
|
||||
int i;
|
||||
thread_type *id;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
i = 0;
|
||||
|
||||
thread_cond_broadcast(&_pool_cond);
|
||||
id = _pop_thread(&_conhands);
|
||||
while (id != NULL) {
|
||||
thread_join(id);
|
||||
_signal_pool();
|
||||
id = _pop_thread(&_conhands);
|
||||
}
|
||||
thread_cond_broadcast(&_pool_cond);
|
||||
id = _pop_thread(&_conhands);
|
||||
while (id != NULL) {
|
||||
thread_join(id);
|
||||
_signal_pool();
|
||||
id = _pop_thread(&_conhands);
|
||||
}
|
||||
}
|
||||
|
||||
void connection_accept_loop(void)
|
||||
{
|
||||
connection_t *con;
|
||||
connection_t *con;
|
||||
|
||||
_build_pool();
|
||||
_build_pool();
|
||||
|
||||
while (global.running == ICE_RUNNING) {
|
||||
con = _accept_connection();
|
||||
while (global.running == ICE_RUNNING) {
|
||||
con = _accept_connection();
|
||||
|
||||
if (con) {
|
||||
_add_connection(con);
|
||||
_signal_pool();
|
||||
}
|
||||
}
|
||||
if (con) {
|
||||
_add_connection(con);
|
||||
_signal_pool();
|
||||
}
|
||||
}
|
||||
|
||||
/* Give all the other threads notification to shut down */
|
||||
thread_cond_broadcast(&global.shutdown_cond);
|
||||
|
||||
_destroy_pool();
|
||||
_destroy_pool();
|
||||
|
||||
/* wait for all the sources to shutdown */
|
||||
thread_rwlock_wlock(&_source_shutdown_rwlock);
|
||||
thread_rwlock_unlock(&_source_shutdown_rwlock);
|
||||
/* wait for all the sources to shutdown */
|
||||
thread_rwlock_wlock(&_source_shutdown_rwlock);
|
||||
thread_rwlock_unlock(&_source_shutdown_rwlock);
|
||||
}
|
||||
|
||||
static connection_t *_get_connection(void)
|
||||
{
|
||||
con_queue_t *node = NULL;
|
||||
con_queue_t *oldnode = NULL;
|
||||
connection_t *con = NULL;
|
||||
con_queue_t *node = NULL;
|
||||
con_queue_t *oldnode = NULL;
|
||||
connection_t *con = NULL;
|
||||
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
if (_queue) {
|
||||
node = _queue;
|
||||
while (node->next) {
|
||||
oldnode = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
/* node is now the last node
|
||||
** and oldnode is the previous one, or NULL
|
||||
*/
|
||||
if (oldnode) oldnode->next = NULL;
|
||||
else (_queue) = NULL;
|
||||
}
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
thread_mutex_lock(&_queue_mutex);
|
||||
if (_queue) {
|
||||
node = _queue;
|
||||
while (node->next) {
|
||||
oldnode = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
/* node is now the last node
|
||||
** and oldnode is the previous one, or NULL
|
||||
*/
|
||||
if (oldnode) oldnode->next = NULL;
|
||||
else (_queue) = NULL;
|
||||
}
|
||||
thread_mutex_unlock(&_queue_mutex);
|
||||
|
||||
if (node) {
|
||||
con = node->con;
|
||||
free(node);
|
||||
}
|
||||
if (node) {
|
||||
con = node->con;
|
||||
free(node);
|
||||
}
|
||||
|
||||
return con;
|
||||
return con;
|
||||
}
|
||||
|
||||
void connection_inject_event(int eventnum, void *event_data) {
|
||||
@ -380,8 +380,8 @@ void connection_inject_event(int eventnum, void *event_data) {
|
||||
* codes where appropriate
|
||||
*/
|
||||
int connection_create_source(client_t *client, connection_t *con, http_parser_t *parser, char *mount) {
|
||||
source_t *source;
|
||||
char *contenttype;
|
||||
source_t *source;
|
||||
char *contenttype;
|
||||
mount_proxy *mountproxy, *mountinfo = NULL;
|
||||
int source_limit;
|
||||
ice_config_t *config;
|
||||
@ -390,19 +390,19 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t
|
||||
source_limit = config->source_limit;
|
||||
config_release_config();
|
||||
|
||||
/* check to make sure this source wouldn't
|
||||
** be over the limit
|
||||
*/
|
||||
global_lock();
|
||||
if (global.sources >= source_limit) {
|
||||
INFO1("Source (%s) logged in, but there are too many sources", mount);
|
||||
global_unlock();
|
||||
return 0;
|
||||
}
|
||||
global.sources++;
|
||||
global_unlock();
|
||||
/* check to make sure this source wouldn't
|
||||
** be over the limit
|
||||
*/
|
||||
global_lock();
|
||||
if (global.sources >= source_limit) {
|
||||
INFO1("Source (%s) logged in, but there are too many sources", mount);
|
||||
global_unlock();
|
||||
return 0;
|
||||
}
|
||||
global.sources++;
|
||||
global_unlock();
|
||||
|
||||
stats_event_inc(NULL, "sources");
|
||||
stats_event_inc(NULL, "sources");
|
||||
|
||||
config = config_get_config();
|
||||
mountproxy = config->mounts;
|
||||
@ -417,31 +417,31 @@ int connection_create_source(client_t *client, connection_t *con, http_parser_t
|
||||
mountproxy = mountproxy->next;
|
||||
}
|
||||
|
||||
contenttype = httpp_getvar(parser, "content-type");
|
||||
contenttype = httpp_getvar(parser, "content-type");
|
||||
|
||||
if (contenttype != NULL) {
|
||||
format_type_t format = format_get_type(contenttype);
|
||||
if (format == FORMAT_ERROR) {
|
||||
WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
|
||||
if (contenttype != NULL) {
|
||||
format_type_t format = format_get_type(contenttype);
|
||||
if (format == FORMAT_ERROR) {
|
||||
WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
|
||||
thread_mutex_unlock(&(config_locks()->mounts_lock));
|
||||
goto fail;
|
||||
} else {
|
||||
source = source_create(client, con, parser, mount,
|
||||
} else {
|
||||
source = source_create(client, con, parser, mount,
|
||||
format, mountinfo);
|
||||
thread_mutex_unlock(&(config_locks()->mounts_lock));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
format_type_t format = FORMAT_TYPE_MP3;
|
||||
ERROR0("No content-type header, falling back to backwards compatibility mode for icecast 1.x relays. Assuming content is mp3.");
|
||||
ERROR0("No content-type header, falling back to backwards compatibility mode for icecast 1.x relays. Assuming content is mp3.");
|
||||
source = source_create(client, con, parser, mount, format, mountinfo);
|
||||
thread_mutex_unlock(&(config_locks()->mounts_lock));
|
||||
}
|
||||
}
|
||||
|
||||
source->send_return = 1;
|
||||
source->shutdown_rwlock = &_source_shutdown_rwlock;
|
||||
sock_set_blocking(con->sock, SOCK_NONBLOCK);
|
||||
thread_create("Source Thread", source_main, (void *)source, THREAD_DETACHED);
|
||||
return 1;
|
||||
source->shutdown_rwlock = &_source_shutdown_rwlock;
|
||||
sock_set_blocking(con->sock, SOCK_NONBLOCK);
|
||||
thread_create("Source Thread", source_main, (void *)source, THREAD_DETACHED);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
global_lock();
|
||||
@ -499,7 +499,7 @@ static int _check_pass_icy(http_parser_t *parser, char *correctpass)
|
||||
if(!password)
|
||||
return 0;
|
||||
|
||||
if (strcmp(password, correctpass))
|
||||
if (strcmp(password, correctpass))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
@ -513,7 +513,7 @@ static int _check_pass_ice(http_parser_t *parser, char *correctpass)
|
||||
if(!password)
|
||||
password = "";
|
||||
|
||||
if (strcmp(password, correctpass))
|
||||
if (strcmp(password, correctpass))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
@ -584,67 +584,67 @@ static void _handle_source_request(connection_t *con,
|
||||
{
|
||||
client_t *client;
|
||||
|
||||
client = client_create(con, parser);
|
||||
client = client_create(con, parser);
|
||||
|
||||
INFO1("Source logging in at mountpoint \"%s\"", uri);
|
||||
stats_event_inc(NULL, "source_connections");
|
||||
|
||||
if (!connection_check_source_pass(parser, uri)) {
|
||||
INFO1("Source (%s) attempted to login with invalid or missing password", uri);
|
||||
|
||||
if (!connection_check_source_pass(parser, uri)) {
|
||||
INFO1("Source (%s) attempted to login with invalid or missing password", uri);
|
||||
client_send_401(client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check to make sure this source has
|
||||
** a unique mountpoint
|
||||
*/
|
||||
/* check to make sure this source has
|
||||
** a unique mountpoint
|
||||
*/
|
||||
|
||||
avl_tree_rlock(global.source_tree);
|
||||
if (source_find_mount(uri) != NULL) {
|
||||
avl_tree_unlock(global.source_tree);
|
||||
INFO1("Source tried to log in as %s, but mountpoint is already used", uri);
|
||||
avl_tree_rlock(global.source_tree);
|
||||
if (source_find_mount(uri) != NULL) {
|
||||
avl_tree_unlock(global.source_tree);
|
||||
INFO1("Source tried to log in as %s, but mountpoint is already used", uri);
|
||||
client_send_404(client, "Mountpoint in use");
|
||||
return;
|
||||
}
|
||||
avl_tree_unlock(global.source_tree);
|
||||
return;
|
||||
}
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
if (!connection_create_source(client, con, parser, uri)) {
|
||||
if (!connection_create_source(client, con, parser, uri)) {
|
||||
client_send_404(client, "Mountpoint in use");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _handle_stats_request(connection_t *con,
|
||||
http_parser_t *parser, char *uri)
|
||||
{
|
||||
stats_connection_t *stats;
|
||||
stats_connection_t *stats;
|
||||
|
||||
stats_event_inc(NULL, "stats_connections");
|
||||
|
||||
if (!connection_check_admin_pass(parser)) {
|
||||
stats_event_inc(NULL, "stats_connections");
|
||||
|
||||
if (!connection_check_admin_pass(parser)) {
|
||||
ERROR0("Bad password for stats connection");
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
return;
|
||||
}
|
||||
|
||||
stats_event_inc(NULL, "stats");
|
||||
|
||||
/* create stats connection and create stats handler thread */
|
||||
stats = (stats_connection_t *)malloc(sizeof(stats_connection_t));
|
||||
stats->parser = parser;
|
||||
stats->con = con;
|
||||
|
||||
thread_create("Stats Connection", stats_connection, (void *)stats, THREAD_DETACHED);
|
||||
}
|
||||
|
||||
stats_event_inc(NULL, "stats");
|
||||
|
||||
/* create stats connection and create stats handler thread */
|
||||
stats = (stats_connection_t *)malloc(sizeof(stats_connection_t));
|
||||
stats->parser = parser;
|
||||
stats->con = con;
|
||||
|
||||
thread_create("Stats Connection", stats_connection, (void *)stats, THREAD_DETACHED);
|
||||
}
|
||||
|
||||
static void _handle_get_request(connection_t *con,
|
||||
http_parser_t *parser, char *uri)
|
||||
{
|
||||
char *fullpath;
|
||||
client_t *client;
|
||||
client_t *client;
|
||||
int bytes;
|
||||
struct stat statbuf;
|
||||
source_t *source;
|
||||
struct stat statbuf;
|
||||
source_t *source;
|
||||
int fileserve;
|
||||
char *host;
|
||||
int port;
|
||||
@ -661,48 +661,48 @@ static void _handle_get_request(connection_t *con,
|
||||
|
||||
DEBUG0("Client connected");
|
||||
|
||||
/* make a client */
|
||||
client = client_create(con, parser);
|
||||
stats_event_inc(NULL, "client_connections");
|
||||
|
||||
/* there are several types of HTTP GET clients
|
||||
** media clients, which are looking for a source (eg, URI = /stream.ogg)
|
||||
** stats clients, which are looking for /admin/stats.xml
|
||||
** and director server authorizers, which are looking for /GUID-xxxxxxxx
|
||||
/* make a client */
|
||||
client = client_create(con, parser);
|
||||
stats_event_inc(NULL, "client_connections");
|
||||
|
||||
/* there are several types of HTTP GET clients
|
||||
** media clients, which are looking for a source (eg, URI = /stream.ogg)
|
||||
** stats clients, which are looking for /admin/stats.xml
|
||||
** and director server authorizers, which are looking for /GUID-xxxxxxxx
|
||||
** (where xxxxxx is the GUID in question) - this isn't implemented yet.
|
||||
** we need to handle the latter two before the former, as the latter two
|
||||
** aren't subject to the limits.
|
||||
*/
|
||||
/* TODO: add GUID-xxxxxx */
|
||||
** we need to handle the latter two before the former, as the latter two
|
||||
** aren't subject to the limits.
|
||||
*/
|
||||
/* TODO: add GUID-xxxxxx */
|
||||
|
||||
/* Dispatch all admin requests */
|
||||
if (strncmp(uri, "/admin/", 7) == 0) {
|
||||
if (strncmp(uri, "/admin/", 7) == 0) {
|
||||
admin_handle_request(client, uri);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Here we are parsing the URI request to see
|
||||
** if the extension is .xsl, if so, then process
|
||||
** this request as an XSLT request
|
||||
*/
|
||||
/* Here we are parsing the URI request to see
|
||||
** if the extension is .xsl, if so, then process
|
||||
** this request as an XSLT request
|
||||
*/
|
||||
fullpath = util_get_path_from_normalised_uri(uri);
|
||||
if (util_check_valid_extension(fullpath) == XSLT_CONTENT) {
|
||||
/* If the file exists, then transform it, otherwise, write a 404 */
|
||||
if (stat(fullpath, &statbuf) == 0) {
|
||||
/* If the file exists, then transform it, otherwise, write a 404 */
|
||||
if (stat(fullpath, &statbuf) == 0) {
|
||||
DEBUG0("Stats request, sending XSL transformed stats");
|
||||
client->respcode = 200;
|
||||
bytes = sock_write(client->con->sock,
|
||||
bytes = sock_write(client->con->sock,
|
||||
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
|
||||
if(bytes > 0) client->con->sent_bytes = bytes;
|
||||
stats_transform_xslt(client, fullpath);
|
||||
client_destroy(client);
|
||||
}
|
||||
else {
|
||||
client_destroy(client);
|
||||
}
|
||||
else {
|
||||
client_send_404(client, "The file you requested could not be found");
|
||||
}
|
||||
}
|
||||
free(fullpath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(fileserve && stat(fullpath, &statbuf) == 0)
|
||||
{
|
||||
fserve_client_create(client, fullpath);
|
||||
@ -715,9 +715,9 @@ static void _handle_get_request(connection_t *con,
|
||||
char *sourceuri = strdup(uri);
|
||||
char *dot = strrchr(sourceuri, '.');
|
||||
*dot = 0;
|
||||
avl_tree_rlock(global.source_tree);
|
||||
source = source_find_mount(sourceuri);
|
||||
if (source) {
|
||||
avl_tree_rlock(global.source_tree);
|
||||
source = source_find_mount(sourceuri);
|
||||
if (source) {
|
||||
client->respcode = 200;
|
||||
bytes = sock_write(client->con->sock,
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
@ -728,7 +728,7 @@ static void _handle_get_request(connection_t *con,
|
||||
sourceuri
|
||||
);
|
||||
if(bytes > 0) client->con->sent_bytes = bytes;
|
||||
client_destroy(client);
|
||||
client_destroy(client);
|
||||
}
|
||||
else if(fileserve) {
|
||||
fullpath = util_get_path_from_normalised_uri(sourceuri);
|
||||
@ -753,85 +753,85 @@ static void _handle_get_request(connection_t *con,
|
||||
else {
|
||||
client_send_404(client, "The file you requested could not be found");
|
||||
}
|
||||
avl_tree_unlock(global.source_tree);
|
||||
avl_tree_unlock(global.source_tree);
|
||||
free(sourceuri);
|
||||
return;
|
||||
}
|
||||
|
||||
global_lock();
|
||||
if (global.clients >= client_limit) {
|
||||
global_lock();
|
||||
if (global.clients >= client_limit) {
|
||||
client_send_504(client,
|
||||
"The server is already full. Try again later.");
|
||||
global_unlock();
|
||||
global_unlock();
|
||||
return;
|
||||
}
|
||||
global_unlock();
|
||||
|
||||
avl_tree_rlock(global.source_tree);
|
||||
source = source_find_mount(uri);
|
||||
if (source) {
|
||||
}
|
||||
global_unlock();
|
||||
|
||||
avl_tree_rlock(global.source_tree);
|
||||
source = source_find_mount(uri);
|
||||
if (source) {
|
||||
DEBUG0("Source found for client");
|
||||
|
||||
global_lock();
|
||||
if (global.clients >= client_limit) {
|
||||
|
||||
global_lock();
|
||||
if (global.clients >= client_limit) {
|
||||
client_send_504(client,
|
||||
"The server is already full. Try again later.");
|
||||
global_unlock();
|
||||
global_unlock();
|
||||
avl_tree_unlock(global.source_tree);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(source->max_listeners != -1 &&
|
||||
source->listeners >= source->max_listeners)
|
||||
{
|
||||
client_send_504(client,
|
||||
"Too many clients on this mountpoint. Try again later.");
|
||||
global_unlock();
|
||||
global_unlock();
|
||||
avl_tree_unlock(global.source_tree);
|
||||
return;
|
||||
}
|
||||
global.clients++;
|
||||
global_unlock();
|
||||
|
||||
global.clients++;
|
||||
global_unlock();
|
||||
|
||||
client->format_data = source->format->create_client_data(
|
||||
source->format, source, client);
|
||||
|
||||
source->format->client_send_headers(source->format, source, client);
|
||||
|
||||
bytes = sock_write(client->con->sock, "\r\n");
|
||||
|
||||
bytes = sock_write(client->con->sock, "\r\n");
|
||||
if(bytes > 0) client->con->sent_bytes += bytes;
|
||||
|
||||
sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
|
||||
|
||||
sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
|
||||
sock_set_nodelay(client->con->sock);
|
||||
|
||||
avl_tree_wlock(source->pending_tree);
|
||||
avl_insert(source->pending_tree, (void *)client);
|
||||
avl_tree_unlock(source->pending_tree);
|
||||
}
|
||||
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
if (!source) {
|
||||
|
||||
avl_tree_wlock(source->pending_tree);
|
||||
avl_insert(source->pending_tree, (void *)client);
|
||||
avl_tree_unlock(source->pending_tree);
|
||||
}
|
||||
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
if (!source) {
|
||||
DEBUG0("Source not found for client");
|
||||
client_send_404(client, "The source you requested could not be found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *_handle_connection(void *arg)
|
||||
{
|
||||
char header[4096];
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
char header[4096];
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
char *rawuri, *uri;
|
||||
client_t *client;
|
||||
client_t *client;
|
||||
|
||||
while (global.running == ICE_RUNNING) {
|
||||
memset(header, 0, 4096);
|
||||
while (global.running == ICE_RUNNING) {
|
||||
memset(header, 0, 4096);
|
||||
|
||||
thread_cond_wait(&_pool_cond);
|
||||
if (global.running != ICE_RUNNING) break;
|
||||
thread_cond_wait(&_pool_cond);
|
||||
if (global.running != ICE_RUNNING) break;
|
||||
|
||||
/* grab a connection and set the socket to blocking */
|
||||
while ((con = _get_connection())) {
|
||||
/* grab a connection and set the socket to blocking */
|
||||
while ((con = _get_connection())) {
|
||||
|
||||
/* Handle meta-connections */
|
||||
if(con->event_number > 0) {
|
||||
@ -847,40 +847,40 @@ static void *_handle_connection(void *arg)
|
||||
continue;
|
||||
}
|
||||
|
||||
stats_event_inc(NULL, "connections");
|
||||
stats_event_inc(NULL, "connections");
|
||||
|
||||
sock_set_blocking(con->sock, SOCK_BLOCK);
|
||||
sock_set_blocking(con->sock, SOCK_BLOCK);
|
||||
|
||||
/* fill header with the http header */
|
||||
if (util_read_header(con->sock, header, 4096) == 0) {
|
||||
/* either we didn't get a complete header, or we timed out */
|
||||
connection_close(con);
|
||||
continue;
|
||||
}
|
||||
/* fill header with the http header */
|
||||
if (util_read_header(con->sock, header, 4096) == 0) {
|
||||
/* either we didn't get a complete header, or we timed out */
|
||||
connection_close(con);
|
||||
continue;
|
||||
}
|
||||
|
||||
parser = httpp_create_parser();
|
||||
httpp_initialize(parser, NULL);
|
||||
if (httpp_parse(parser, header, strlen(header))) {
|
||||
/* handle the connection or something */
|
||||
|
||||
if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) &&
|
||||
parser = httpp_create_parser();
|
||||
httpp_initialize(parser, NULL);
|
||||
if (httpp_parse(parser, header, strlen(header))) {
|
||||
/* handle the connection or something */
|
||||
|
||||
if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) &&
|
||||
strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) {
|
||||
ERROR0("Bad HTTP protocol detected");
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
continue;
|
||||
}
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
continue;
|
||||
}
|
||||
|
||||
rawuri = httpp_getvar(parser, HTTPP_VAR_URI);
|
||||
uri = util_normalise_uri(rawuri);
|
||||
|
||||
if(!uri) {
|
||||
client = client_create(con, parser);
|
||||
client = client_create(con, parser);
|
||||
client_send_404(client, "The path you requested was invalid");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parser->req_type == httpp_req_source) {
|
||||
if (parser->req_type == httpp_req_source) {
|
||||
_handle_source_request(con, parser, uri);
|
||||
}
|
||||
else if (parser->req_type == httpp_req_stats) {
|
||||
@ -891,12 +891,12 @@ static void *_handle_connection(void *arg)
|
||||
}
|
||||
else {
|
||||
ERROR0("Wrong request type from client");
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
}
|
||||
|
||||
free(uri);
|
||||
}
|
||||
}
|
||||
else if(httpp_parse_icy(parser, header, strlen(header))) {
|
||||
/* TODO: Map incoming icy connections to /icy_0, etc. */
|
||||
char mount[20];
|
||||
@ -914,22 +914,22 @@ static void *_handle_connection(void *arg)
|
||||
}
|
||||
else {
|
||||
ERROR0("HTTP request parsing failed");
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_exit(0);
|
||||
thread_exit(0);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void connection_close(connection_t *con)
|
||||
{
|
||||
sock_close(con->sock);
|
||||
if (con->ip) free(con->ip);
|
||||
if (con->host) free(con->host);
|
||||
free(con);
|
||||
sock_close(con->sock);
|
||||
if (con->ip) free(con->ip);
|
||||
if (con->host) free(con->host);
|
||||
free(con);
|
||||
}
|
||||
|
@ -11,16 +11,16 @@ struct _client_tag;
|
||||
|
||||
typedef struct connection_tag
|
||||
{
|
||||
unsigned long id;
|
||||
unsigned long id;
|
||||
|
||||
time_t con_time;
|
||||
uint64_t sent_bytes;
|
||||
time_t con_time;
|
||||
uint64_t sent_bytes;
|
||||
|
||||
int sock;
|
||||
int error;
|
||||
int sock;
|
||||
int error;
|
||||
|
||||
char *ip;
|
||||
char *host;
|
||||
char *ip;
|
||||
char *host;
|
||||
|
||||
/* For 'fake' connections */
|
||||
int event_number;
|
||||
|
@ -12,7 +12,7 @@ void event_config_read(void *arg)
|
||||
int ret;
|
||||
ice_config_t *config;
|
||||
ice_config_t new_config;
|
||||
/* reread config file */
|
||||
/* reread config file */
|
||||
|
||||
config = config_get_config(); /* Both to get the lock, and to be able
|
||||
to find out the config filename */
|
||||
|
42
src/format.c
42
src/format.c
@ -57,23 +57,23 @@ char *format_get_mimetype(format_type_t type)
|
||||
format_plugin_t *format_get_plugin(format_type_t type, char *mount,
|
||||
http_parser_t *parser)
|
||||
{
|
||||
format_plugin_t *plugin;
|
||||
format_plugin_t *plugin;
|
||||
|
||||
switch (type) {
|
||||
case FORMAT_TYPE_VORBIS:
|
||||
plugin = format_vorbis_get_plugin();
|
||||
if (plugin) plugin->mount = mount;
|
||||
break;
|
||||
switch (type) {
|
||||
case FORMAT_TYPE_VORBIS:
|
||||
plugin = format_vorbis_get_plugin();
|
||||
if (plugin) plugin->mount = mount;
|
||||
break;
|
||||
case FORMAT_TYPE_MP3:
|
||||
plugin = format_mp3_get_plugin(parser);
|
||||
if (plugin) plugin->mount = mount;
|
||||
break;
|
||||
default:
|
||||
plugin = NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
plugin = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return plugin;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
int format_generic_write_buf_to_client(format_plugin_t *format,
|
||||
@ -102,21 +102,21 @@ void format_send_general_headers(format_plugin_t *format,
|
||||
avl_node *node;
|
||||
int bytes;
|
||||
|
||||
/* iterate through source http headers and send to client */
|
||||
avl_tree_rlock(source->parser->vars);
|
||||
node = avl_get_first(source->parser->vars);
|
||||
while (node) {
|
||||
var = (http_var_t *)node->key;
|
||||
if (strcasecmp(var->name, "ice-password") &&
|
||||
/* iterate through source http headers and send to client */
|
||||
avl_tree_rlock(source->parser->vars);
|
||||
node = avl_get_first(source->parser->vars);
|
||||
while (node) {
|
||||
var = (http_var_t *)node->key;
|
||||
if (strcasecmp(var->name, "ice-password") &&
|
||||
(!strncasecmp("ice-", var->name, 4) ||
|
||||
!strncasecmp("icy-", var->name, 4))) {
|
||||
bytes = sock_write(client->con->sock,
|
||||
"%s: %s\r\n", var->name, var->value);
|
||||
if(bytes > 0) client->con->sent_bytes += bytes;
|
||||
}
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
avl_tree_unlock(source->parser->vars);
|
||||
}
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
avl_tree_unlock(source->parser->vars);
|
||||
bytes = sock_write(client->con->sock,
|
||||
"Server: %s\r\n", ICECAST_VERSION_STRING);
|
||||
if(bytes > 0) client->con->sent_bytes += bytes;
|
||||
|
26
src/format.h
26
src/format.h
@ -14,28 +14,28 @@ struct source_tag;
|
||||
|
||||
typedef enum _format_type_tag
|
||||
{
|
||||
FORMAT_TYPE_VORBIS,
|
||||
FORMAT_TYPE_MP3,
|
||||
FORMAT_TYPE_VORBIS,
|
||||
FORMAT_TYPE_MP3,
|
||||
FORMAT_ERROR /* No format, source not processable */
|
||||
} format_type_t;
|
||||
|
||||
typedef struct _format_plugin_tag
|
||||
{
|
||||
format_type_t type;
|
||||
format_type_t type;
|
||||
|
||||
/* we need to know the mount to report statistics */
|
||||
char *mount;
|
||||
/* we need to know the mount to report statistics */
|
||||
char *mount;
|
||||
|
||||
char *format_description;
|
||||
|
||||
/* set this is the data format has a header that
|
||||
** we must send before regular data
|
||||
*/
|
||||
int has_predata;
|
||||
/* set this is the data format has a header that
|
||||
** we must send before regular data
|
||||
*/
|
||||
int has_predata;
|
||||
|
||||
int (*get_buffer)(struct _format_plugin_tag *self, char *data, unsigned long
|
||||
len, refbuf_t **buffer);
|
||||
refbuf_queue_t *(*get_predata)(struct _format_plugin_tag *self);
|
||||
refbuf_queue_t *(*get_predata)(struct _format_plugin_tag *self);
|
||||
int (*write_buf_to_client)(struct _format_plugin_tag *format,
|
||||
client_t *client, unsigned char *buf, int len);
|
||||
void *(*create_client_data)(struct _format_plugin_tag *format,
|
||||
@ -43,10 +43,10 @@ typedef struct _format_plugin_tag
|
||||
void (*client_send_headers)(struct _format_plugin_tag *format,
|
||||
struct source_tag *source, client_t *client);
|
||||
|
||||
void (*free_plugin)(struct _format_plugin_tag *self);
|
||||
void (*free_plugin)(struct _format_plugin_tag *self);
|
||||
|
||||
/* for internal state management */
|
||||
void *_state;
|
||||
/* for internal state management */
|
||||
void *_state;
|
||||
} format_plugin_t;
|
||||
|
||||
format_type_t format_get_type(char *contenttype);
|
||||
|
@ -54,22 +54,22 @@ typedef struct {
|
||||
format_plugin_t *format_mp3_get_plugin(http_parser_t *parser)
|
||||
{
|
||||
char *metadata;
|
||||
format_plugin_t *plugin;
|
||||
format_plugin_t *plugin;
|
||||
mp3_state *state = calloc(1, sizeof(mp3_state));
|
||||
|
||||
plugin = (format_plugin_t *)malloc(sizeof(format_plugin_t));
|
||||
plugin = (format_plugin_t *)malloc(sizeof(format_plugin_t));
|
||||
|
||||
plugin->type = FORMAT_TYPE_MP3;
|
||||
plugin->has_predata = 0;
|
||||
plugin->get_buffer = format_mp3_get_buffer;
|
||||
plugin->get_predata = format_mp3_get_predata;
|
||||
plugin->type = FORMAT_TYPE_MP3;
|
||||
plugin->has_predata = 0;
|
||||
plugin->get_buffer = format_mp3_get_buffer;
|
||||
plugin->get_predata = format_mp3_get_predata;
|
||||
plugin->write_buf_to_client = format_mp3_write_buf_to_client;
|
||||
plugin->create_client_data = format_mp3_create_client_data;
|
||||
plugin->client_send_headers = format_mp3_send_headers;
|
||||
plugin->free_plugin = format_mp3_free_plugin;
|
||||
plugin->free_plugin = format_mp3_free_plugin;
|
||||
plugin->format_description = "MP3 audio";
|
||||
|
||||
plugin->_state = state;
|
||||
plugin->_state = state;
|
||||
|
||||
state->metadata_age = 0;
|
||||
state->metadata = strdup("");
|
||||
@ -79,7 +79,7 @@ format_plugin_t *format_mp3_get_plugin(http_parser_t *parser)
|
||||
if(metadata)
|
||||
state->inline_metadata_interval = atoi(metadata);
|
||||
|
||||
return plugin;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static int send_metadata(client_t *client, mp3_client_data *client_state,
|
||||
@ -91,8 +91,8 @@ static int send_metadata(client_t *client, mp3_client_data *client_state,
|
||||
unsigned char *buf;
|
||||
int ret;
|
||||
int source_age;
|
||||
char *fullmetadata = NULL;
|
||||
int fullmetadata_size = 0;
|
||||
char *fullmetadata = NULL;
|
||||
int fullmetadata_size = 0;
|
||||
|
||||
thread_mutex_lock(&(source_state->lock));
|
||||
if(source_state->metadata == NULL) {
|
||||
@ -198,19 +198,19 @@ static int format_mp3_write_buf_to_client(format_plugin_t *self,
|
||||
|
||||
static void format_mp3_free_plugin(format_plugin_t *self)
|
||||
{
|
||||
/* free the plugin instance */
|
||||
/* free the plugin instance */
|
||||
mp3_state *state = self->_state;
|
||||
thread_mutex_destroy(&(state->lock));
|
||||
|
||||
free(state->metadata);
|
||||
free(state);
|
||||
free(self);
|
||||
free(self);
|
||||
}
|
||||
|
||||
static int format_mp3_get_buffer(format_plugin_t *self, char *data,
|
||||
unsigned long len, refbuf_t **buffer)
|
||||
{
|
||||
refbuf_t *refbuf;
|
||||
refbuf_t *refbuf;
|
||||
mp3_state *state = self->_state;
|
||||
|
||||
/* Set this to NULL in case it doesn't get set to a valid buffer later */
|
||||
@ -319,7 +319,7 @@ static int format_mp3_get_buffer(format_plugin_t *self, char *data,
|
||||
memcpy(refbuf->data, data, len);
|
||||
|
||||
*buffer = refbuf;
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,16 +26,16 @@
|
||||
|
||||
typedef struct _vstate_tag
|
||||
{
|
||||
ogg_sync_state oy;
|
||||
ogg_stream_state os;
|
||||
vorbis_info vi;
|
||||
vorbis_comment vc;
|
||||
ogg_sync_state oy;
|
||||
ogg_stream_state os;
|
||||
vorbis_info vi;
|
||||
vorbis_comment vc;
|
||||
|
||||
ogg_page og;
|
||||
unsigned long serialno;
|
||||
int header;
|
||||
refbuf_t *headbuf[MAX_HEADER_PAGES];
|
||||
int packets;
|
||||
ogg_page og;
|
||||
unsigned long serialno;
|
||||
int header;
|
||||
refbuf_t *headbuf[MAX_HEADER_PAGES];
|
||||
int packets;
|
||||
} vstate_t;
|
||||
|
||||
static void format_vorbis_free_plugin(format_plugin_t *self);
|
||||
@ -49,179 +49,179 @@ static void format_vorbis_send_headers(format_plugin_t *self,
|
||||
|
||||
format_plugin_t *format_vorbis_get_plugin(void)
|
||||
{
|
||||
format_plugin_t *plugin;
|
||||
vstate_t *state;
|
||||
format_plugin_t *plugin;
|
||||
vstate_t *state;
|
||||
|
||||
plugin = (format_plugin_t *)malloc(sizeof(format_plugin_t));
|
||||
plugin = (format_plugin_t *)malloc(sizeof(format_plugin_t));
|
||||
|
||||
plugin->type = FORMAT_TYPE_VORBIS;
|
||||
plugin->has_predata = 1;
|
||||
plugin->get_buffer = format_vorbis_get_buffer;
|
||||
plugin->get_predata = format_vorbis_get_predata;
|
||||
plugin->type = FORMAT_TYPE_VORBIS;
|
||||
plugin->has_predata = 1;
|
||||
plugin->get_buffer = format_vorbis_get_buffer;
|
||||
plugin->get_predata = format_vorbis_get_predata;
|
||||
plugin->write_buf_to_client = format_generic_write_buf_to_client;
|
||||
plugin->create_client_data = format_vorbis_create_client_data;
|
||||
plugin->client_send_headers = format_vorbis_send_headers;
|
||||
plugin->free_plugin = format_vorbis_free_plugin;
|
||||
plugin->free_plugin = format_vorbis_free_plugin;
|
||||
plugin->format_description = "Ogg Vorbis";
|
||||
|
||||
state = (vstate_t *)calloc(1, sizeof(vstate_t));
|
||||
ogg_sync_init(&state->oy);
|
||||
state = (vstate_t *)calloc(1, sizeof(vstate_t));
|
||||
ogg_sync_init(&state->oy);
|
||||
|
||||
plugin->_state = (void *)state;
|
||||
plugin->_state = (void *)state;
|
||||
|
||||
return plugin;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void format_vorbis_free_plugin(format_plugin_t *self)
|
||||
{
|
||||
int i;
|
||||
vstate_t *state = (vstate_t *)self->_state;
|
||||
int i;
|
||||
vstate_t *state = (vstate_t *)self->_state;
|
||||
|
||||
/* free memory associated with this plugin instance */
|
||||
/* free memory associated with this plugin instance */
|
||||
|
||||
/* free state memory */
|
||||
ogg_sync_clear(&state->oy);
|
||||
ogg_stream_clear(&state->os);
|
||||
vorbis_comment_clear(&state->vc);
|
||||
vorbis_info_clear(&state->vi);
|
||||
|
||||
for (i = 0; i < MAX_HEADER_PAGES; i++) {
|
||||
if (state->headbuf[i]) {
|
||||
refbuf_release(state->headbuf[i]);
|
||||
state->headbuf[i] = NULL;
|
||||
}
|
||||
}
|
||||
/* free state memory */
|
||||
ogg_sync_clear(&state->oy);
|
||||
ogg_stream_clear(&state->os);
|
||||
vorbis_comment_clear(&state->vc);
|
||||
vorbis_info_clear(&state->vi);
|
||||
|
||||
for (i = 0; i < MAX_HEADER_PAGES; i++) {
|
||||
if (state->headbuf[i]) {
|
||||
refbuf_release(state->headbuf[i]);
|
||||
state->headbuf[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(state);
|
||||
free(state);
|
||||
|
||||
/* free the plugin instance */
|
||||
free(self);
|
||||
/* free the plugin instance */
|
||||
free(self);
|
||||
}
|
||||
|
||||
int format_vorbis_get_buffer(format_plugin_t *self, char *data, unsigned long len, refbuf_t **buffer)
|
||||
{
|
||||
char *buf;
|
||||
int i, result;
|
||||
ogg_packet op;
|
||||
char *tag;
|
||||
char *buf;
|
||||
int i, result;
|
||||
ogg_packet op;
|
||||
char *tag;
|
||||
refbuf_t *refbuf;
|
||||
vstate_t *state = (vstate_t *)self->_state;
|
||||
vstate_t *state = (vstate_t *)self->_state;
|
||||
|
||||
if (data) {
|
||||
/* write the data to the buffer */
|
||||
buf = ogg_sync_buffer(&state->oy, len);
|
||||
if (data) {
|
||||
/* write the data to the buffer */
|
||||
buf = ogg_sync_buffer(&state->oy, len);
|
||||
memcpy(buf, data, len);
|
||||
ogg_sync_wrote(&state->oy, len);
|
||||
}
|
||||
ogg_sync_wrote(&state->oy, len);
|
||||
}
|
||||
|
||||
refbuf = NULL;
|
||||
if (ogg_sync_pageout(&state->oy, &state->og) == 1) {
|
||||
refbuf = refbuf_new(state->og.header_len + state->og.body_len);
|
||||
memcpy(refbuf->data, state->og.header, state->og.header_len);
|
||||
memcpy(&refbuf->data[state->og.header_len], state->og.body, state->og.body_len);
|
||||
refbuf = NULL;
|
||||
if (ogg_sync_pageout(&state->oy, &state->og) == 1) {
|
||||
refbuf = refbuf_new(state->og.header_len + state->og.body_len);
|
||||
memcpy(refbuf->data, state->og.header, state->og.header_len);
|
||||
memcpy(&refbuf->data[state->og.header_len], state->og.body, state->og.body_len);
|
||||
|
||||
if (state->serialno != ogg_page_serialno(&state->og)) {
|
||||
/* this is a new logical bitstream */
|
||||
state->header = 0;
|
||||
state->packets = 0;
|
||||
if (state->serialno != ogg_page_serialno(&state->og)) {
|
||||
/* this is a new logical bitstream */
|
||||
state->header = 0;
|
||||
state->packets = 0;
|
||||
|
||||
/* release old headers, stream state, vorbis data */
|
||||
for (i = 0; i < MAX_HEADER_PAGES; i++) {
|
||||
if (state->headbuf[i]) {
|
||||
refbuf_release(state->headbuf[i]);
|
||||
state->headbuf[i] = NULL;
|
||||
}
|
||||
}
|
||||
/* release old headers, stream state, vorbis data */
|
||||
for (i = 0; i < MAX_HEADER_PAGES; i++) {
|
||||
if (state->headbuf[i]) {
|
||||
refbuf_release(state->headbuf[i]);
|
||||
state->headbuf[i] = NULL;
|
||||
}
|
||||
}
|
||||
/* Clear old stuff. Rarely but occasionally needed. */
|
||||
ogg_stream_clear(&state->os);
|
||||
vorbis_comment_clear(&state->vc);
|
||||
vorbis_info_clear(&state->vi);
|
||||
ogg_stream_clear(&state->os);
|
||||
vorbis_comment_clear(&state->vc);
|
||||
vorbis_info_clear(&state->vi);
|
||||
|
||||
state->serialno = ogg_page_serialno(&state->og);
|
||||
ogg_stream_init(&state->os, state->serialno);
|
||||
vorbis_info_init(&state->vi);
|
||||
vorbis_comment_init(&state->vc);
|
||||
}
|
||||
state->serialno = ogg_page_serialno(&state->og);
|
||||
ogg_stream_init(&state->os, state->serialno);
|
||||
vorbis_info_init(&state->vi);
|
||||
vorbis_comment_init(&state->vc);
|
||||
}
|
||||
|
||||
if (state->header >= 0) {
|
||||
if (state->header >= 0) {
|
||||
/* FIXME: In some streams (non-vorbis ogg streams), this could get
|
||||
* extras pages beyond the header. We need to collect the pages
|
||||
* here anyway, but they may have to be discarded later.
|
||||
*/
|
||||
if (ogg_page_granulepos(&state->og) <= 0) {
|
||||
state->header++;
|
||||
} else {
|
||||
/* we're done caching headers */
|
||||
state->header = -1;
|
||||
if (ogg_page_granulepos(&state->og) <= 0) {
|
||||
state->header++;
|
||||
} else {
|
||||
/* we're done caching headers */
|
||||
state->header = -1;
|
||||
|
||||
/* put known comments in the stats */
|
||||
tag = vorbis_comment_query(&state->vc, "TITLE", 0);
|
||||
if (tag) stats_event(self->mount, "title", tag);
|
||||
else stats_event(self->mount, "title", "unknown");
|
||||
tag = vorbis_comment_query(&state->vc, "ARTIST", 0);
|
||||
if (tag) stats_event(self->mount, "artist", tag);
|
||||
else stats_event(self->mount, "artist", "unknown");
|
||||
/* put known comments in the stats */
|
||||
tag = vorbis_comment_query(&state->vc, "TITLE", 0);
|
||||
if (tag) stats_event(self->mount, "title", tag);
|
||||
else stats_event(self->mount, "title", "unknown");
|
||||
tag = vorbis_comment_query(&state->vc, "ARTIST", 0);
|
||||
if (tag) stats_event(self->mount, "artist", tag);
|
||||
else stats_event(self->mount, "artist", "unknown");
|
||||
|
||||
/* don't need these now */
|
||||
ogg_stream_clear(&state->os);
|
||||
vorbis_comment_clear(&state->vc);
|
||||
vorbis_info_clear(&state->vi);
|
||||
}
|
||||
}
|
||||
/* don't need these now */
|
||||
ogg_stream_clear(&state->os);
|
||||
vorbis_comment_clear(&state->vc);
|
||||
vorbis_info_clear(&state->vi);
|
||||
}
|
||||
}
|
||||
|
||||
/* cache header pages */
|
||||
if (state->header > 0 && state->packets < 3) {
|
||||
/* cache header pages */
|
||||
if (state->header > 0 && state->packets < 3) {
|
||||
if(state->header > MAX_HEADER_PAGES) {
|
||||
refbuf_release(refbuf);
|
||||
ERROR1("Bad vorbis input: header is more than %d pages long", MAX_HEADER_PAGES);
|
||||
|
||||
return -1;
|
||||
}
|
||||
refbuf_addref(refbuf);
|
||||
state->headbuf[state->header - 1] = refbuf;
|
||||
refbuf_addref(refbuf);
|
||||
state->headbuf[state->header - 1] = refbuf;
|
||||
|
||||
if (state->packets >= 0 && state->packets < 3) {
|
||||
ogg_stream_pagein(&state->os, &state->og);
|
||||
while (state->packets < 3) {
|
||||
result = ogg_stream_packetout(&state->os, &op);
|
||||
if (result == 0) break; /* need more data */
|
||||
if (result < 0) {
|
||||
state->packets = -1;
|
||||
break;
|
||||
}
|
||||
if (state->packets >= 0 && state->packets < 3) {
|
||||
ogg_stream_pagein(&state->os, &state->og);
|
||||
while (state->packets < 3) {
|
||||
result = ogg_stream_packetout(&state->os, &op);
|
||||
if (result == 0) break; /* need more data */
|
||||
if (result < 0) {
|
||||
state->packets = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
state->packets++;
|
||||
state->packets++;
|
||||
|
||||
if (vorbis_synthesis_headerin(&state->vi, &state->vc, &op) < 0) {
|
||||
state->packets = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vorbis_synthesis_headerin(&state->vi, &state->vc, &op) < 0) {
|
||||
state->packets = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*buffer = refbuf;
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
refbuf_queue_t *format_vorbis_get_predata(format_plugin_t *self)
|
||||
{
|
||||
refbuf_queue_t *queue;
|
||||
int i;
|
||||
vstate_t *state = (vstate_t *)self->_state;
|
||||
refbuf_queue_t *queue;
|
||||
int i;
|
||||
vstate_t *state = (vstate_t *)self->_state;
|
||||
|
||||
queue = NULL;
|
||||
for (i = 0; i < MAX_HEADER_PAGES; i++) {
|
||||
if (state->headbuf[i]) {
|
||||
refbuf_addref(state->headbuf[i]);
|
||||
refbuf_queue_add(&queue, state->headbuf[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
queue = NULL;
|
||||
for (i = 0; i < MAX_HEADER_PAGES; i++) {
|
||||
if (state->headbuf[i]) {
|
||||
refbuf_addref(state->headbuf[i]);
|
||||
refbuf_queue_add(&queue, state->headbuf[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return queue;
|
||||
return queue;
|
||||
}
|
||||
|
||||
static void *format_vorbis_create_client_data(format_plugin_t *self,
|
||||
|
22
src/fserve.c
22
src/fserve.c
@ -88,8 +88,8 @@ void fserve_initialize(void)
|
||||
|
||||
create_mime_mappings(MIMETYPESFILE);
|
||||
|
||||
client_tree = avl_tree_new(_compare_clients, NULL);
|
||||
pending_tree = avl_tree_new(_compare_clients, NULL);
|
||||
client_tree = avl_tree_new(_compare_clients, NULL);
|
||||
pending_tree = avl_tree_new(_compare_clients, NULL);
|
||||
thread_cond_create(&fserv_cond);
|
||||
|
||||
run_fserv = 1;
|
||||
@ -408,32 +408,32 @@ int fserve_client_create(client_t *httpclient, char *path)
|
||||
|
||||
static int _compare_clients(void *compare_arg, void *a, void *b)
|
||||
{
|
||||
connection_t *cona = (connection_t *)a;
|
||||
connection_t *cona = (connection_t *)a;
|
||||
connection_t *conb = (connection_t *)b;
|
||||
|
||||
if (cona->id < conb->id) return -1;
|
||||
if (cona->id > conb->id) return 1;
|
||||
if (cona->id < conb->id) return -1;
|
||||
if (cona->id > conb->id) return 1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _remove_client(void *key)
|
||||
{
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _free_client(void *key)
|
||||
{
|
||||
fserve_t *client = (fserve_t *)key;
|
||||
fserve_t *client = (fserve_t *)key;
|
||||
|
||||
fserve_client_destroy(client);
|
||||
fserve_client_destroy(client);
|
||||
global_lock();
|
||||
global.clients--;
|
||||
global_unlock();
|
||||
stats_event_dec(NULL, "clients");
|
||||
|
||||
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _delete_mapping(void *mapping) {
|
||||
|
20
src/global.c
20
src/global.c
@ -20,26 +20,26 @@ static mutex_t _global_mutex;
|
||||
void global_initialize(void)
|
||||
{
|
||||
memset(global.serversock, 0, sizeof(int)*MAX_LISTEN_SOCKETS);
|
||||
global.server_sockets = 0;
|
||||
global.running = 0;
|
||||
global.clients = 0;
|
||||
global.sources = 0;
|
||||
global.source_tree = avl_tree_new(source_compare_sources, NULL);
|
||||
thread_mutex_create(&_global_mutex);
|
||||
global.server_sockets = 0;
|
||||
global.running = 0;
|
||||
global.clients = 0;
|
||||
global.sources = 0;
|
||||
global.source_tree = avl_tree_new(source_compare_sources, NULL);
|
||||
thread_mutex_create(&_global_mutex);
|
||||
}
|
||||
|
||||
void global_shutdown(void)
|
||||
{
|
||||
thread_mutex_destroy(&_global_mutex);
|
||||
avl_tree_free(global.source_tree, source_free_source);
|
||||
thread_mutex_destroy(&_global_mutex);
|
||||
avl_tree_free(global.source_tree, source_free_source);
|
||||
}
|
||||
|
||||
void global_lock(void)
|
||||
{
|
||||
thread_mutex_lock(&_global_mutex);
|
||||
thread_mutex_lock(&_global_mutex);
|
||||
}
|
||||
|
||||
void global_unlock(void)
|
||||
{
|
||||
thread_mutex_unlock(&_global_mutex);
|
||||
thread_mutex_unlock(&_global_mutex);
|
||||
}
|
||||
|
10
src/global.h
10
src/global.h
@ -14,15 +14,15 @@
|
||||
|
||||
typedef struct ice_global_tag
|
||||
{
|
||||
int serversock[MAX_LISTEN_SOCKETS];
|
||||
int serversock[MAX_LISTEN_SOCKETS];
|
||||
int server_sockets;
|
||||
|
||||
int running;
|
||||
int running;
|
||||
|
||||
int sources;
|
||||
int clients;
|
||||
int sources;
|
||||
int clients;
|
||||
|
||||
avl_tree *source_tree;
|
||||
avl_tree *source_tree;
|
||||
|
||||
cond_t shutdown_cond;
|
||||
} ice_global_t;
|
||||
|
@ -33,50 +33,50 @@ int _free_vars(void *key);
|
||||
|
||||
http_parser_t *httpp_create_parser(void)
|
||||
{
|
||||
return (http_parser_t *)malloc(sizeof(http_parser_t));
|
||||
return (http_parser_t *)malloc(sizeof(http_parser_t));
|
||||
}
|
||||
|
||||
void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
|
||||
{
|
||||
http_varlist_t *list;
|
||||
http_varlist_t *list;
|
||||
|
||||
parser->req_type = httpp_req_none;
|
||||
parser->uri = NULL;
|
||||
parser->vars = avl_tree_new(_compare_vars, NULL);
|
||||
parser->queryvars = avl_tree_new(_compare_vars, NULL);
|
||||
parser->req_type = httpp_req_none;
|
||||
parser->uri = NULL;
|
||||
parser->vars = avl_tree_new(_compare_vars, NULL);
|
||||
parser->queryvars = avl_tree_new(_compare_vars, NULL);
|
||||
|
||||
/* now insert the default variables */
|
||||
list = defaults;
|
||||
while (list != NULL) {
|
||||
httpp_setvar(parser, list->var.name, list->var.value);
|
||||
list = list->next;
|
||||
}
|
||||
/* now insert the default variables */
|
||||
list = defaults;
|
||||
while (list != NULL) {
|
||||
httpp_setvar(parser, list->var.name, list->var.value);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int split_headers(char *data, unsigned long len, char **line)
|
||||
{
|
||||
/* first we count how many lines there are
|
||||
** and set up the line[] array
|
||||
*/
|
||||
int lines = 0;
|
||||
/* first we count how many lines there are
|
||||
** and set up the line[] array
|
||||
*/
|
||||
int lines = 0;
|
||||
unsigned long i;
|
||||
line[lines] = data;
|
||||
for (i = 0; i < len && lines < MAX_HEADERS; i++) {
|
||||
if (data[i] == '\r')
|
||||
data[i] = '\0';
|
||||
if (data[i] == '\n') {
|
||||
lines++;
|
||||
data[i] = '\0';
|
||||
if (i + 1 < len) {
|
||||
if (data[i + 1] == '\n' || data[i + 1] == '\r')
|
||||
break;
|
||||
line[lines] = &data[i + 1];
|
||||
line[lines] = data;
|
||||
for (i = 0; i < len && lines < MAX_HEADERS; i++) {
|
||||
if (data[i] == '\r')
|
||||
data[i] = '\0';
|
||||
if (data[i] == '\n') {
|
||||
lines++;
|
||||
data[i] = '\0';
|
||||
if (i + 1 < len) {
|
||||
if (data[i + 1] == '\n' || data[i + 1] == '\r')
|
||||
break;
|
||||
line[lines] = &data[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
while (data[i] == '\n') i++;
|
||||
i++;
|
||||
while (data[i] == '\n') i++;
|
||||
|
||||
return lines;
|
||||
}
|
||||
@ -84,194 +84,194 @@ static int split_headers(char *data, unsigned long len, char **line)
|
||||
static void parse_headers(http_parser_t *parser, char **line, int lines)
|
||||
{
|
||||
int i,l;
|
||||
int whitespace, where, slen;
|
||||
char *name = NULL;
|
||||
char *value = NULL;
|
||||
int whitespace, where, slen;
|
||||
char *name = NULL;
|
||||
char *value = NULL;
|
||||
|
||||
/* parse the name: value lines. */
|
||||
for (l = 1; l < lines; l++) {
|
||||
where = 0;
|
||||
whitespace = 0;
|
||||
name = line[l];
|
||||
value = NULL;
|
||||
slen = strlen(line[l]);
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (line[l][i] == ':') {
|
||||
whitespace = 1;
|
||||
line[l][i] = '\0';
|
||||
} else {
|
||||
if (whitespace) {
|
||||
whitespace = 0;
|
||||
while (i < slen && line[l][i] == ' ')
|
||||
i++;
|
||||
/* parse the name: value lines. */
|
||||
for (l = 1; l < lines; l++) {
|
||||
where = 0;
|
||||
whitespace = 0;
|
||||
name = line[l];
|
||||
value = NULL;
|
||||
slen = strlen(line[l]);
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (line[l][i] == ':') {
|
||||
whitespace = 1;
|
||||
line[l][i] = '\0';
|
||||
} else {
|
||||
if (whitespace) {
|
||||
whitespace = 0;
|
||||
while (i < slen && line[l][i] == ' ')
|
||||
i++;
|
||||
|
||||
if (i < slen)
|
||||
value = &line[l][i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name != NULL && value != NULL) {
|
||||
httpp_setvar(parser, _lowercase(name), value);
|
||||
name = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
if (i < slen)
|
||||
value = &line[l][i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name != NULL && value != NULL) {
|
||||
httpp_setvar(parser, _lowercase(name), value);
|
||||
name = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri)
|
||||
{
|
||||
char *data;
|
||||
char *line[MAX_HEADERS];
|
||||
int lines, slen,i, whitespace=0, where=0,code;
|
||||
char *version=NULL, *resp_code=NULL, *message=NULL;
|
||||
char *data;
|
||||
char *line[MAX_HEADERS];
|
||||
int lines, slen,i, whitespace=0, where=0,code;
|
||||
char *version=NULL, *resp_code=NULL, *message=NULL;
|
||||
|
||||
if(http_data == NULL)
|
||||
return 0;
|
||||
if(http_data == NULL)
|
||||
return 0;
|
||||
|
||||
/* make a local copy of the data, including 0 terminator */
|
||||
data = (char *)malloc(len+1);
|
||||
if (data == NULL) return 0;
|
||||
memcpy(data, http_data, len);
|
||||
data[len] = 0;
|
||||
/* make a local copy of the data, including 0 terminator */
|
||||
data = (char *)malloc(len+1);
|
||||
if (data == NULL) return 0;
|
||||
memcpy(data, http_data, len);
|
||||
data[len] = 0;
|
||||
|
||||
lines = split_headers(data, len, line);
|
||||
lines = split_headers(data, len, line);
|
||||
|
||||
/* In this case, the first line contains:
|
||||
* VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
|
||||
*/
|
||||
slen = strlen(line[0]);
|
||||
version = line[0];
|
||||
for(i=0; i < slen; i++) {
|
||||
if(line[0][i] == ' ') {
|
||||
line[0][i] = 0;
|
||||
whitespace = 1;
|
||||
} else if(whitespace) {
|
||||
whitespace = 0;
|
||||
where++;
|
||||
if(where == 1)
|
||||
resp_code = &line[0][i];
|
||||
else {
|
||||
message = &line[0][i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* In this case, the first line contains:
|
||||
* VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK
|
||||
*/
|
||||
slen = strlen(line[0]);
|
||||
version = line[0];
|
||||
for(i=0; i < slen; i++) {
|
||||
if(line[0][i] == ' ') {
|
||||
line[0][i] = 0;
|
||||
whitespace = 1;
|
||||
} else if(whitespace) {
|
||||
whitespace = 0;
|
||||
where++;
|
||||
if(where == 1)
|
||||
resp_code = &line[0][i];
|
||||
else {
|
||||
message = &line[0][i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(version == NULL || resp_code == NULL || message == NULL) {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
if(version == NULL || resp_code == NULL || message == NULL) {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
|
||||
code = atoi(resp_code);
|
||||
if(code < 200 || code >= 300) {
|
||||
httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
|
||||
}
|
||||
httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code);
|
||||
code = atoi(resp_code);
|
||||
if(code < 200 || code >= 300) {
|
||||
httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message);
|
||||
}
|
||||
|
||||
httpp_setvar(parser, HTTPP_VAR_URI, uri);
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
|
||||
httpp_setvar(parser, HTTPP_VAR_URI, uri);
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE");
|
||||
|
||||
parse_headers(parser, line, lines);
|
||||
parse_headers(parser, line, lines);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hex(char c)
|
||||
{
|
||||
if(c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if(c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if(c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
if(c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if(c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if(c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *url_escape(char *src)
|
||||
{
|
||||
int len = strlen(src);
|
||||
unsigned char *decoded;
|
||||
int i;
|
||||
char *dst;
|
||||
int done = 0;
|
||||
int len = strlen(src);
|
||||
unsigned char *decoded;
|
||||
int i;
|
||||
char *dst;
|
||||
int done = 0;
|
||||
|
||||
decoded = calloc(1, len + 1);
|
||||
decoded = calloc(1, len + 1);
|
||||
|
||||
dst = decoded;
|
||||
dst = decoded;
|
||||
|
||||
for(i=0; i < len; i++) {
|
||||
switch(src[i]) {
|
||||
case '%':
|
||||
if(i+2 >= len) {
|
||||
free(decoded);
|
||||
return NULL;
|
||||
}
|
||||
if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
|
||||
free(decoded);
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i < len; i++) {
|
||||
switch(src[i]) {
|
||||
case '%':
|
||||
if(i+2 >= len) {
|
||||
free(decoded);
|
||||
return NULL;
|
||||
}
|
||||
if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
|
||||
free(decoded);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*dst++ = hex(src[i+1]) * 16 + hex(src[i+2]);
|
||||
i+= 2;
|
||||
break;
|
||||
case '#':
|
||||
done = 1;
|
||||
break;
|
||||
case 0:
|
||||
free(decoded);
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
*dst++ = src[i];
|
||||
break;
|
||||
}
|
||||
if(done)
|
||||
break;
|
||||
}
|
||||
*dst++ = hex(src[i+1]) * 16 + hex(src[i+2]);
|
||||
i+= 2;
|
||||
break;
|
||||
case '#':
|
||||
done = 1;
|
||||
break;
|
||||
case 0:
|
||||
free(decoded);
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
*dst++ = src[i];
|
||||
break;
|
||||
}
|
||||
if(done)
|
||||
break;
|
||||
}
|
||||
|
||||
*dst = 0; /* null terminator */
|
||||
*dst = 0; /* null terminator */
|
||||
|
||||
return decoded;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
/** TODO: This is almost certainly buggy in some cases */
|
||||
static void parse_query(http_parser_t *parser, char *query)
|
||||
{
|
||||
int len;
|
||||
int i=0;
|
||||
char *key = query;
|
||||
char *val=NULL;
|
||||
int len;
|
||||
int i=0;
|
||||
char *key = query;
|
||||
char *val=NULL;
|
||||
|
||||
if(!query || !*query)
|
||||
return;
|
||||
if(!query || !*query)
|
||||
return;
|
||||
|
||||
len = strlen(query);
|
||||
len = strlen(query);
|
||||
|
||||
while(i<len) {
|
||||
switch(query[i]) {
|
||||
case '&':
|
||||
query[i] = 0;
|
||||
if(val && key)
|
||||
httpp_set_query_param(parser, key, val);
|
||||
key = query+i+1;
|
||||
break;
|
||||
case '=':
|
||||
query[i] = 0;
|
||||
val = query+i+1;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
while(i<len) {
|
||||
switch(query[i]) {
|
||||
case '&':
|
||||
query[i] = 0;
|
||||
if(val && key)
|
||||
httpp_set_query_param(parser, key, val);
|
||||
key = query+i+1;
|
||||
break;
|
||||
case '=':
|
||||
query[i] = 0;
|
||||
val = query+i+1;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if(val && key) {
|
||||
httpp_set_query_param(parser, key, val);
|
||||
}
|
||||
if(val && key) {
|
||||
httpp_set_query_param(parser, key, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* The old shoutcast procotol. Don't look at this, it's really nasty */
|
||||
@ -288,7 +288,7 @@ int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len)
|
||||
memcpy(data, http_data, len);
|
||||
data[len] = 0;
|
||||
|
||||
lines = split_headers(data, len, line);
|
||||
lines = split_headers(data, len, line);
|
||||
|
||||
/* Now, this protocol looks like:
|
||||
* sourcepassword\n
|
||||
@ -313,261 +313,261 @@ int httpp_parse_icy(http_parser_t *parser, char *http_data, unsigned long len)
|
||||
|
||||
int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len)
|
||||
{
|
||||
char *data, *tmp;
|
||||
char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
|
||||
int i;
|
||||
int lines;
|
||||
char *req_type = NULL;
|
||||
char *uri = NULL;
|
||||
char *version = NULL;
|
||||
int whitespace, where, slen;
|
||||
char *data, *tmp;
|
||||
char *line[MAX_HEADERS]; /* limited to 32 lines, should be more than enough */
|
||||
int i;
|
||||
int lines;
|
||||
char *req_type = NULL;
|
||||
char *uri = NULL;
|
||||
char *version = NULL;
|
||||
int whitespace, where, slen;
|
||||
|
||||
if (http_data == NULL)
|
||||
return 0;
|
||||
if (http_data == NULL)
|
||||
return 0;
|
||||
|
||||
/* make a local copy of the data, including 0 terminator */
|
||||
data = (char *)malloc(len+1);
|
||||
if (data == NULL) return 0;
|
||||
memcpy(data, http_data, len);
|
||||
data[len] = 0;
|
||||
/* make a local copy of the data, including 0 terminator */
|
||||
data = (char *)malloc(len+1);
|
||||
if (data == NULL) return 0;
|
||||
memcpy(data, http_data, len);
|
||||
data[len] = 0;
|
||||
|
||||
lines = split_headers(data, len, line);
|
||||
lines = split_headers(data, len, line);
|
||||
|
||||
/* parse the first line special
|
||||
** the format is:
|
||||
** REQ_TYPE URI VERSION
|
||||
** eg:
|
||||
** GET /index.html HTTP/1.0
|
||||
*/
|
||||
where = 0;
|
||||
whitespace = 0;
|
||||
slen = strlen(line[0]);
|
||||
req_type = line[0];
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (line[0][i] == ' ') {
|
||||
whitespace = 1;
|
||||
line[0][i] = '\0';
|
||||
} else {
|
||||
/* we're just past the whitespace boundry */
|
||||
if (whitespace) {
|
||||
whitespace = 0;
|
||||
where++;
|
||||
switch (where) {
|
||||
case 1:
|
||||
uri = &line[0][i];
|
||||
break;
|
||||
case 2:
|
||||
version = &line[0][i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* parse the first line special
|
||||
** the format is:
|
||||
** REQ_TYPE URI VERSION
|
||||
** eg:
|
||||
** GET /index.html HTTP/1.0
|
||||
*/
|
||||
where = 0;
|
||||
whitespace = 0;
|
||||
slen = strlen(line[0]);
|
||||
req_type = line[0];
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (line[0][i] == ' ') {
|
||||
whitespace = 1;
|
||||
line[0][i] = '\0';
|
||||
} else {
|
||||
/* we're just past the whitespace boundry */
|
||||
if (whitespace) {
|
||||
whitespace = 0;
|
||||
where++;
|
||||
switch (where) {
|
||||
case 1:
|
||||
uri = &line[0][i];
|
||||
break;
|
||||
case 2:
|
||||
version = &line[0][i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp("GET", req_type) == 0) {
|
||||
parser->req_type = httpp_req_get;
|
||||
} else if (strcasecmp("POST", req_type) == 0) {
|
||||
parser->req_type = httpp_req_post;
|
||||
} else if (strcasecmp("HEAD", req_type) == 0) {
|
||||
parser->req_type = httpp_req_head;
|
||||
} else if (strcasecmp("SOURCE", req_type) == 0) {
|
||||
parser->req_type = httpp_req_source;
|
||||
} else if (strcasecmp("PLAY", req_type) == 0) {
|
||||
parser->req_type = httpp_req_play;
|
||||
} else if (strcasecmp("STATS", req_type) == 0) {
|
||||
parser->req_type = httpp_req_stats;
|
||||
} else {
|
||||
parser->req_type = httpp_req_unknown;
|
||||
}
|
||||
if (strcasecmp("GET", req_type) == 0) {
|
||||
parser->req_type = httpp_req_get;
|
||||
} else if (strcasecmp("POST", req_type) == 0) {
|
||||
parser->req_type = httpp_req_post;
|
||||
} else if (strcasecmp("HEAD", req_type) == 0) {
|
||||
parser->req_type = httpp_req_head;
|
||||
} else if (strcasecmp("SOURCE", req_type) == 0) {
|
||||
parser->req_type = httpp_req_source;
|
||||
} else if (strcasecmp("PLAY", req_type) == 0) {
|
||||
parser->req_type = httpp_req_play;
|
||||
} else if (strcasecmp("STATS", req_type) == 0) {
|
||||
parser->req_type = httpp_req_stats;
|
||||
} else {
|
||||
parser->req_type = httpp_req_unknown;
|
||||
}
|
||||
|
||||
if (uri != NULL && strlen(uri) > 0) {
|
||||
char *query;
|
||||
if((query = strchr(uri, '?')) != NULL) {
|
||||
*query = 0;
|
||||
query++;
|
||||
parse_query(parser, query);
|
||||
}
|
||||
if (uri != NULL && strlen(uri) > 0) {
|
||||
char *query;
|
||||
if((query = strchr(uri, '?')) != NULL) {
|
||||
*query = 0;
|
||||
query++;
|
||||
parse_query(parser, query);
|
||||
}
|
||||
|
||||
parser->uri = strdup(uri);
|
||||
} else {
|
||||
parser->uri = strdup(uri);
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
|
||||
tmp[0] = '\0';
|
||||
if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
|
||||
httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
|
||||
httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) {
|
||||
tmp[0] = '\0';
|
||||
if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) {
|
||||
httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version);
|
||||
httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]);
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
|
||||
switch (parser->req_type) {
|
||||
case httpp_req_get:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
|
||||
break;
|
||||
case httpp_req_post:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
|
||||
break;
|
||||
case httpp_req_head:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
|
||||
break;
|
||||
case httpp_req_source:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
|
||||
break;
|
||||
case httpp_req_play:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
|
||||
break;
|
||||
case httpp_req_stats:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) {
|
||||
switch (parser->req_type) {
|
||||
case httpp_req_get:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET");
|
||||
break;
|
||||
case httpp_req_post:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST");
|
||||
break;
|
||||
case httpp_req_head:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD");
|
||||
break;
|
||||
case httpp_req_source:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE");
|
||||
break;
|
||||
case httpp_req_play:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY");
|
||||
break;
|
||||
case httpp_req_stats:
|
||||
httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parser->uri != NULL) {
|
||||
httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
if (parser->uri != NULL) {
|
||||
httpp_setvar(parser, HTTPP_VAR_URI, parser->uri);
|
||||
} else {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
parse_headers(parser, line, lines);
|
||||
parse_headers(parser, line, lines);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void httpp_setvar(http_parser_t *parser, char *name, char *value)
|
||||
{
|
||||
http_var_t *var;
|
||||
http_var_t *var;
|
||||
|
||||
if (name == NULL || value == NULL)
|
||||
return;
|
||||
if (name == NULL || value == NULL)
|
||||
return;
|
||||
|
||||
var = (http_var_t *)malloc(sizeof(http_var_t));
|
||||
if (var == NULL) return;
|
||||
var = (http_var_t *)malloc(sizeof(http_var_t));
|
||||
if (var == NULL) return;
|
||||
|
||||
var->name = strdup(name);
|
||||
var->value = strdup(value);
|
||||
var->name = strdup(name);
|
||||
var->value = strdup(value);
|
||||
|
||||
if (httpp_getvar(parser, name) == NULL) {
|
||||
avl_insert(parser->vars, (void *)var);
|
||||
} else {
|
||||
avl_delete(parser->vars, (void *)var, _free_vars);
|
||||
avl_insert(parser->vars, (void *)var);
|
||||
}
|
||||
if (httpp_getvar(parser, name) == NULL) {
|
||||
avl_insert(parser->vars, (void *)var);
|
||||
} else {
|
||||
avl_delete(parser->vars, (void *)var, _free_vars);
|
||||
avl_insert(parser->vars, (void *)var);
|
||||
}
|
||||
}
|
||||
|
||||
char *httpp_getvar(http_parser_t *parser, char *name)
|
||||
{
|
||||
http_var_t var;
|
||||
http_var_t *found;
|
||||
http_var_t var;
|
||||
http_var_t *found;
|
||||
|
||||
var.name = name;
|
||||
var.value = NULL;
|
||||
var.name = name;
|
||||
var.value = NULL;
|
||||
|
||||
if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
|
||||
return found->value;
|
||||
else
|
||||
return NULL;
|
||||
if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
|
||||
return found->value;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void httpp_set_query_param(http_parser_t *parser, char *name, char *value)
|
||||
{
|
||||
http_var_t *var;
|
||||
http_var_t *var;
|
||||
|
||||
if (name == NULL || value == NULL)
|
||||
return;
|
||||
if (name == NULL || value == NULL)
|
||||
return;
|
||||
|
||||
var = (http_var_t *)malloc(sizeof(http_var_t));
|
||||
if (var == NULL) return;
|
||||
var = (http_var_t *)malloc(sizeof(http_var_t));
|
||||
if (var == NULL) return;
|
||||
|
||||
var->name = strdup(name);
|
||||
var->value = url_escape(value);
|
||||
var->name = strdup(name);
|
||||
var->value = url_escape(value);
|
||||
|
||||
if (httpp_get_query_param(parser, name) == NULL) {
|
||||
avl_insert(parser->queryvars, (void *)var);
|
||||
} else {
|
||||
avl_delete(parser->queryvars, (void *)var, _free_vars);
|
||||
avl_insert(parser->queryvars, (void *)var);
|
||||
}
|
||||
if (httpp_get_query_param(parser, name) == NULL) {
|
||||
avl_insert(parser->queryvars, (void *)var);
|
||||
} else {
|
||||
avl_delete(parser->queryvars, (void *)var, _free_vars);
|
||||
avl_insert(parser->queryvars, (void *)var);
|
||||
}
|
||||
}
|
||||
|
||||
char *httpp_get_query_param(http_parser_t *parser, char *name)
|
||||
{
|
||||
http_var_t var;
|
||||
http_var_t *found;
|
||||
http_var_t var;
|
||||
http_var_t *found;
|
||||
|
||||
var.name = name;
|
||||
var.value = NULL;
|
||||
var.name = name;
|
||||
var.value = NULL;
|
||||
|
||||
if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
|
||||
return found->value;
|
||||
else
|
||||
return NULL;
|
||||
if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
|
||||
return found->value;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void httpp_clear(http_parser_t *parser)
|
||||
{
|
||||
parser->req_type = httpp_req_none;
|
||||
if (parser->uri)
|
||||
free(parser->uri);
|
||||
parser->uri = NULL;
|
||||
avl_tree_free(parser->vars, _free_vars);
|
||||
avl_tree_free(parser->queryvars, _free_vars);
|
||||
parser->vars = NULL;
|
||||
parser->req_type = httpp_req_none;
|
||||
if (parser->uri)
|
||||
free(parser->uri);
|
||||
parser->uri = NULL;
|
||||
avl_tree_free(parser->vars, _free_vars);
|
||||
avl_tree_free(parser->queryvars, _free_vars);
|
||||
parser->vars = NULL;
|
||||
}
|
||||
|
||||
void httpp_destroy(http_parser_t *parser)
|
||||
{
|
||||
httpp_clear(parser);
|
||||
free(parser);
|
||||
httpp_clear(parser);
|
||||
free(parser);
|
||||
}
|
||||
|
||||
char *_lowercase(char *str)
|
||||
{
|
||||
long i;
|
||||
for (i = 0; i < strlen(str); i++)
|
||||
str[i] = tolower(str[i]);
|
||||
long i;
|
||||
for (i = 0; i < strlen(str); i++)
|
||||
str[i] = tolower(str[i]);
|
||||
|
||||
return str;
|
||||
return str;
|
||||
}
|
||||
|
||||
int _compare_vars(void *compare_arg, void *a, void *b)
|
||||
{
|
||||
http_var_t *vara, *varb;
|
||||
http_var_t *vara, *varb;
|
||||
|
||||
vara = (http_var_t *)a;
|
||||
varb = (http_var_t *)b;
|
||||
vara = (http_var_t *)a;
|
||||
varb = (http_var_t *)b;
|
||||
|
||||
return strcmp(vara->name, varb->name);
|
||||
return strcmp(vara->name, varb->name);
|
||||
}
|
||||
|
||||
int _free_vars(void *key)
|
||||
{
|
||||
http_var_t *var;
|
||||
http_var_t *var;
|
||||
|
||||
var = (http_var_t *)key;
|
||||
var = (http_var_t *)key;
|
||||
|
||||
if (var->name)
|
||||
free(var->name);
|
||||
if (var->value)
|
||||
free(var->value);
|
||||
free(var);
|
||||
if (var->name)
|
||||
free(var->name);
|
||||
if (var->value)
|
||||
free(var->value);
|
||||
free(var);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -17,25 +17,25 @@
|
||||
#define HTTPP_VAR_ICYPASSWORD "__icy_password"
|
||||
|
||||
typedef enum httpp_request_type_tag {
|
||||
httpp_req_none, httpp_req_get, httpp_req_post, httpp_req_head,
|
||||
httpp_req_source, httpp_req_play, httpp_req_stats, httpp_req_unknown
|
||||
httpp_req_none, httpp_req_get, httpp_req_post, httpp_req_head,
|
||||
httpp_req_source, httpp_req_play, httpp_req_stats, httpp_req_unknown
|
||||
} httpp_request_type_e;
|
||||
|
||||
typedef struct http_var_tag {
|
||||
char *name;
|
||||
char *value;
|
||||
char *name;
|
||||
char *value;
|
||||
} http_var_t;
|
||||
|
||||
typedef struct http_varlist_tag {
|
||||
http_var_t var;
|
||||
struct http_varlist_tag *next;
|
||||
http_var_t var;
|
||||
struct http_varlist_tag *next;
|
||||
} http_varlist_t;
|
||||
|
||||
typedef struct http_parser_tag {
|
||||
httpp_request_type_e req_type;
|
||||
char *uri;
|
||||
avl_tree *vars;
|
||||
avl_tree *queryvars;
|
||||
httpp_request_type_e req_type;
|
||||
char *uri;
|
||||
avl_tree *vars;
|
||||
avl_tree *queryvars;
|
||||
} http_parser_t;
|
||||
|
||||
http_parser_t *httpp_create_parser(void);
|
||||
|
@ -6,54 +6,54 @@
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buff[8192];
|
||||
int readed;
|
||||
http_parser_t parser;
|
||||
avl_node *node;
|
||||
http_var_t *var;
|
||||
char buff[8192];
|
||||
int readed;
|
||||
http_parser_t parser;
|
||||
avl_node *node;
|
||||
http_var_t *var;
|
||||
|
||||
httpp_initialize(&parser, NULL);
|
||||
httpp_initialize(&parser, NULL);
|
||||
|
||||
readed = fread(buff, 1, 8192, stdin);
|
||||
if (httpp_parse(&parser, buff, readed)) {
|
||||
printf("Parse succeeded...\n\n");
|
||||
printf("Request was ");
|
||||
switch (parser.req_type) {
|
||||
case httpp_req_none:
|
||||
printf(" none\n");
|
||||
break;
|
||||
case httpp_req_unknown:
|
||||
printf(" unknown\n");
|
||||
break;
|
||||
case httpp_req_get:
|
||||
printf(" get\n");
|
||||
break;
|
||||
case httpp_req_post:
|
||||
printf(" post\n");
|
||||
break;
|
||||
case httpp_req_head:
|
||||
printf(" head\n");
|
||||
break;
|
||||
}
|
||||
printf("Version was 1.%d\n", parser.version);
|
||||
|
||||
node = avl_get_first(parser.vars);
|
||||
while (node) {
|
||||
var = (http_var_t *)node->key;
|
||||
|
||||
if (var)
|
||||
printf("Iterating variable(s): %s = %s\n", var->name, var->value);
|
||||
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
} else {
|
||||
printf("Parse failed...\n");
|
||||
}
|
||||
readed = fread(buff, 1, 8192, stdin);
|
||||
if (httpp_parse(&parser, buff, readed)) {
|
||||
printf("Parse succeeded...\n\n");
|
||||
printf("Request was ");
|
||||
switch (parser.req_type) {
|
||||
case httpp_req_none:
|
||||
printf(" none\n");
|
||||
break;
|
||||
case httpp_req_unknown:
|
||||
printf(" unknown\n");
|
||||
break;
|
||||
case httpp_req_get:
|
||||
printf(" get\n");
|
||||
break;
|
||||
case httpp_req_post:
|
||||
printf(" post\n");
|
||||
break;
|
||||
case httpp_req_head:
|
||||
printf(" head\n");
|
||||
break;
|
||||
}
|
||||
printf("Version was 1.%d\n", parser.version);
|
||||
|
||||
node = avl_get_first(parser.vars);
|
||||
while (node) {
|
||||
var = (http_var_t *)node->key;
|
||||
|
||||
if (var)
|
||||
printf("Iterating variable(s): %s = %s\n", var->name, var->value);
|
||||
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
} else {
|
||||
printf("Parse failed...\n");
|
||||
}
|
||||
|
||||
printf("Destroying parser...\n");
|
||||
httpp_destroy(&parser);
|
||||
printf("Destroying parser...\n");
|
||||
httpp_destroy(&parser);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
198
src/log/log.c
198
src/log/log.c
@ -28,13 +28,13 @@ static int _initialized = 0;
|
||||
|
||||
typedef struct log_tag
|
||||
{
|
||||
int in_use;
|
||||
int in_use;
|
||||
|
||||
int level;
|
||||
int level;
|
||||
|
||||
char *filename;
|
||||
FILE *logfile;
|
||||
|
||||
char *filename;
|
||||
FILE *logfile;
|
||||
|
||||
char *buffer;
|
||||
} log_t;
|
||||
|
||||
@ -47,26 +47,26 @@ static void _unlock_logger();
|
||||
|
||||
void log_initialize()
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
if (_initialized) return;
|
||||
if (_initialized) return;
|
||||
|
||||
for (i = 0; i < LOG_MAXLOGS; i++) {
|
||||
loglist[i].in_use = 0;
|
||||
loglist[i].level = 2;
|
||||
loglist[i].filename = NULL;
|
||||
loglist[i].logfile = NULL;
|
||||
loglist[i].buffer = NULL;
|
||||
}
|
||||
for (i = 0; i < LOG_MAXLOGS; i++) {
|
||||
loglist[i].in_use = 0;
|
||||
loglist[i].level = 2;
|
||||
loglist[i].filename = NULL;
|
||||
loglist[i].logfile = NULL;
|
||||
loglist[i].buffer = NULL;
|
||||
}
|
||||
|
||||
/* initialize mutexes */
|
||||
/* initialize mutexes */
|
||||
#ifndef _WIN32
|
||||
pthread_mutex_init(&_logger_mutex, NULL);
|
||||
pthread_mutex_init(&_logger_mutex, NULL);
|
||||
#else
|
||||
InitializeCriticalSection(&_logger_mutex);
|
||||
InitializeCriticalSection(&_logger_mutex);
|
||||
#endif
|
||||
|
||||
_initialized = 1;
|
||||
_initialized = 1;
|
||||
}
|
||||
|
||||
int log_open_file(FILE *file)
|
||||
@ -75,34 +75,34 @@ int log_open_file(FILE *file)
|
||||
|
||||
if(file == NULL) return LOG_EINSANE;
|
||||
|
||||
log_id = _get_log_id();
|
||||
if (log_id < 0) return LOG_ENOMORELOGS;
|
||||
log_id = _get_log_id();
|
||||
if (log_id < 0) return LOG_ENOMORELOGS;
|
||||
|
||||
loglist[log_id].logfile = file;
|
||||
if (loglist[log_id].logfile != NULL) {
|
||||
loglist[log_id].filename = NULL;
|
||||
} else {
|
||||
_release_log_id(log_id);
|
||||
return LOG_ECANTOPEN;
|
||||
}
|
||||
loglist[log_id].logfile = file;
|
||||
if (loglist[log_id].logfile != NULL) {
|
||||
loglist[log_id].filename = NULL;
|
||||
} else {
|
||||
_release_log_id(log_id);
|
||||
return LOG_ECANTOPEN;
|
||||
}
|
||||
|
||||
return log_id;
|
||||
return log_id;
|
||||
}
|
||||
|
||||
|
||||
int log_open(const char *filename)
|
||||
{
|
||||
int ret;
|
||||
int ret;
|
||||
FILE *file;
|
||||
|
||||
if (filename == NULL) return LOG_EINSANE;
|
||||
if (strcmp(filename, "") == 0) return LOG_EINSANE;
|
||||
if (filename == NULL) return LOG_EINSANE;
|
||||
if (strcmp(filename, "") == 0) return LOG_EINSANE;
|
||||
|
||||
file = fopen(filename, "a");
|
||||
|
||||
ret = log_open_file(file);
|
||||
|
||||
if(ret >= 0)
|
||||
if(ret >= 0)
|
||||
setvbuf(file, NULL, IO_BUFFER_TYPE, 0);
|
||||
|
||||
return ret;
|
||||
@ -110,152 +110,152 @@ int log_open(const char *filename)
|
||||
|
||||
int log_open_with_buffer(const char *filename, int size)
|
||||
{
|
||||
/* not implemented */
|
||||
return LOG_ENOTIMPL;
|
||||
/* not implemented */
|
||||
return LOG_ENOTIMPL;
|
||||
}
|
||||
|
||||
void log_set_level(int log_id, int level)
|
||||
{
|
||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||
if (loglist[log_id].in_use == 0) return;
|
||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||
if (loglist[log_id].in_use == 0) return;
|
||||
|
||||
loglist[log_id].level = level;
|
||||
loglist[log_id].level = level;
|
||||
}
|
||||
|
||||
void log_flush(int log_id)
|
||||
{
|
||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||
if (loglist[log_id].in_use == 0) return;
|
||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||
if (loglist[log_id].in_use == 0) return;
|
||||
|
||||
fflush(loglist[log_id].logfile);
|
||||
fflush(loglist[log_id].logfile);
|
||||
}
|
||||
|
||||
void log_reopen(int log_id)
|
||||
{
|
||||
/* not implemented yet */
|
||||
/* not implemented yet */
|
||||
}
|
||||
|
||||
void log_close(int log_id)
|
||||
{
|
||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||
if (loglist[log_id].in_use == 0) return;
|
||||
if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
|
||||
if (loglist[log_id].in_use == 0) return;
|
||||
|
||||
loglist[log_id].in_use = 0;
|
||||
loglist[log_id].level = 2;
|
||||
if (loglist[log_id].filename) free(loglist[log_id].filename);
|
||||
if (loglist[log_id].buffer) free(loglist[log_id].buffer);
|
||||
fclose(loglist[log_id].logfile);
|
||||
loglist[log_id].logfile = NULL;
|
||||
loglist[log_id].in_use = 0;
|
||||
loglist[log_id].level = 2;
|
||||
if (loglist[log_id].filename) free(loglist[log_id].filename);
|
||||
if (loglist[log_id].buffer) free(loglist[log_id].buffer);
|
||||
fclose(loglist[log_id].logfile);
|
||||
loglist[log_id].logfile = NULL;
|
||||
}
|
||||
|
||||
void log_shutdown()
|
||||
{
|
||||
/* destroy mutexes */
|
||||
/* destroy mutexes */
|
||||
#ifndef _WIN32
|
||||
pthread_mutex_destroy(&_logger_mutex);
|
||||
pthread_mutex_destroy(&_logger_mutex);
|
||||
#else
|
||||
DeleteCriticalSection(&_logger_mutex);
|
||||
DeleteCriticalSection(&_logger_mutex);
|
||||
#endif
|
||||
|
||||
_initialized = 0;
|
||||
_initialized = 0;
|
||||
}
|
||||
|
||||
void log_write(int log_id, int priority, const char *cat, const char *func,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
static char prior[4][5] = { "EROR\0", "WARN\0", "INFO\0", "DBUG\0" };
|
||||
char tyme[128];
|
||||
char pre[256];
|
||||
char line[LOG_MAXLINELEN];
|
||||
time_t now;
|
||||
va_list ap;
|
||||
char tyme[128];
|
||||
char pre[256];
|
||||
char line[LOG_MAXLINELEN];
|
||||
time_t now;
|
||||
va_list ap;
|
||||
|
||||
if (log_id < 0) return;
|
||||
if (log_id < 0) return;
|
||||
if (log_id > LOG_MAXLOGS) return; /* Bad log number */
|
||||
if (loglist[log_id].level < priority) return;
|
||||
if (loglist[log_id].level < priority) return;
|
||||
if (priority > 4) return; /* Bad priority */
|
||||
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||
|
||||
now = time(NULL);
|
||||
now = time(NULL);
|
||||
|
||||
/* localtime() isn't threadsafe, localtime_r isn't portable enough... */
|
||||
_lock_logger();
|
||||
strftime(tyme, 128, "[%Y-%m-%d %H:%M:%S]", localtime(&now));
|
||||
strftime(tyme, 128, "[%Y-%m-%d %H:%M:%S]", localtime(&now));
|
||||
_unlock_logger();
|
||||
|
||||
snprintf(pre, 256, "%s %s%s", prior[priority-1], cat, func);
|
||||
snprintf(pre, 256, "%s %s%s", prior[priority-1], cat, func);
|
||||
|
||||
fprintf(loglist[log_id].logfile, "%s %s %s\n", tyme, pre, line);
|
||||
fprintf(loglist[log_id].logfile, "%s %s %s\n", tyme, pre, line);
|
||||
|
||||
va_end(ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_write_direct(int log_id, const char *fmt, ...)
|
||||
{
|
||||
char line[LOG_MAXLINELEN];
|
||||
va_list ap;
|
||||
char line[LOG_MAXLINELEN];
|
||||
va_list ap;
|
||||
|
||||
if (log_id < 0) return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||
fprintf(loglist[log_id].logfile, "%s\n", line);
|
||||
va_end(ap);
|
||||
if (log_id < 0) return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||
fprintf(loglist[log_id].logfile, "%s\n", line);
|
||||
va_end(ap);
|
||||
|
||||
fflush(loglist[log_id].logfile);
|
||||
fflush(loglist[log_id].logfile);
|
||||
}
|
||||
|
||||
int _get_log_id()
|
||||
{
|
||||
int i;
|
||||
int id = -1;
|
||||
int i;
|
||||
int id = -1;
|
||||
|
||||
/* lock mutex */
|
||||
_lock_logger();
|
||||
/* lock mutex */
|
||||
_lock_logger();
|
||||
|
||||
for (i = 0; i < LOG_MAXLOGS; i++)
|
||||
if (loglist[i].in_use == 0) {
|
||||
loglist[i].in_use = 1;
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < LOG_MAXLOGS; i++)
|
||||
if (loglist[i].in_use == 0) {
|
||||
loglist[i].in_use = 1;
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/* unlock mutex */
|
||||
_unlock_logger();
|
||||
/* unlock mutex */
|
||||
_unlock_logger();
|
||||
|
||||
return id;
|
||||
return id;
|
||||
}
|
||||
|
||||
void _release_log_id(int log_id)
|
||||
{
|
||||
/* lock mutex */
|
||||
_lock_logger();
|
||||
/* lock mutex */
|
||||
_lock_logger();
|
||||
|
||||
loglist[log_id].in_use = 0;
|
||||
loglist[log_id].in_use = 0;
|
||||
|
||||
/* unlock mutex */
|
||||
_unlock_logger();
|
||||
/* unlock mutex */
|
||||
_unlock_logger();
|
||||
}
|
||||
|
||||
static void _lock_logger()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
pthread_mutex_lock(&_logger_mutex);
|
||||
pthread_mutex_lock(&_logger_mutex);
|
||||
#else
|
||||
EnterCriticalSection(&_logger_mutex);
|
||||
EnterCriticalSection(&_logger_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _unlock_logger()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
pthread_mutex_unlock(&_logger_mutex);
|
||||
pthread_mutex_unlock(&_logger_mutex);
|
||||
#else
|
||||
LeaveCriticalSection(&_logger_mutex);
|
||||
#endif
|
||||
LeaveCriticalSection(&_logger_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,15 +7,15 @@
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int lid;
|
||||
int lid;
|
||||
|
||||
log_initialize();
|
||||
log_initialize();
|
||||
|
||||
lid = log_open("test.log");
|
||||
lid = log_open("test.log");
|
||||
|
||||
LOG_ERR(lid, "The log id is %d, damnit...", lid);
|
||||
LOG_ERR(lid, "The log id is %d, damnit...", lid);
|
||||
|
||||
log_close(lid);
|
||||
log_close(lid);
|
||||
|
||||
log_shutdown();
|
||||
log_shutdown();
|
||||
}
|
||||
|
@ -36,35 +36,35 @@ int accesslog = 0;
|
||||
*/
|
||||
void logging_access(client_t *client)
|
||||
{
|
||||
char datebuf[128];
|
||||
char reqbuf[1024];
|
||||
struct tm *thetime;
|
||||
time_t now;
|
||||
time_t stayed;
|
||||
char datebuf[128];
|
||||
char reqbuf[1024];
|
||||
struct tm *thetime;
|
||||
time_t now;
|
||||
time_t stayed;
|
||||
|
||||
now = time(NULL);
|
||||
now = time(NULL);
|
||||
|
||||
/* build the data */
|
||||
/* TODO: localtime is not threadsafe on all platforms
|
||||
** we should probably use localtime_r if it's available
|
||||
*/
|
||||
PROTECT_CODE(thetime = localtime(&now); strftime(datebuf, 128, LOGGING_FORMAT_CLF, thetime))
|
||||
/* build the data */
|
||||
/* TODO: localtime is not threadsafe on all platforms
|
||||
** we should probably use localtime_r if it's available
|
||||
*/
|
||||
PROTECT_CODE(thetime = localtime(&now); strftime(datebuf, 128, LOGGING_FORMAT_CLF, thetime))
|
||||
|
||||
/* build the request */
|
||||
snprintf(reqbuf, 1024, "%s %s %s/%s", httpp_getvar(client->parser, HTTPP_VAR_REQ_TYPE), httpp_getvar(client->parser, HTTPP_VAR_URI),
|
||||
httpp_getvar(client->parser, HTTPP_VAR_PROTOCOL), httpp_getvar(client->parser, HTTPP_VAR_VERSION));
|
||||
/* build the request */
|
||||
snprintf(reqbuf, 1024, "%s %s %s/%s", httpp_getvar(client->parser, HTTPP_VAR_REQ_TYPE), httpp_getvar(client->parser, HTTPP_VAR_URI),
|
||||
httpp_getvar(client->parser, HTTPP_VAR_PROTOCOL), httpp_getvar(client->parser, HTTPP_VAR_VERSION));
|
||||
|
||||
stayed = now - client->con->con_time;
|
||||
stayed = now - client->con->con_time;
|
||||
|
||||
log_write_direct(accesslog, "%s - - [%s] \"%s\" %d %lld \"%s\" \"%s\" %d",
|
||||
client->con->ip,
|
||||
datebuf,
|
||||
reqbuf,
|
||||
client->respcode,
|
||||
client->con->sent_bytes,
|
||||
(httpp_getvar(client->parser, "referer") != NULL) ? httpp_getvar(client->parser, "referer") : "-",
|
||||
(httpp_getvar(client->parser, "user-agent") != NULL) ? httpp_getvar(client->parser, "user-agent") : "-",
|
||||
(int)stayed);
|
||||
log_write_direct(accesslog, "%s - - [%s] \"%s\" %d %lld \"%s\" \"%s\" %d",
|
||||
client->con->ip,
|
||||
datebuf,
|
||||
reqbuf,
|
||||
client->respcode,
|
||||
client->con->sent_bytes,
|
||||
(httpp_getvar(client->parser, "referer") != NULL) ? httpp_getvar(client->parser, "referer") : "-",
|
||||
(httpp_getvar(client->parser, "user-agent") != NULL) ? httpp_getvar(client->parser, "user-agent") : "-",
|
||||
(int)stayed);
|
||||
}
|
||||
|
||||
|
||||
|
262
src/main.c
262
src/main.c
@ -41,126 +41,126 @@
|
||||
|
||||
static void _print_usage()
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf("\ticecast -c <file>\t\tSpecify configuration file\n");
|
||||
printf("\n");
|
||||
printf("Usage:\n");
|
||||
printf("\ticecast -c <file>\t\tSpecify configuration file\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void _stop_logging(void)
|
||||
{
|
||||
log_close(errorlog);
|
||||
log_close(accesslog);
|
||||
log_close(errorlog);
|
||||
log_close(accesslog);
|
||||
}
|
||||
|
||||
static void _initialize_subsystems(void)
|
||||
{
|
||||
log_initialize();
|
||||
thread_initialize();
|
||||
sock_initialize();
|
||||
resolver_initialize();
|
||||
config_initialize();
|
||||
connection_initialize();
|
||||
global_initialize();
|
||||
refbuf_initialize();
|
||||
log_initialize();
|
||||
thread_initialize();
|
||||
sock_initialize();
|
||||
resolver_initialize();
|
||||
config_initialize();
|
||||
connection_initialize();
|
||||
global_initialize();
|
||||
refbuf_initialize();
|
||||
xslt_initialize();
|
||||
curl_initialize();
|
||||
curl_initialize();
|
||||
}
|
||||
|
||||
static void _shutdown_subsystems(void)
|
||||
{
|
||||
curl_shutdown();
|
||||
curl_shutdown();
|
||||
fserve_shutdown();
|
||||
xslt_shutdown();
|
||||
refbuf_shutdown();
|
||||
stats_shutdown();
|
||||
slave_shutdown();
|
||||
refbuf_shutdown();
|
||||
stats_shutdown();
|
||||
slave_shutdown();
|
||||
|
||||
/* Now that these are done, we can stop the loggers. */
|
||||
_stop_logging();
|
||||
_stop_logging();
|
||||
|
||||
global_shutdown();
|
||||
connection_shutdown();
|
||||
config_shutdown();
|
||||
resolver_shutdown();
|
||||
sock_shutdown();
|
||||
thread_shutdown();
|
||||
log_shutdown();
|
||||
global_shutdown();
|
||||
connection_shutdown();
|
||||
config_shutdown();
|
||||
resolver_shutdown();
|
||||
sock_shutdown();
|
||||
thread_shutdown();
|
||||
log_shutdown();
|
||||
|
||||
xmlCleanupParser();
|
||||
}
|
||||
|
||||
static int _parse_config_file(int argc, char **argv, char *filename, int size)
|
||||
{
|
||||
int i = 1;
|
||||
int processID = 0;
|
||||
int i = 1;
|
||||
int processID = 0;
|
||||
|
||||
if (argc < 3) return -1;
|
||||
if (argc < 3) return -1;
|
||||
|
||||
while (i < argc) {
|
||||
if (strcmp(argv[i], "-b") == 0) {
|
||||
while (i < argc) {
|
||||
if (strcmp(argv[i], "-b") == 0) {
|
||||
#ifndef WIN32
|
||||
fprintf(stdout, "Starting icecast2\nDetaching from the console\n");
|
||||
if ((processID = (int)fork()) > 0) {
|
||||
/* exit the parent */
|
||||
_exit(0);
|
||||
}
|
||||
fprintf(stdout, "Starting icecast2\nDetaching from the console\n");
|
||||
if ((processID = (int)fork()) > 0) {
|
||||
/* exit the parent */
|
||||
_exit(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (strcmp(argv[i], "-c") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
strncpy(filename, argv[i + 1], size-1);
|
||||
}
|
||||
if (strcmp(argv[i], "-c") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
strncpy(filename, argv[i + 1], size-1);
|
||||
filename[size-1] = 0;
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _start_logging(void)
|
||||
{
|
||||
char fn_error[FILENAME_MAX];
|
||||
char fn_access[FILENAME_MAX];
|
||||
ice_config_t *config = config_get_config_unlocked();
|
||||
char fn_error[FILENAME_MAX];
|
||||
char fn_access[FILENAME_MAX];
|
||||
ice_config_t *config = config_get_config_unlocked();
|
||||
|
||||
if(strcmp(config->error_log, "-")) {
|
||||
if(strcmp(config->error_log, "-")) {
|
||||
snprintf(fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log);
|
||||
errorlog = log_open(fn_error);
|
||||
errorlog = log_open(fn_error);
|
||||
} else {
|
||||
errorlog = log_open_file(stderr);
|
||||
}
|
||||
if(strcmp(config->access_log, "-")) {
|
||||
if(strcmp(config->access_log, "-")) {
|
||||
snprintf(fn_access, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->access_log);
|
||||
accesslog = log_open(fn_access);
|
||||
accesslog = log_open(fn_access);
|
||||
} else {
|
||||
accesslog = log_open_file(stderr);
|
||||
}
|
||||
|
||||
log_set_level(errorlog, config->loglevel);
|
||||
log_set_level(accesslog, 4);
|
||||
|
||||
log_set_level(errorlog, config->loglevel);
|
||||
log_set_level(accesslog, 4);
|
||||
|
||||
if (errorlog < 0)
|
||||
fprintf(stderr, "FATAL: could not open %s for error logging\n", fn_error);
|
||||
if (accesslog < 0)
|
||||
fprintf(stderr, "FATAL: could not open %s for access logging\n", fn_access);
|
||||
if (errorlog < 0)
|
||||
fprintf(stderr, "FATAL: could not open %s for error logging\n", fn_error);
|
||||
if (accesslog < 0)
|
||||
fprintf(stderr, "FATAL: could not open %s for access logging\n", fn_access);
|
||||
|
||||
if (errorlog >= 0 && accesslog >= 0) return 1;
|
||||
|
||||
return 0;
|
||||
if (errorlog >= 0 && accesslog >= 0) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
for(i = 0; i < MAX_LISTEN_SOCKETS; i++) {
|
||||
if(config->listeners[i].port <= 0)
|
||||
@ -169,8 +169,8 @@ static int _setup_sockets(void)
|
||||
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",
|
||||
if (global.serversock[i] == SOCK_ERROR) {
|
||||
fprintf(stderr, "Could not create listener socket on port %d\n",
|
||||
config->listeners[i].port);
|
||||
return 0;
|
||||
}
|
||||
@ -181,33 +181,33 @@ static int _setup_sockets(void)
|
||||
}
|
||||
|
||||
global.server_sockets = successful;
|
||||
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _start_listening(void)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i < global.server_sockets; i++) {
|
||||
if (sock_listen(global.serversock[i], ICE_LISTEN_QUEUE) == SOCK_ERROR)
|
||||
return 0;
|
||||
if (sock_listen(global.serversock[i], ICE_LISTEN_QUEUE) == SOCK_ERROR)
|
||||
return 0;
|
||||
|
||||
sock_set_blocking(global.serversock[i], SOCK_NONBLOCK);
|
||||
sock_set_blocking(global.serversock[i], SOCK_NONBLOCK);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* bind the socket and start listening */
|
||||
static int _server_proc_init(void)
|
||||
{
|
||||
if (!_setup_sockets())
|
||||
return 0;
|
||||
if (!_setup_sockets())
|
||||
return 0;
|
||||
|
||||
if (!_start_listening()) {
|
||||
fprintf(stderr, "Failed trying to listen on server socket\n");
|
||||
return 0;
|
||||
}
|
||||
if (!_start_listening()) {
|
||||
fprintf(stderr, "Failed trying to listen on server socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -217,10 +217,10 @@ static void _server_proc(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
connection_accept_loop();
|
||||
connection_accept_loop();
|
||||
|
||||
for(i=0; i < MAX_LISTEN_SOCKETS; i++)
|
||||
sock_close(global.serversock[i]);
|
||||
sock_close(global.serversock[i]);
|
||||
}
|
||||
|
||||
/* chroot the process. Watch out - we need to do this before starting other
|
||||
@ -302,47 +302,47 @@ static void _ch_root_uid_setup(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int res, ret;
|
||||
char filename[512];
|
||||
int res, ret;
|
||||
char filename[512];
|
||||
|
||||
/* parse the '-c icecast.xml' option
|
||||
** only, so that we can read a configfile
|
||||
*/
|
||||
res = _parse_config_file(argc, argv, filename, 512);
|
||||
if (res == 1) {
|
||||
/* startup all the modules */
|
||||
_initialize_subsystems();
|
||||
/* parse the '-c icecast.xml' option
|
||||
** only, so that we can read a configfile
|
||||
*/
|
||||
res = _parse_config_file(argc, argv, filename, 512);
|
||||
if (res == 1) {
|
||||
/* startup all the modules */
|
||||
_initialize_subsystems();
|
||||
|
||||
/* parse the config file */
|
||||
/* parse the config file */
|
||||
config_get_config();
|
||||
ret = config_initial_parse_file(filename);
|
||||
ret = config_initial_parse_file(filename);
|
||||
config_release_config();
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "FATAL: error parsing config file:");
|
||||
switch (ret) {
|
||||
case CONFIG_EINSANE:
|
||||
fprintf(stderr, "filename was null or blank\n");
|
||||
break;
|
||||
case CONFIG_ENOROOT:
|
||||
fprintf(stderr, "no root element found\n");
|
||||
break;
|
||||
case CONFIG_EBADROOT:
|
||||
fprintf(stderr, "root element is not <icecast>\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "parse error\n");
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "FATAL: error parsing config file:");
|
||||
switch (ret) {
|
||||
case CONFIG_EINSANE:
|
||||
fprintf(stderr, "filename was null or blank\n");
|
||||
break;
|
||||
case CONFIG_ENOROOT:
|
||||
fprintf(stderr, "no root element found\n");
|
||||
break;
|
||||
case CONFIG_EBADROOT:
|
||||
fprintf(stderr, "root element is not <icecast>\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "parse error\n");
|
||||
break;
|
||||
}
|
||||
_shutdown_subsystems();
|
||||
return 1;
|
||||
}
|
||||
} else if (res == -1) {
|
||||
_print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* override config file options with commandline options */
|
||||
config_parse_cmdline(argc, argv);
|
||||
}
|
||||
} else if (res == -1) {
|
||||
_print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* override config file options with commandline options */
|
||||
config_parse_cmdline(argc, argv);
|
||||
|
||||
/* Bind socket, before we change userid */
|
||||
if(!_server_proc_init()) {
|
||||
@ -371,28 +371,28 @@ int main(int argc, char **argv)
|
||||
/* setup default signal handlers */
|
||||
sighandler_initialize();
|
||||
|
||||
if (!_start_logging()) {
|
||||
fprintf(stderr, "FATAL: Could not start logging\n");
|
||||
_shutdown_subsystems();
|
||||
return 1;
|
||||
}
|
||||
if (!_start_logging()) {
|
||||
fprintf(stderr, "FATAL: Could not start logging\n");
|
||||
_shutdown_subsystems();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Do this after logging init */
|
||||
slave_initialize();
|
||||
|
||||
INFO0("icecast server started");
|
||||
INFO0("icecast server started");
|
||||
|
||||
/* REM 3D Graphics */
|
||||
/* REM 3D Graphics */
|
||||
|
||||
/* let her rip */
|
||||
global.running = ICE_RUNNING;
|
||||
_server_proc();
|
||||
/* let her rip */
|
||||
global.running = ICE_RUNNING;
|
||||
_server_proc();
|
||||
|
||||
INFO0("Shutting down");
|
||||
INFO0("Shutting down");
|
||||
|
||||
_shutdown_subsystems();
|
||||
_shutdown_subsystems();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
296
src/net/sock.c
296
src/net/sock.c
@ -47,7 +47,7 @@
|
||||
#define ENOTSOCK WSAENOTSOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define EALREADY WSAEALREADY
|
||||
#define socklen_t int
|
||||
#define socklen_t int
|
||||
#endif
|
||||
|
||||
#include "sock.h"
|
||||
@ -61,11 +61,11 @@
|
||||
void sock_initialize(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsad;
|
||||
WSAStartup(0x0101, &wsad);
|
||||
WSADATA wsad;
|
||||
WSAStartup(0x0101, &wsad);
|
||||
#endif
|
||||
|
||||
resolver_initialize();
|
||||
resolver_initialize();
|
||||
}
|
||||
|
||||
/* sock_shutdown
|
||||
@ -76,7 +76,7 @@ void sock_initialize(void)
|
||||
void sock_shutdown(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -89,15 +89,15 @@ void sock_shutdown(void)
|
||||
*/
|
||||
char *sock_get_localip(char *buff, int len)
|
||||
{
|
||||
char temp[1024];
|
||||
char temp[1024];
|
||||
|
||||
if (gethostname(temp, 1024) != 0)
|
||||
return NULL;
|
||||
if (gethostname(temp, 1024) != 0)
|
||||
return NULL;
|
||||
|
||||
if (resolver_getip(temp, buff, len))
|
||||
return buff;
|
||||
if (resolver_getip(temp, buff, len))
|
||||
return buff;
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* sock_error
|
||||
@ -107,9 +107,9 @@ char *sock_get_localip(char *buff, int len)
|
||||
int sock_error(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return WSAGetLastError();
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -163,15 +163,15 @@ int sock_valid_socket(sock_t sock)
|
||||
#ifdef _WIN32
|
||||
int inet_aton(const char *s, struct in_addr *a)
|
||||
{
|
||||
int lsb, b2, b3, msb;
|
||||
int lsb, b2, b3, msb;
|
||||
|
||||
if (sscanf(s, "%d.%d.%d.%d", &lsb, &b2, &b3, &msb) < 4) {
|
||||
return 0;
|
||||
}
|
||||
if (sscanf(s, "%d.%d.%d.%d", &lsb, &b2, &b3, &msb) < 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
a->s_addr = inet_addr(s);
|
||||
a->s_addr = inet_addr(s);
|
||||
|
||||
return (a->s_addr != INADDR_NONE);
|
||||
return (a->s_addr != INADDR_NONE);
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@ -184,23 +184,23 @@ int inet_aton(const char *s, struct in_addr *a)
|
||||
int sock_set_blocking(sock_t sock, const int block)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int varblock = block;
|
||||
int varblock = block;
|
||||
#endif
|
||||
|
||||
if ((!sock_valid_socket(sock)) || (block < 0) || (block > 1))
|
||||
return SOCK_ERROR;
|
||||
if ((!sock_valid_socket(sock)) || (block < 0) || (block > 1))
|
||||
return SOCK_ERROR;
|
||||
|
||||
#ifdef _WIN32
|
||||
return ioctlsocket(sock, FIONBIO, &varblock);
|
||||
return ioctlsocket(sock, FIONBIO, &varblock);
|
||||
#else
|
||||
return fcntl(sock, F_SETFL, (block == SOCK_BLOCK) ? 0 : O_NONBLOCK);
|
||||
return fcntl(sock, F_SETFL, (block == SOCK_BLOCK) ? 0 : O_NONBLOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
int sock_set_nolinger(sock_t sock)
|
||||
{
|
||||
struct linger lin = { 0, 0 };
|
||||
return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin,
|
||||
struct linger lin = { 0, 0 };
|
||||
return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin,
|
||||
sizeof(struct linger));
|
||||
}
|
||||
|
||||
@ -214,8 +214,8 @@ int sock_set_nodelay(sock_t sock)
|
||||
|
||||
int sock_set_keepalive(sock_t sock)
|
||||
{
|
||||
int keepalive = 1;
|
||||
return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
|
||||
int keepalive = 1;
|
||||
return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
|
||||
sizeof(int));
|
||||
}
|
||||
|
||||
@ -226,9 +226,9 @@ int sock_set_keepalive(sock_t sock)
|
||||
int sock_close(sock_t sock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return closesocket(sock);
|
||||
return closesocket(sock);
|
||||
#else
|
||||
return close(sock);
|
||||
return close(sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -278,16 +278,16 @@ ssize_t sock_writev (int sock, const struct iovec *iov, const size_t count)
|
||||
*/
|
||||
int sock_write_bytes(sock_t sock, const void *buff, const size_t len)
|
||||
{
|
||||
/* sanity check */
|
||||
if (!buff) {
|
||||
return SOCK_ERROR;
|
||||
} else if (len <= 0) {
|
||||
return SOCK_ERROR;
|
||||
} /*else if (!sock_valid_socket(sock)) {
|
||||
return SOCK_ERROR;
|
||||
} */
|
||||
/* sanity check */
|
||||
if (!buff) {
|
||||
return SOCK_ERROR;
|
||||
} else if (len <= 0) {
|
||||
return SOCK_ERROR;
|
||||
} /*else if (!sock_valid_socket(sock)) {
|
||||
return SOCK_ERROR;
|
||||
} */
|
||||
|
||||
return send(sock, buff, len, 0);
|
||||
return send(sock, buff, len, 0);
|
||||
}
|
||||
|
||||
/* sock_write_string
|
||||
@ -297,7 +297,7 @@ int sock_write_bytes(sock_t sock, const void *buff, const size_t len)
|
||||
*/
|
||||
int sock_write_string(sock_t sock, const char *buff)
|
||||
{
|
||||
return (sock_write_bytes(sock, buff, strlen(buff)) > 0);
|
||||
return (sock_write_bytes(sock, buff, strlen(buff)) > 0);
|
||||
}
|
||||
|
||||
/* sock_write
|
||||
@ -308,14 +308,14 @@ int sock_write_string(sock_t sock, const char *buff)
|
||||
*/
|
||||
int sock_write(sock_t sock, const char *fmt, ...)
|
||||
{
|
||||
char buff[1024];
|
||||
va_list ap;
|
||||
char buff[1024];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buff, 1024, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return sock_write_bytes(sock, buff, strlen(buff));
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buff, 1024, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return sock_write_bytes(sock, buff, strlen(buff));
|
||||
}
|
||||
|
||||
int sock_write_fmt(sock_t sock, char *fmt, va_list ap)
|
||||
@ -330,11 +330,11 @@ int sock_write_fmt(sock_t sock, char *fmt, va_list ap)
|
||||
int sock_read_bytes(sock_t sock, char *buff, const int len)
|
||||
{
|
||||
|
||||
/*if (!sock_valid_socket(sock)) return 0; */
|
||||
if (!buff) return 0;
|
||||
if (len <= 0) return 0;
|
||||
/*if (!sock_valid_socket(sock)) return 0; */
|
||||
if (!buff) return 0;
|
||||
if (len <= 0) return 0;
|
||||
|
||||
return recv(sock, buff, len, 0);
|
||||
return recv(sock, buff, len, 0);
|
||||
}
|
||||
|
||||
/* sock_read_line
|
||||
@ -347,36 +347,36 @@ int sock_read_bytes(sock_t sock, char *buff, const int len)
|
||||
*/
|
||||
int sock_read_line(sock_t sock, char *buff, const int len)
|
||||
{
|
||||
char c = '\0';
|
||||
int read_bytes, pos;
|
||||
char c = '\0';
|
||||
int read_bytes, pos;
|
||||
|
||||
/*if (!sock_valid_socket(sock)) {
|
||||
return 0;
|
||||
} else*/ if (!buff) {
|
||||
return 0;
|
||||
} else if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
/*if (!sock_valid_socket(sock)) {
|
||||
return 0;
|
||||
} else*/ if (!buff) {
|
||||
return 0;
|
||||
} else if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
read_bytes = recv(sock, &c, 1, 0);
|
||||
pos = 0;
|
||||
read_bytes = recv(sock, &c, 1, 0);
|
||||
|
||||
if (read_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (read_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((c != '\n') && (pos < len) && (read_bytes == 1)) {
|
||||
if (c != '\r')
|
||||
buff[pos++] = c;
|
||||
read_bytes = recv(sock, &c, 1, 0);
|
||||
}
|
||||
|
||||
if (read_bytes == 1) {
|
||||
buff[pos] = '\0';
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
while ((c != '\n') && (pos < len) && (read_bytes == 1)) {
|
||||
if (c != '\r')
|
||||
buff[pos++] = c;
|
||||
read_bytes = recv(sock, &c, 1, 0);
|
||||
}
|
||||
|
||||
if (read_bytes == 1) {
|
||||
buff[pos] = '\0';
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if a connection can be written to
|
||||
@ -588,99 +588,99 @@ sock_t sock_connect_wto(const char *hostname, const int port, const int timeout)
|
||||
sock_t sock_get_server_socket(const int port, char *sinterface)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_storage sa;
|
||||
#else
|
||||
struct sockaddr_in sa;
|
||||
struct sockaddr_storage sa;
|
||||
#else
|
||||
struct sockaddr_in sa;
|
||||
#endif
|
||||
int sa_family, sa_len, error, opt;
|
||||
sock_t sock;
|
||||
char ip[MAX_ADDR_LEN];
|
||||
int sa_family, sa_len, error, opt;
|
||||
sock_t sock;
|
||||
char ip[MAX_ADDR_LEN];
|
||||
|
||||
if (port < 0)
|
||||
return SOCK_ERROR;
|
||||
if (port < 0)
|
||||
return SOCK_ERROR;
|
||||
|
||||
/* defaults */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa_family = AF_INET;
|
||||
sa_len = sizeof(struct sockaddr_in);
|
||||
/* defaults */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa_family = AF_INET;
|
||||
sa_len = sizeof(struct sockaddr_in);
|
||||
|
||||
/* set the interface to bind to if specified */
|
||||
if (sinterface != NULL) {
|
||||
if (!resolver_getip(sinterface, ip, sizeof (ip)))
|
||||
return SOCK_ERROR;
|
||||
/* set the interface to bind to if specified */
|
||||
if (sinterface != NULL) {
|
||||
if (!resolver_getip(sinterface, ip, sizeof (ip)))
|
||||
return SOCK_ERROR;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (inet_pton(AF_INET, ip, &((struct sockaddr_in*)&sa)->sin_addr) > 0) {
|
||||
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
||||
} else if (inet_pton(AF_INET6, ip,
|
||||
if (inet_pton(AF_INET, ip, &((struct sockaddr_in*)&sa)->sin_addr) > 0) {
|
||||
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
||||
} else if (inet_pton(AF_INET6, ip,
|
||||
&((struct sockaddr_in6*)&sa)->sin6_addr) > 0) {
|
||||
sa_family = AF_INET6;
|
||||
sa_len = sizeof (struct sockaddr_in6);
|
||||
((struct sockaddr_in6*)&sa)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6*)&sa)->sin6_port = htons(port);
|
||||
} else {
|
||||
return SOCK_ERROR;
|
||||
}
|
||||
sa_family = AF_INET6;
|
||||
sa_len = sizeof (struct sockaddr_in6);
|
||||
((struct sockaddr_in6*)&sa)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6*)&sa)->sin6_port = htons(port);
|
||||
} else {
|
||||
return SOCK_ERROR;
|
||||
}
|
||||
#else
|
||||
if (!inet_aton(ip, &sa.sin_addr)) {
|
||||
return SOCK_ERROR;
|
||||
} else {
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(port);
|
||||
}
|
||||
if (!inet_aton(ip, &sa.sin_addr)) {
|
||||
return SOCK_ERROR;
|
||||
} else {
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(port);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
((struct sockaddr_in*)&sa)->sin_addr.s_addr = INADDR_ANY;
|
||||
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
||||
}
|
||||
} else {
|
||||
((struct sockaddr_in*)&sa)->sin_addr.s_addr = INADDR_ANY;
|
||||
((struct sockaddr_in*)&sa)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)&sa)->sin_port = htons(port);
|
||||
}
|
||||
|
||||
/* get a socket */
|
||||
sock = socket(sa_family, SOCK_STREAM, 0);
|
||||
if (sock == -1)
|
||||
return SOCK_ERROR;
|
||||
/* get a socket */
|
||||
sock = socket(sa_family, SOCK_STREAM, 0);
|
||||
if (sock == -1)
|
||||
return SOCK_ERROR;
|
||||
|
||||
/* reuse it if we can */
|
||||
opt = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(int));
|
||||
|
||||
/* bind socket to port */
|
||||
error = bind(sock, (struct sockaddr *)&sa, sa_len);
|
||||
if (error == -1)
|
||||
return SOCK_ERROR;
|
||||
/* reuse it if we can */
|
||||
opt = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(int));
|
||||
|
||||
/* bind socket to port */
|
||||
error = bind(sock, (struct sockaddr *)&sa, sa_len);
|
||||
if (error == -1)
|
||||
return SOCK_ERROR;
|
||||
|
||||
return sock;
|
||||
return sock;
|
||||
}
|
||||
|
||||
int sock_listen(sock_t serversock, int backlog)
|
||||
{
|
||||
if (!sock_valid_socket(serversock))
|
||||
return 0;
|
||||
if (!sock_valid_socket(serversock))
|
||||
return 0;
|
||||
|
||||
if (backlog <= 0)
|
||||
backlog = 10;
|
||||
if (backlog <= 0)
|
||||
backlog = 10;
|
||||
|
||||
return (listen(serversock, backlog) == 0);
|
||||
return (listen(serversock, backlog) == 0);
|
||||
}
|
||||
|
||||
int sock_accept(sock_t serversock, char *ip, int len)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_storage sa;
|
||||
#else
|
||||
struct sockaddr_in sa;
|
||||
struct sockaddr_storage sa;
|
||||
#else
|
||||
struct sockaddr_in sa;
|
||||
#endif
|
||||
int ret;
|
||||
socklen_t slen;
|
||||
int ret;
|
||||
socklen_t slen;
|
||||
|
||||
if (!sock_valid_socket(serversock))
|
||||
return SOCK_ERROR;
|
||||
if (!sock_valid_socket(serversock))
|
||||
return SOCK_ERROR;
|
||||
|
||||
slen = sizeof(sa);
|
||||
ret = accept(serversock, (struct sockaddr *)&sa, &slen);
|
||||
slen = sizeof(sa);
|
||||
ret = accept(serversock, (struct sockaddr *)&sa, &slen);
|
||||
|
||||
if (ret >= 0 && ip != NULL) {
|
||||
if (ret >= 0 && ip != NULL) {
|
||||
#ifdef HAVE_IPV6
|
||||
if(((struct sockaddr_in *)&sa)->sin_family == AF_INET)
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
|
||||
@ -694,12 +694,12 @@ int sock_accept(sock_t serversock, char *ip, int len)
|
||||
}
|
||||
#else
|
||||
/* inet_ntoa is not reentrant, we should protect this */
|
||||
strncpy(ip, inet_ntoa(sa.sin_addr), len);
|
||||
strncpy(ip, inet_ntoa(sa.sin_addr), len);
|
||||
#endif
|
||||
sock_set_nolinger(ret);
|
||||
sock_set_keepalive(ret);
|
||||
}
|
||||
sock_set_nolinger(ret);
|
||||
sock_set_keepalive(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,13 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
char buff[1024];
|
||||
char buff[1024];
|
||||
|
||||
resolver_initialize();
|
||||
resolver_initialize();
|
||||
|
||||
printf("I got %s, when looking up %s.\n", resolver_getip("bach.greenwitch.com", buff, 1024), "bach.greenwitch.com");
|
||||
printf("I got %s, when looking up %s.\n", resolver_getname("207.181.249.14", buff, 1024), "207.181.249.14");
|
||||
printf("I got %s, when looking up %s.\n", resolver_getip("bach.greenwitch.com", buff, 1024), "bach.greenwitch.com");
|
||||
printf("I got %s, when looking up %s.\n", resolver_getname("207.181.249.14", buff, 1024), "207.181.249.14");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
104
src/refbuf.c
104
src/refbuf.c
@ -15,110 +15,110 @@ mutex_t _refbuf_mutex;
|
||||
|
||||
void refbuf_initialize(void)
|
||||
{
|
||||
thread_mutex_create(&_refbuf_mutex);
|
||||
thread_mutex_create(&_refbuf_mutex);
|
||||
}
|
||||
|
||||
void refbuf_shutdown(void)
|
||||
{
|
||||
thread_mutex_destroy(&_refbuf_mutex);
|
||||
thread_mutex_destroy(&_refbuf_mutex);
|
||||
}
|
||||
|
||||
refbuf_t *refbuf_new(unsigned long size)
|
||||
{
|
||||
refbuf_t *refbuf;
|
||||
refbuf_t *refbuf;
|
||||
|
||||
refbuf = (refbuf_t *)malloc(sizeof(refbuf_t));
|
||||
refbuf->data = (void *)malloc(size);
|
||||
refbuf->len = size;
|
||||
refbuf->_count = 1;
|
||||
refbuf = (refbuf_t *)malloc(sizeof(refbuf_t));
|
||||
refbuf->data = (void *)malloc(size);
|
||||
refbuf->len = size;
|
||||
refbuf->_count = 1;
|
||||
|
||||
return refbuf;
|
||||
return refbuf;
|
||||
}
|
||||
|
||||
void refbuf_addref(refbuf_t *self)
|
||||
{
|
||||
thread_mutex_lock(&_refbuf_mutex);
|
||||
self->_count++;
|
||||
thread_mutex_unlock(&_refbuf_mutex);
|
||||
thread_mutex_lock(&_refbuf_mutex);
|
||||
self->_count++;
|
||||
thread_mutex_unlock(&_refbuf_mutex);
|
||||
}
|
||||
|
||||
void refbuf_release(refbuf_t *self)
|
||||
{
|
||||
thread_mutex_lock(&_refbuf_mutex);
|
||||
self->_count--;
|
||||
if (self->_count == 0) {
|
||||
free(self->data);
|
||||
free(self);
|
||||
}
|
||||
thread_mutex_unlock(&_refbuf_mutex);
|
||||
thread_mutex_lock(&_refbuf_mutex);
|
||||
self->_count--;
|
||||
if (self->_count == 0) {
|
||||
free(self->data);
|
||||
free(self);
|
||||
}
|
||||
thread_mutex_unlock(&_refbuf_mutex);
|
||||
}
|
||||
|
||||
void refbuf_queue_add(refbuf_queue_t **queue, refbuf_t *refbuf)
|
||||
{
|
||||
refbuf_queue_t *node;
|
||||
refbuf_queue_t *item = (refbuf_queue_t *)malloc(sizeof(refbuf_queue_t));
|
||||
refbuf_queue_t *node;
|
||||
refbuf_queue_t *item = (refbuf_queue_t *)malloc(sizeof(refbuf_queue_t));
|
||||
|
||||
item->refbuf = refbuf;
|
||||
item->next = NULL;
|
||||
item->refbuf = refbuf;
|
||||
item->next = NULL;
|
||||
|
||||
if (*queue == NULL) {
|
||||
*queue = item;
|
||||
if (*queue == NULL) {
|
||||
*queue = item;
|
||||
(*queue)->total_length = item->refbuf->len;
|
||||
} else {
|
||||
node = *queue;
|
||||
while (node->next) node = node->next;
|
||||
node->next = item;
|
||||
} else {
|
||||
node = *queue;
|
||||
while (node->next) node = node->next;
|
||||
node->next = item;
|
||||
(*queue)->total_length += item->refbuf->len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refbuf_t *refbuf_queue_remove(refbuf_queue_t **queue)
|
||||
{
|
||||
refbuf_queue_t *item;
|
||||
refbuf_t *refbuf;
|
||||
refbuf_queue_t *item;
|
||||
refbuf_t *refbuf;
|
||||
|
||||
if (*queue == NULL) return NULL;
|
||||
if (*queue == NULL) return NULL;
|
||||
|
||||
item = *queue;
|
||||
*queue = item->next;
|
||||
item->next = NULL;
|
||||
item = *queue;
|
||||
*queue = item->next;
|
||||
item->next = NULL;
|
||||
|
||||
refbuf = item->refbuf;
|
||||
item->refbuf = NULL;
|
||||
refbuf = item->refbuf;
|
||||
item->refbuf = NULL;
|
||||
|
||||
if(*queue)
|
||||
(*queue)->total_length = item->total_length - refbuf->len;
|
||||
|
||||
free(item);
|
||||
|
||||
free(item);
|
||||
|
||||
|
||||
return refbuf;
|
||||
return refbuf;
|
||||
}
|
||||
|
||||
void refbuf_queue_insert(refbuf_queue_t **queue, refbuf_t *refbuf)
|
||||
{
|
||||
refbuf_queue_t *item = (refbuf_queue_t *)malloc(sizeof(refbuf_queue_t));
|
||||
refbuf_queue_t *item = (refbuf_queue_t *)malloc(sizeof(refbuf_queue_t));
|
||||
|
||||
item->refbuf = refbuf;
|
||||
item->next = *queue;
|
||||
item->refbuf = refbuf;
|
||||
item->next = *queue;
|
||||
if(item->next)
|
||||
item->total_length = item->next->total_length + item->refbuf->len;
|
||||
else
|
||||
item->total_length = item->refbuf->len;
|
||||
*queue = item;
|
||||
*queue = item;
|
||||
}
|
||||
|
||||
int refbuf_queue_size(refbuf_queue_t **queue)
|
||||
{
|
||||
refbuf_queue_t *node = *queue;
|
||||
int size = 0;
|
||||
refbuf_queue_t *node = *queue;
|
||||
int size = 0;
|
||||
|
||||
while (node) {
|
||||
node = node->next;
|
||||
size++;
|
||||
}
|
||||
|
||||
return size;
|
||||
while (node) {
|
||||
node = node->next;
|
||||
size++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int refbuf_queue_length(refbuf_queue_t **queue)
|
||||
|
12
src/refbuf.h
12
src/refbuf.h
@ -8,18 +8,18 @@
|
||||
|
||||
typedef struct _refbuf_tag
|
||||
{
|
||||
char *data;
|
||||
long len;
|
||||
char *data;
|
||||
long len;
|
||||
|
||||
unsigned long _count;
|
||||
unsigned long _count;
|
||||
} refbuf_t;
|
||||
|
||||
typedef struct _refbuf_queue_tag
|
||||
{
|
||||
refbuf_t *refbuf;
|
||||
refbuf_t *refbuf;
|
||||
long total_length;
|
||||
|
||||
struct _refbuf_queue_tag *next;
|
||||
|
||||
struct _refbuf_queue_tag *next;
|
||||
} refbuf_queue_t;
|
||||
|
||||
void refbuf_initialize(void);
|
||||
|
@ -24,10 +24,10 @@ void _sig_die(int signo);
|
||||
void sighandler_initialize(void)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
signal(SIGHUP, _sig_hup);
|
||||
signal(SIGINT, _sig_die);
|
||||
signal(SIGTERM, _sig_die);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, _sig_hup);
|
||||
signal(SIGINT, _sig_die);
|
||||
signal(SIGTERM, _sig_die);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -40,25 +40,25 @@ void _sig_hup(int signo)
|
||||
* practice.
|
||||
*/
|
||||
|
||||
INFO1("Caught signal %d, scheduling config reread ...",
|
||||
INFO1("Caught signal %d, scheduling config reread ...",
|
||||
signo);
|
||||
|
||||
/* reread config file */
|
||||
/* reread config file */
|
||||
|
||||
connection_inject_event(EVENT_CONFIG_READ, NULL);
|
||||
|
||||
/* reopen logfiles (TODO: We don't do this currently) */
|
||||
/* reopen logfiles (TODO: We don't do this currently) */
|
||||
|
||||
/* some OSes require us to reattach the signal handler */
|
||||
signal(SIGHUP, _sig_hup);
|
||||
/* some OSes require us to reattach the signal handler */
|
||||
signal(SIGHUP, _sig_hup);
|
||||
}
|
||||
|
||||
void _sig_die(int signo)
|
||||
{
|
||||
INFO1("Caught signal %d, shutting down...", signo);
|
||||
INFO1("Caught signal %d, shutting down...", signo);
|
||||
|
||||
/* inform the server to start shutting down */
|
||||
global.running = ICE_HALTING;
|
||||
/* inform the server to start shutting down */
|
||||
global.running = ICE_HALTING;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
94
src/slave.c
94
src/slave.c
@ -50,7 +50,7 @@ static int _initialized = 0;
|
||||
|
||||
void slave_initialize(void) {
|
||||
ice_config_t *config;
|
||||
if (_initialized) return;
|
||||
if (_initialized) return;
|
||||
|
||||
config = config_get_config();
|
||||
/* Don't create a slave thread if it isn't configured */
|
||||
@ -62,23 +62,23 @@ void slave_initialize(void) {
|
||||
}
|
||||
config_release_config();
|
||||
|
||||
_initialized = 1;
|
||||
_slave_thread_id = thread_create("Slave Thread", _slave_thread, NULL, THREAD_ATTACHED);
|
||||
_initialized = 1;
|
||||
_slave_thread_id = thread_create("Slave Thread", _slave_thread, NULL, THREAD_ATTACHED);
|
||||
}
|
||||
|
||||
void slave_shutdown(void) {
|
||||
if (!_initialized) return;
|
||||
_initialized = 0;
|
||||
thread_join(_slave_thread_id);
|
||||
if (!_initialized) return;
|
||||
_initialized = 0;
|
||||
thread_join(_slave_thread_id);
|
||||
}
|
||||
|
||||
static void create_relay_stream(char *server, int port,
|
||||
char *remotemount, char *localmount, int mp3)
|
||||
{
|
||||
sock_t streamsock;
|
||||
char header[4096];
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
char header[4096];
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
client_t *client;
|
||||
|
||||
if(!localmount)
|
||||
@ -86,61 +86,61 @@ static void create_relay_stream(char *server, int port,
|
||||
|
||||
DEBUG1("Adding source at mountpoint \"%s\"", localmount);
|
||||
|
||||
streamsock = sock_connect_wto(server, port, 0);
|
||||
if (streamsock == SOCK_ERROR) {
|
||||
streamsock = sock_connect_wto(server, port, 0);
|
||||
if (streamsock == SOCK_ERROR) {
|
||||
WARN2("Failed to relay stream from master server, couldn't connect to http://%s:%d", server, port);
|
||||
return;
|
||||
}
|
||||
con = create_connection(streamsock, NULL);
|
||||
}
|
||||
con = create_connection(streamsock, NULL);
|
||||
if(mp3) {
|
||||
/* Some mp3 servers are bitchy, send a user-agent string to make them
|
||||
* send the right response.
|
||||
*/
|
||||
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
|
||||
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
|
||||
"User-Agent: " ICECAST_VERSION_STRING "\r\n"
|
||||
"Icy-MetaData: 1\r\n"
|
||||
"\r\n",
|
||||
remotemount);
|
||||
}
|
||||
else {
|
||||
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
|
||||
sock_write(streamsock, "GET %s HTTP/1.0\r\n"
|
||||
"User-Agent: " ICECAST_VERSION_STRING "\r\n"
|
||||
"\r\n",
|
||||
remotemount);
|
||||
}
|
||||
memset(header, 0, sizeof(header));
|
||||
if (util_read_header(con->sock, header, 4096) == 0) {
|
||||
memset(header, 0, sizeof(header));
|
||||
if (util_read_header(con->sock, header, 4096) == 0) {
|
||||
WARN0("Header read failed");
|
||||
connection_close(con);
|
||||
return;
|
||||
}
|
||||
parser = httpp_create_parser();
|
||||
httpp_initialize(parser, NULL);
|
||||
if(!httpp_parse_response(parser, header, strlen(header), localmount)) {
|
||||
connection_close(con);
|
||||
return;
|
||||
}
|
||||
parser = httpp_create_parser();
|
||||
httpp_initialize(parser, NULL);
|
||||
if(!httpp_parse_response(parser, header, strlen(header), localmount)) {
|
||||
if(httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE)) {
|
||||
ERROR1("Error parsing relay request: %s",
|
||||
httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE));
|
||||
}
|
||||
else
|
||||
ERROR0("Error parsing relay request");
|
||||
connection_close(con);
|
||||
connection_close(con);
|
||||
httpp_destroy(parser);
|
||||
return;
|
||||
}
|
||||
|
||||
client = client_create(con, parser);
|
||||
if (!connection_create_source(client, con, parser,
|
||||
if (!connection_create_source(client, con, parser,
|
||||
httpp_getvar(parser, HTTPP_VAR_URI))) {
|
||||
DEBUG0("Failed to create source");
|
||||
client_destroy(client);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void *_slave_thread(void *arg) {
|
||||
sock_t mastersock;
|
||||
char buf[256];
|
||||
sock_t mastersock;
|
||||
char buf[256];
|
||||
int interval;
|
||||
char *authheader, *data;
|
||||
int len;
|
||||
@ -161,9 +161,9 @@ static void *_slave_thread(void *arg) {
|
||||
config_release_config();
|
||||
|
||||
|
||||
while (_initialized) {
|
||||
while (_initialized) {
|
||||
if (max_interval > ++interval) {
|
||||
thread_sleep(1000000);
|
||||
thread_sleep(1000000);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
@ -181,12 +181,12 @@ static void *_slave_thread(void *arg) {
|
||||
int port = config->master_server_port;
|
||||
config_release_config();
|
||||
|
||||
mastersock = sock_connect_wto(server, port, 0);
|
||||
mastersock = sock_connect_wto(server, port, 0);
|
||||
|
||||
if (mastersock == SOCK_ERROR) {
|
||||
if (mastersock == SOCK_ERROR) {
|
||||
WARN0("Relay slave failed to contact master server to fetch stream list");
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
len = strlen(username) + strlen(password) + 1;
|
||||
authheader = malloc(len+1);
|
||||
@ -194,28 +194,28 @@ static void *_slave_thread(void *arg) {
|
||||
strcat(authheader, ":");
|
||||
strcat(authheader, password);
|
||||
data = util_base64_encode(authheader);
|
||||
sock_write(mastersock,
|
||||
sock_write(mastersock,
|
||||
"GET /admin/streamlist HTTP/1.0\r\n"
|
||||
"Authorization: Basic %s\r\n"
|
||||
"\r\n", data);
|
||||
free(authheader);
|
||||
free(data);
|
||||
while (sock_read_line(mastersock, buf, sizeof(buf))) {
|
||||
while (sock_read_line(mastersock, buf, sizeof(buf))) {
|
||||
if(!strlen(buf))
|
||||
break;
|
||||
}
|
||||
|
||||
while (sock_read_line(mastersock, buf, sizeof(buf))) {
|
||||
avl_tree_rlock(global.source_tree);
|
||||
if (!source_find_mount(buf)) {
|
||||
avl_tree_unlock(global.source_tree);
|
||||
while (sock_read_line(mastersock, buf, sizeof(buf))) {
|
||||
avl_tree_rlock(global.source_tree);
|
||||
if (!source_find_mount(buf)) {
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
create_relay_stream(server, port, buf, NULL, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
avl_tree_unlock(global.source_tree);
|
||||
}
|
||||
sock_close(mastersock);
|
||||
avl_tree_unlock(global.source_tree);
|
||||
}
|
||||
sock_close(mastersock);
|
||||
}
|
||||
else {
|
||||
config_release_config();
|
||||
@ -241,8 +241,8 @@ static void *_slave_thread(void *arg) {
|
||||
}
|
||||
|
||||
thread_mutex_unlock(&(config_locks()->relay_lock));
|
||||
}
|
||||
thread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
thread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
622
src/source.c
622
src/source.c
@ -58,20 +58,20 @@ source_t *source_create(client_t *client, connection_t *con,
|
||||
http_parser_t *parser, const char *mount, format_type_t type,
|
||||
mount_proxy *mountinfo)
|
||||
{
|
||||
source_t *src;
|
||||
source_t *src;
|
||||
|
||||
src = (source_t *)malloc(sizeof(source_t));
|
||||
src = (source_t *)malloc(sizeof(source_t));
|
||||
src->client = client;
|
||||
src->mount = (char *)strdup(mount);
|
||||
src->mount = (char *)strdup(mount);
|
||||
src->fallback_mount = NULL;
|
||||
src->format = format_get_plugin(type, src->mount, parser);
|
||||
src->con = con;
|
||||
src->parser = parser;
|
||||
src->client_tree = avl_tree_new(_compare_clients, NULL);
|
||||
src->pending_tree = avl_tree_new(_compare_clients, NULL);
|
||||
src->format = format_get_plugin(type, src->mount, parser);
|
||||
src->con = con;
|
||||
src->parser = parser;
|
||||
src->client_tree = avl_tree_new(_compare_clients, NULL);
|
||||
src->pending_tree = avl_tree_new(_compare_clients, NULL);
|
||||
src->running = 1;
|
||||
src->num_yp_directories = 0;
|
||||
src->listeners = 0;
|
||||
src->num_yp_directories = 0;
|
||||
src->listeners = 0;
|
||||
src->max_listeners = -1;
|
||||
src->send_return = 0;
|
||||
src->dumpfilename = NULL;
|
||||
@ -92,7 +92,7 @@ source_t *source_create(client_t *client, connection_t *con,
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
return src;
|
||||
}
|
||||
|
||||
static int source_remove_source(void *key)
|
||||
@ -105,82 +105,82 @@ static int source_remove_source(void *key)
|
||||
*/
|
||||
source_t *source_find_mount(const char *mount)
|
||||
{
|
||||
source_t *source;
|
||||
avl_node *node;
|
||||
int cmp;
|
||||
source_t *source;
|
||||
avl_node *node;
|
||||
int cmp;
|
||||
|
||||
if (!mount) {
|
||||
return NULL;
|
||||
}
|
||||
/* get the root node */
|
||||
node = global.source_tree->root->right;
|
||||
|
||||
while (node) {
|
||||
source = (source_t *)node->key;
|
||||
cmp = strcmp(mount, source->mount);
|
||||
if (cmp < 0)
|
||||
node = node->left;
|
||||
else if (cmp > 0)
|
||||
node = node->right;
|
||||
else
|
||||
return source;
|
||||
}
|
||||
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
if (!mount) {
|
||||
return NULL;
|
||||
}
|
||||
/* get the root node */
|
||||
node = global.source_tree->root->right;
|
||||
|
||||
while (node) {
|
||||
source = (source_t *)node->key;
|
||||
cmp = strcmp(mount, source->mount);
|
||||
if (cmp < 0)
|
||||
node = node->left;
|
||||
else if (cmp > 0)
|
||||
node = node->right;
|
||||
else
|
||||
return source;
|
||||
}
|
||||
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int source_compare_sources(void *arg, void *a, void *b)
|
||||
{
|
||||
source_t *srca = (source_t *)a;
|
||||
source_t *srcb = (source_t *)b;
|
||||
source_t *srca = (source_t *)a;
|
||||
source_t *srcb = (source_t *)b;
|
||||
|
||||
return strcmp(srca->mount, srcb->mount);
|
||||
return strcmp(srca->mount, srcb->mount);
|
||||
}
|
||||
|
||||
int source_free_source(void *key)
|
||||
{
|
||||
source_t *source = key;
|
||||
int i=0;
|
||||
int i=0;
|
||||
|
||||
free(source->mount);
|
||||
free(source->mount);
|
||||
free(source->fallback_mount);
|
||||
client_destroy(source->client);
|
||||
avl_tree_free(source->pending_tree, _free_client);
|
||||
avl_tree_free(source->client_tree, _free_client);
|
||||
source->format->free_plugin(source->format);
|
||||
avl_tree_free(source->pending_tree, _free_client);
|
||||
avl_tree_free(source->client_tree, _free_client);
|
||||
source->format->free_plugin(source->format);
|
||||
for (i=0; i<source->num_yp_directories; i++) {
|
||||
yp_destroy_ypdata(source->ypdata[i]);
|
||||
}
|
||||
util_dict_free(source->audio_info);
|
||||
free(source);
|
||||
free(source);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The caller MUST have a current write lock on global.source_tree when calling
|
||||
* this
|
||||
*/
|
||||
void *source_main(void *arg)
|
||||
{
|
||||
source_t *source = (source_t *)arg;
|
||||
source_t *source = (source_t *)arg;
|
||||
source_t *fallback_source;
|
||||
char buffer[4096];
|
||||
long bytes, sbytes;
|
||||
int ret, timeout;
|
||||
client_t *client;
|
||||
avl_node *client_node;
|
||||
char *s;
|
||||
long current_time;
|
||||
char current_song[256];
|
||||
char buffer[4096];
|
||||
long bytes, sbytes;
|
||||
int ret, timeout;
|
||||
client_t *client;
|
||||
avl_node *client_node;
|
||||
char *s;
|
||||
long current_time;
|
||||
char current_song[256];
|
||||
|
||||
refbuf_t *refbuf, *abuf;
|
||||
int data_done;
|
||||
refbuf_t *refbuf, *abuf;
|
||||
int data_done;
|
||||
|
||||
int listeners = 0;
|
||||
int i=0;
|
||||
int suppress_yp = 0;
|
||||
int i=0;
|
||||
int suppress_yp = 0;
|
||||
char *ai;
|
||||
|
||||
long queue_limit;
|
||||
@ -191,26 +191,26 @@ void *source_main(void *arg)
|
||||
config = config_get_config();
|
||||
|
||||
queue_limit = config->queue_size_limit;
|
||||
timeout = config->source_timeout;
|
||||
timeout = config->source_timeout;
|
||||
hostname = config->hostname;
|
||||
port = config->port;
|
||||
|
||||
for (i=0;i<config->num_yp_directories;i++) {
|
||||
if (config->yp_url[i]) {
|
||||
source->ypdata[source->num_yp_directories] = yp_create_ypdata();
|
||||
source->ypdata[source->num_yp_directories]->yp_url =
|
||||
for (i=0;i<config->num_yp_directories;i++) {
|
||||
if (config->yp_url[i]) {
|
||||
source->ypdata[source->num_yp_directories] = yp_create_ypdata();
|
||||
source->ypdata[source->num_yp_directories]->yp_url =
|
||||
config->yp_url[i];
|
||||
source->ypdata[source->num_yp_directories]->yp_url_timeout =
|
||||
source->ypdata[source->num_yp_directories]->yp_url_timeout =
|
||||
config->yp_url_timeout[i];
|
||||
source->ypdata[source->num_yp_directories]->yp_touch_interval = 0;
|
||||
source->num_yp_directories++;
|
||||
}
|
||||
}
|
||||
source->ypdata[source->num_yp_directories]->yp_touch_interval = 0;
|
||||
source->num_yp_directories++;
|
||||
}
|
||||
}
|
||||
|
||||
config_release_config();
|
||||
|
||||
/* grab a read lock, to make sure we get a chance to cleanup */
|
||||
thread_rwlock_rlock(source->shutdown_rwlock);
|
||||
/* grab a read lock, to make sure we get a chance to cleanup */
|
||||
thread_rwlock_rlock(source->shutdown_rwlock);
|
||||
|
||||
avl_tree_wlock(global.source_tree);
|
||||
/* Now, we must do a final check with write lock taken out that the
|
||||
@ -224,10 +224,10 @@ void *source_main(void *arg)
|
||||
thread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
/* insert source onto source tree */
|
||||
avl_insert(global.source_tree, (void *)source);
|
||||
/* release write lock on global source tree */
|
||||
avl_tree_unlock(global.source_tree);
|
||||
/* insert source onto source tree */
|
||||
avl_insert(global.source_tree, (void *)source);
|
||||
/* release write lock on global source tree */
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
/* If we connected successfully, we can send the message (if requested)
|
||||
* back
|
||||
@ -239,175 +239,175 @@ void *source_main(void *arg)
|
||||
if(bytes > 0) source->client->con->sent_bytes = bytes;
|
||||
}
|
||||
|
||||
/* start off the statistics */
|
||||
stats_event(source->mount, "listeners", "0");
|
||||
source->listeners = 0;
|
||||
if ((s = httpp_getvar(source->parser, "ice-name"))) {
|
||||
/* start off the statistics */
|
||||
stats_event(source->mount, "listeners", "0");
|
||||
source->listeners = 0;
|
||||
if ((s = httpp_getvar(source->parser, "ice-name"))) {
|
||||
_add_yp_info(source, "server_name", s, YP_SERVER_NAME);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-url"))) {
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-url"))) {
|
||||
_add_yp_info(source, "server_url", s, YP_SERVER_URL);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-genre"))) {
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-genre"))) {
|
||||
_add_yp_info(source, "genre", s, YP_SERVER_GENRE);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-bitrate"))) {
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-bitrate"))) {
|
||||
_add_yp_info(source, "bitrate", s, YP_BITRATE);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-description"))) {
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-description"))) {
|
||||
_add_yp_info(source, "server_description", s, YP_SERVER_DESC);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-private"))) {
|
||||
stats_event(source->mount, "public", s);
|
||||
suppress_yp = atoi(s);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-audio-info"))) {
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-private"))) {
|
||||
stats_event(source->mount, "public", s);
|
||||
suppress_yp = atoi(s);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-audio-info"))) {
|
||||
if (_parse_audio_info(source, s)) {
|
||||
ai = util_dict_urlencode(source->audio_info, '&');
|
||||
_add_yp_info(source, "audio_info",
|
||||
ai,
|
||||
YP_AUDIO_INFO);
|
||||
}
|
||||
}
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_type) {
|
||||
free(source->ypdata[i]->server_type);
|
||||
}
|
||||
source->ypdata[i]->server_type = malloc(
|
||||
}
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_type) {
|
||||
free(source->ypdata[i]->server_type);
|
||||
}
|
||||
source->ypdata[i]->server_type = malloc(
|
||||
strlen(source->format->format_description) + 1);
|
||||
strcpy(source->ypdata[i]->server_type,
|
||||
strcpy(source->ypdata[i]->server_type,
|
||||
source->format->format_description);
|
||||
}
|
||||
}
|
||||
stats_event(source->mount, "type", source->format->format_description);
|
||||
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
int listen_url_size;
|
||||
if (source->ypdata[i]->listen_url) {
|
||||
free(source->ypdata[i]->listen_url);
|
||||
}
|
||||
/* 6 for max size of port */
|
||||
listen_url_size = strlen("http://") +
|
||||
if (source->ypdata[i]->listen_url) {
|
||||
free(source->ypdata[i]->listen_url);
|
||||
}
|
||||
/* 6 for max size of port */
|
||||
listen_url_size = strlen("http://") +
|
||||
strlen(hostname) +
|
||||
strlen(":") + 6 + strlen(source->mount) + 1;
|
||||
source->ypdata[i]->listen_url = malloc(listen_url_size);
|
||||
sprintf(source->ypdata[i]->listen_url, "http://%s:%d%s",
|
||||
source->ypdata[i]->listen_url = malloc(listen_url_size);
|
||||
sprintf(source->ypdata[i]->listen_url, "http://%s:%d%s",
|
||||
hostname, port, source->mount);
|
||||
}
|
||||
}
|
||||
|
||||
if(!suppress_yp) {
|
||||
if(!suppress_yp) {
|
||||
yp_add(source, YP_ADD_ALL);
|
||||
|
||||
current_time = time(NULL);
|
||||
current_time = time(NULL);
|
||||
|
||||
_add_yp_info(source, "last_touch", (void *)current_time,
|
||||
YP_LAST_TOUCH);
|
||||
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
/* Give the source 5 seconds to update the metadata
|
||||
before we do our first touch */
|
||||
source->ypdata[i]->yp_last_touch = current_time -
|
||||
source->ypdata[i]->yp_touch_interval + 5;
|
||||
/* Don't permit touch intervals of less than 30 seconds */
|
||||
if (source->ypdata[i]->yp_touch_interval <= 30) {
|
||||
source->ypdata[i]->yp_touch_interval = 30;
|
||||
}
|
||||
}
|
||||
if (source->ypdata[i]->yp_touch_interval <= 30) {
|
||||
source->ypdata[i]->yp_touch_interval = 30;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG0("Source creation complete");
|
||||
|
||||
while (global.running == ICE_RUNNING && source->running) {
|
||||
if(!suppress_yp) {
|
||||
while (global.running == ICE_RUNNING && source->running) {
|
||||
if(!suppress_yp) {
|
||||
current_time = time(NULL);
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (current_time > (source->ypdata[i]->yp_last_touch +
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (current_time > (source->ypdata[i]->yp_last_touch +
|
||||
source->ypdata[i]->yp_touch_interval)) {
|
||||
current_song[0] = 0;
|
||||
if (stats_get_value(source->mount, "artist")) {
|
||||
strncat(current_song,
|
||||
if (stats_get_value(source->mount, "artist")) {
|
||||
strncat(current_song,
|
||||
stats_get_value(source->mount, "artist"),
|
||||
sizeof(current_song) - 1);
|
||||
if (strlen(current_song) + 4 < sizeof(current_song)) {
|
||||
strncat(current_song, " - ", 3);
|
||||
}
|
||||
}
|
||||
if (stats_get_value(source->mount, "title")) {
|
||||
if (strlen(current_song) +
|
||||
if (strlen(current_song) + 4 < sizeof(current_song)) {
|
||||
strncat(current_song, " - ", 3);
|
||||
}
|
||||
}
|
||||
if (stats_get_value(source->mount, "title")) {
|
||||
if (strlen(current_song) +
|
||||
strlen(stats_get_value(source->mount, "title"))
|
||||
< sizeof(current_song) -1)
|
||||
{
|
||||
strncat(current_song,
|
||||
strncat(current_song,
|
||||
stats_get_value(source->mount, "title"),
|
||||
sizeof(current_song) - 1 -
|
||||
strlen(current_song));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source->ypdata[i]->current_song) {
|
||||
free(source->ypdata[i]->current_song);
|
||||
source->ypdata[i]->current_song = NULL;
|
||||
}
|
||||
|
||||
source->ypdata[i]->current_song =
|
||||
if (source->ypdata[i]->current_song) {
|
||||
free(source->ypdata[i]->current_song);
|
||||
source->ypdata[i]->current_song = NULL;
|
||||
}
|
||||
|
||||
source->ypdata[i]->current_song =
|
||||
malloc(strlen(current_song) + 1);
|
||||
strcpy(source->ypdata[i]->current_song, current_song);
|
||||
|
||||
thread_create("YP Touch Thread", yp_touch_thread,
|
||||
strcpy(source->ypdata[i]->current_song, current_song);
|
||||
|
||||
thread_create("YP Touch Thread", yp_touch_thread,
|
||||
(void *)source, THREAD_DETACHED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = source->format->get_buffer(source->format, NULL, 0, &refbuf);
|
||||
ret = source->format->get_buffer(source->format, NULL, 0, &refbuf);
|
||||
if(ret < 0) {
|
||||
WARN0("Bad data from source");
|
||||
break;
|
||||
}
|
||||
bytes = 1; /* Set to > 0 so that the post-loop check won't be tripped */
|
||||
while (refbuf == NULL) {
|
||||
bytes = 0;
|
||||
while (bytes <= 0) {
|
||||
while (refbuf == NULL) {
|
||||
bytes = 0;
|
||||
while (bytes <= 0) {
|
||||
ret = util_timed_wait_for_fd(source->con->sock, timeout*1000);
|
||||
|
||||
if (ret <= 0) { /* timeout expired */
|
||||
if (ret <= 0) { /* timeout expired */
|
||||
WARN1("Disconnecting source: socket timeout (%d s) expired",
|
||||
timeout);
|
||||
bytes = 0;
|
||||
break;
|
||||
}
|
||||
bytes = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
bytes = sock_read_bytes(source->con->sock, buffer, 4096);
|
||||
if (bytes == 0 || (bytes < 0 && !sock_recoverable(sock_error()))) {
|
||||
bytes = sock_read_bytes(source->con->sock, buffer, 4096);
|
||||
if (bytes == 0 || (bytes < 0 && !sock_recoverable(sock_error()))) {
|
||||
DEBUG1("Disconnecting source due to socket read error: %s",
|
||||
strerror(sock_error()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bytes <= 0) break;
|
||||
}
|
||||
if (bytes <= 0) break;
|
||||
source->client->con->sent_bytes += bytes;
|
||||
ret = source->format->get_buffer(source->format, buffer, bytes, &refbuf);
|
||||
ret = source->format->get_buffer(source->format, buffer, bytes, &refbuf);
|
||||
if(ret < 0) {
|
||||
WARN0("Bad data from source");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes <= 0) {
|
||||
INFO0("Removing source following disconnection");
|
||||
break;
|
||||
}
|
||||
if (bytes <= 0) {
|
||||
INFO0("Removing source following disconnection");
|
||||
break;
|
||||
}
|
||||
|
||||
/* we have a refbuf buffer, which a data block to be sent to
|
||||
** all clients. if a client is not able to send the buffer
|
||||
** immediately, it should store it on its queue for the next
|
||||
** go around.
|
||||
**
|
||||
** instead of sending the current block, a client should send
|
||||
** all data in the queue, plus the current block, until either
|
||||
** it runs out of data, or it hits a recoverable error like
|
||||
** EAGAIN. this will allow a client that got slightly lagged
|
||||
** to catch back up if it can
|
||||
*/
|
||||
/* we have a refbuf buffer, which a data block to be sent to
|
||||
** all clients. if a client is not able to send the buffer
|
||||
** immediately, it should store it on its queue for the next
|
||||
** go around.
|
||||
**
|
||||
** instead of sending the current block, a client should send
|
||||
** all data in the queue, plus the current block, until either
|
||||
** it runs out of data, or it hits a recoverable error like
|
||||
** EAGAIN. this will allow a client that got slightly lagged
|
||||
** to catch back up if it can
|
||||
*/
|
||||
|
||||
/* First, stream dumping, if enabled */
|
||||
if(source->dumpfile) {
|
||||
@ -421,29 +421,29 @@ void *source_main(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* acquire read lock on client_tree */
|
||||
avl_tree_rlock(source->client_tree);
|
||||
/* acquire read lock on client_tree */
|
||||
avl_tree_rlock(source->client_tree);
|
||||
|
||||
client_node = avl_get_first(source->client_tree);
|
||||
while (client_node) {
|
||||
/* acquire read lock on node */
|
||||
avl_node_wlock(client_node);
|
||||
client_node = avl_get_first(source->client_tree);
|
||||
while (client_node) {
|
||||
/* acquire read lock on node */
|
||||
avl_node_wlock(client_node);
|
||||
|
||||
client = (client_t *)client_node->key;
|
||||
|
||||
data_done = 0;
|
||||
client = (client_t *)client_node->key;
|
||||
|
||||
data_done = 0;
|
||||
|
||||
/* do we have any old buffers? */
|
||||
abuf = refbuf_queue_remove(&client->queue);
|
||||
while (abuf) {
|
||||
if (client->pos > 0)
|
||||
bytes = abuf->len - client->pos;
|
||||
else
|
||||
bytes = abuf->len;
|
||||
/* do we have any old buffers? */
|
||||
abuf = refbuf_queue_remove(&client->queue);
|
||||
while (abuf) {
|
||||
if (client->pos > 0)
|
||||
bytes = abuf->len - client->pos;
|
||||
else
|
||||
bytes = abuf->len;
|
||||
|
||||
sbytes = source->format->write_buf_to_client(source->format,
|
||||
sbytes = source->format->write_buf_to_client(source->format,
|
||||
client, &abuf->data[client->pos], bytes);
|
||||
if (sbytes >= 0) {
|
||||
if (sbytes >= 0) {
|
||||
if(sbytes != bytes) {
|
||||
/* We didn't send the entire buffer. Leave it for
|
||||
* the moment, handle it in the next iteration.
|
||||
@ -457,121 +457,121 @@ void *source_main(void *arg)
|
||||
else {
|
||||
DEBUG0("Client has unrecoverable error catching up. Client has probably disconnected");
|
||||
client->con->error = 1;
|
||||
data_done = 1;
|
||||
data_done = 1;
|
||||
refbuf_release(abuf);
|
||||
break;
|
||||
}
|
||||
|
||||
/* we're done with that refbuf, release it and reset the pos */
|
||||
refbuf_release(abuf);
|
||||
client->pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* we're done with that refbuf, release it and reset the pos */
|
||||
refbuf_release(abuf);
|
||||
client->pos = 0;
|
||||
|
||||
abuf = refbuf_queue_remove(&client->queue);
|
||||
}
|
||||
|
||||
/* now send or queue the new data */
|
||||
if (data_done) {
|
||||
refbuf_addref(refbuf);
|
||||
refbuf_queue_add(&client->queue, refbuf);
|
||||
} else {
|
||||
sbytes = source->format->write_buf_to_client(source->format,
|
||||
abuf = refbuf_queue_remove(&client->queue);
|
||||
}
|
||||
|
||||
/* now send or queue the new data */
|
||||
if (data_done) {
|
||||
refbuf_addref(refbuf);
|
||||
refbuf_queue_add(&client->queue, refbuf);
|
||||
} else {
|
||||
sbytes = source->format->write_buf_to_client(source->format,
|
||||
client, refbuf->data, refbuf->len);
|
||||
if (sbytes >= 0) {
|
||||
if (sbytes >= 0) {
|
||||
if(sbytes != refbuf->len) {
|
||||
/* Didn't send the entire buffer, queue it */
|
||||
client->pos = sbytes;
|
||||
refbuf_addref(refbuf);
|
||||
refbuf_addref(refbuf);
|
||||
refbuf_queue_insert(&client->queue, refbuf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG0("Client had unrecoverable error with new data, probably due to client disconnection");
|
||||
client->con->error = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if the client is too slow, its queue will slowly build up.
|
||||
** we need to make sure the client is keeping up with the
|
||||
** data, so we'll kick any client who's queue gets to large.
|
||||
*/
|
||||
if (refbuf_queue_length(&client->queue) > queue_limit) {
|
||||
/* if the client is too slow, its queue will slowly build up.
|
||||
** we need to make sure the client is keeping up with the
|
||||
** data, so we'll kick any client who's queue gets to large.
|
||||
*/
|
||||
if (refbuf_queue_length(&client->queue) > queue_limit) {
|
||||
DEBUG0("Client has fallen too far behind, removing");
|
||||
client->con->error = 1;
|
||||
}
|
||||
client->con->error = 1;
|
||||
}
|
||||
|
||||
/* release read lock on node */
|
||||
avl_node_unlock(client_node);
|
||||
/* release read lock on node */
|
||||
avl_node_unlock(client_node);
|
||||
|
||||
/* get the next node */
|
||||
client_node = avl_get_next(client_node);
|
||||
}
|
||||
/* release read lock on client_tree */
|
||||
avl_tree_unlock(source->client_tree);
|
||||
/* get the next node */
|
||||
client_node = avl_get_next(client_node);
|
||||
}
|
||||
/* release read lock on client_tree */
|
||||
avl_tree_unlock(source->client_tree);
|
||||
|
||||
refbuf_release(refbuf);
|
||||
refbuf_release(refbuf);
|
||||
|
||||
/* acquire write lock on client_tree */
|
||||
avl_tree_wlock(source->client_tree);
|
||||
/* acquire write lock on client_tree */
|
||||
avl_tree_wlock(source->client_tree);
|
||||
|
||||
/** delete bad clients **/
|
||||
client_node = avl_get_first(source->client_tree);
|
||||
while (client_node) {
|
||||
client = (client_t *)client_node->key;
|
||||
if (client->con->error) {
|
||||
client_node = avl_get_next(client_node);
|
||||
avl_delete(source->client_tree, (void *)client, _free_client);
|
||||
listeners--;
|
||||
stats_event_args(source->mount, "listeners", "%d", listeners);
|
||||
source->listeners = listeners;
|
||||
/** delete bad clients **/
|
||||
client_node = avl_get_first(source->client_tree);
|
||||
while (client_node) {
|
||||
client = (client_t *)client_node->key;
|
||||
if (client->con->error) {
|
||||
client_node = avl_get_next(client_node);
|
||||
avl_delete(source->client_tree, (void *)client, _free_client);
|
||||
listeners--;
|
||||
stats_event_args(source->mount, "listeners", "%d", listeners);
|
||||
source->listeners = listeners;
|
||||
DEBUG0("Client removed");
|
||||
continue;
|
||||
}
|
||||
client_node = avl_get_next(client_node);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
client_node = avl_get_next(client_node);
|
||||
}
|
||||
|
||||
/* acquire write lock on pending_tree */
|
||||
avl_tree_wlock(source->pending_tree);
|
||||
/* acquire write lock on pending_tree */
|
||||
avl_tree_wlock(source->pending_tree);
|
||||
|
||||
/** add pending clients **/
|
||||
client_node = avl_get_first(source->pending_tree);
|
||||
while (client_node) {
|
||||
avl_insert(source->client_tree, client_node->key);
|
||||
listeners++;
|
||||
/** add pending clients **/
|
||||
client_node = avl_get_first(source->pending_tree);
|
||||
while (client_node) {
|
||||
avl_insert(source->client_tree, client_node->key);
|
||||
listeners++;
|
||||
DEBUG0("Client added");
|
||||
stats_event_inc(NULL, "clients");
|
||||
stats_event_inc(source->mount, "connections");
|
||||
stats_event_args(source->mount, "listeners", "%d", listeners);
|
||||
source->listeners = listeners;
|
||||
stats_event_inc(NULL, "clients");
|
||||
stats_event_inc(source->mount, "connections");
|
||||
stats_event_args(source->mount, "listeners", "%d", listeners);
|
||||
source->listeners = listeners;
|
||||
|
||||
/* we have to send cached headers for some data formats
|
||||
** this is where we queue up the buffers to send
|
||||
*/
|
||||
if (source->format->has_predata) {
|
||||
client = (client_t *)client_node->key;
|
||||
client->queue = source->format->get_predata(source->format);
|
||||
}
|
||||
/* we have to send cached headers for some data formats
|
||||
** this is where we queue up the buffers to send
|
||||
*/
|
||||
if (source->format->has_predata) {
|
||||
client = (client_t *)client_node->key;
|
||||
client->queue = source->format->get_predata(source->format);
|
||||
}
|
||||
|
||||
client_node = avl_get_next(client_node);
|
||||
}
|
||||
client_node = avl_get_next(client_node);
|
||||
}
|
||||
|
||||
/** clear pending tree **/
|
||||
while (avl_get_first(source->pending_tree)) {
|
||||
avl_delete(source->pending_tree, avl_get_first(source->pending_tree)->key, source_remove_client);
|
||||
}
|
||||
/** clear pending tree **/
|
||||
while (avl_get_first(source->pending_tree)) {
|
||||
avl_delete(source->pending_tree, avl_get_first(source->pending_tree)->key, source_remove_client);
|
||||
}
|
||||
|
||||
/* release write lock on pending_tree */
|
||||
avl_tree_unlock(source->pending_tree);
|
||||
/* release write lock on pending_tree */
|
||||
avl_tree_unlock(source->pending_tree);
|
||||
|
||||
/* release write lock on client_tree */
|
||||
avl_tree_unlock(source->client_tree);
|
||||
}
|
||||
/* release write lock on client_tree */
|
||||
avl_tree_unlock(source->client_tree);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
DEBUG0("Source exiting");
|
||||
if(!suppress_yp) {
|
||||
yp_remove(source);
|
||||
}
|
||||
if(!suppress_yp) {
|
||||
yp_remove(source);
|
||||
}
|
||||
|
||||
avl_tree_rlock(global.source_tree);
|
||||
fallback_source = source_find_mount(source->fallback_mount);
|
||||
@ -581,13 +581,13 @@ done:
|
||||
* removing the clients, otherwise new clients can sneak into the pending
|
||||
* tree after we've cleared it
|
||||
*/
|
||||
avl_tree_wlock(global.source_tree);
|
||||
avl_delete(global.source_tree, source, source_remove_source);
|
||||
avl_tree_unlock(global.source_tree);
|
||||
avl_tree_wlock(global.source_tree);
|
||||
avl_delete(global.source_tree, source, source_remove_source);
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
/* we need to empty the client and pending trees */
|
||||
avl_tree_wlock(source->pending_tree);
|
||||
while (avl_get_first(source->pending_tree)) {
|
||||
/* we need to empty the client and pending trees */
|
||||
avl_tree_wlock(source->pending_tree);
|
||||
while (avl_get_first(source->pending_tree)) {
|
||||
client_t *client = (client_t *)avl_get_first(
|
||||
source->pending_tree)->key;
|
||||
if(fallback_source) {
|
||||
@ -599,13 +599,13 @@ done:
|
||||
avl_tree_unlock(fallback_source->pending_tree);
|
||||
}
|
||||
else {
|
||||
avl_delete(source->pending_tree, client, _free_client);
|
||||
avl_delete(source->pending_tree, client, _free_client);
|
||||
}
|
||||
}
|
||||
avl_tree_unlock(source->pending_tree);
|
||||
}
|
||||
avl_tree_unlock(source->pending_tree);
|
||||
|
||||
avl_tree_wlock(source->client_tree);
|
||||
while (avl_get_first(source->client_tree)) {
|
||||
avl_tree_wlock(source->client_tree);
|
||||
while (avl_get_first(source->client_tree)) {
|
||||
client_t *client = (client_t *)avl_get_first(source->client_tree)->key;
|
||||
|
||||
if(fallback_source) {
|
||||
@ -617,60 +617,60 @@ done:
|
||||
avl_tree_unlock(fallback_source->pending_tree);
|
||||
}
|
||||
else {
|
||||
avl_delete(source->client_tree, client, _free_client);
|
||||
avl_delete(source->client_tree, client, _free_client);
|
||||
}
|
||||
}
|
||||
avl_tree_unlock(source->client_tree);
|
||||
}
|
||||
avl_tree_unlock(source->client_tree);
|
||||
|
||||
/* delete this sources stats */
|
||||
stats_event_dec(NULL, "sources");
|
||||
stats_event(source->mount, "listeners", NULL);
|
||||
/* delete this sources stats */
|
||||
stats_event_dec(NULL, "sources");
|
||||
stats_event(source->mount, "listeners", NULL);
|
||||
|
||||
global_lock();
|
||||
global.sources--;
|
||||
global_unlock();
|
||||
global_lock();
|
||||
global.sources--;
|
||||
global_unlock();
|
||||
|
||||
if(source->dumpfile)
|
||||
fclose(source->dumpfile);
|
||||
|
||||
source_free_source(source);
|
||||
|
||||
/* release our hold on the lock so the main thread can continue cleaning up */
|
||||
thread_rwlock_unlock(source->shutdown_rwlock);
|
||||
/* release our hold on the lock so the main thread can continue cleaning up */
|
||||
thread_rwlock_unlock(source->shutdown_rwlock);
|
||||
|
||||
thread_exit(0);
|
||||
thread_exit(0);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _compare_clients(void *compare_arg, void *a, void *b)
|
||||
{
|
||||
connection_t *cona = (connection_t *)a;
|
||||
connection_t *cona = (connection_t *)a;
|
||||
connection_t *conb = (connection_t *)b;
|
||||
|
||||
if (cona->id < conb->id) return -1;
|
||||
if (cona->id > conb->id) return 1;
|
||||
if (cona->id < conb->id) return -1;
|
||||
if (cona->id > conb->id) return 1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int source_remove_client(void *key)
|
||||
{
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _free_client(void *key)
|
||||
{
|
||||
client_t *client = (client_t *)key;
|
||||
client_t *client = (client_t *)key;
|
||||
|
||||
global_lock();
|
||||
global.clients--;
|
||||
global_unlock();
|
||||
stats_event_dec(NULL, "clients");
|
||||
|
||||
client_destroy(client);
|
||||
|
||||
return 1;
|
||||
global_lock();
|
||||
global.clients--;
|
||||
global_unlock();
|
||||
stats_event_dec(NULL, "clients");
|
||||
|
||||
client_destroy(client);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_audio_info(source_t *source, char *s)
|
||||
@ -684,7 +684,7 @@ static int _parse_audio_info(source_t *source, char *s)
|
||||
pvar = strchr(token, '=');
|
||||
if (pvar) {
|
||||
variable = (char *)malloc(pvar-token+1);
|
||||
strncpy(variable, token, pvar-token);
|
||||
strncpy(variable, token, pvar-token);
|
||||
pvar++;
|
||||
if (strlen(pvar)) {
|
||||
value = util_url_unescape(pvar);
|
||||
|
22
src/source.h
22
src/source.h
@ -11,10 +11,10 @@
|
||||
typedef struct source_tag
|
||||
{
|
||||
client_t *client;
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
|
||||
char *mount;
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
|
||||
char *mount;
|
||||
|
||||
/* If this source drops, try to move all clients to this fallback */
|
||||
char *fallback_mount;
|
||||
@ -23,20 +23,20 @@ typedef struct source_tag
|
||||
* shutdown */
|
||||
int running;
|
||||
|
||||
struct _format_plugin_tag *format;
|
||||
struct _format_plugin_tag *format;
|
||||
|
||||
avl_tree *client_tree;
|
||||
avl_tree *pending_tree;
|
||||
avl_tree *client_tree;
|
||||
avl_tree *pending_tree;
|
||||
|
||||
rwlock_t *shutdown_rwlock;
|
||||
ypdata_t *ypdata[MAX_YP_DIRECTORIES];
|
||||
rwlock_t *shutdown_rwlock;
|
||||
ypdata_t *ypdata[MAX_YP_DIRECTORIES];
|
||||
util_dict *audio_info;
|
||||
|
||||
char *dumpfilename; /* Name of a file to dump incoming stream to */
|
||||
FILE *dumpfile;
|
||||
|
||||
int num_yp_directories;
|
||||
long listeners;
|
||||
int num_yp_directories;
|
||||
long listeners;
|
||||
long max_listeners;
|
||||
int send_return;
|
||||
} source_t;
|
||||
|
1118
src/stats.c
1118
src/stats.c
File diff suppressed because it is too large
Load Diff
52
src/stats.h
52
src/stats.h
@ -11,52 +11,52 @@
|
||||
|
||||
typedef struct _stats_connection_tag
|
||||
{
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
connection_t *con;
|
||||
http_parser_t *parser;
|
||||
} stats_connection_t;
|
||||
|
||||
typedef struct _stats_node_tag
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
char *name;
|
||||
char *value;
|
||||
} stats_node_t;
|
||||
|
||||
typedef struct _stats_event_tag
|
||||
{
|
||||
char *source;
|
||||
char *name;
|
||||
char *value;
|
||||
char *source;
|
||||
char *name;
|
||||
char *value;
|
||||
|
||||
struct _stats_event_tag *next;
|
||||
struct _stats_event_tag *next;
|
||||
} stats_event_t;
|
||||
|
||||
typedef struct _stats_source_tag
|
||||
{
|
||||
char *source;
|
||||
avl_tree *stats_tree;
|
||||
char *source;
|
||||
avl_tree *stats_tree;
|
||||
} stats_source_t;
|
||||
|
||||
typedef struct _stats_tag
|
||||
{
|
||||
avl_tree *global_tree;
|
||||
avl_tree *global_tree;
|
||||
|
||||
/* global stats
|
||||
start_time
|
||||
total_users
|
||||
max_users
|
||||
total_sources
|
||||
max_sources
|
||||
total_user_connections
|
||||
total_source_connections
|
||||
*/
|
||||
/* global stats
|
||||
start_time
|
||||
total_users
|
||||
max_users
|
||||
total_sources
|
||||
max_sources
|
||||
total_user_connections
|
||||
total_source_connections
|
||||
*/
|
||||
|
||||
avl_tree *source_tree;
|
||||
avl_tree *source_tree;
|
||||
|
||||
/* stats by source, and for stats
|
||||
start_time
|
||||
total_users
|
||||
max_users
|
||||
*/
|
||||
/* stats by source, and for stats
|
||||
start_time
|
||||
total_users
|
||||
max_users
|
||||
*/
|
||||
|
||||
} stats_t;
|
||||
|
||||
|
@ -74,18 +74,18 @@
|
||||
|
||||
/* thread starting structure */
|
||||
typedef struct thread_start_tag {
|
||||
/* the real start routine and arg */
|
||||
void *(*start_routine)(void *);
|
||||
void *arg;
|
||||
/* the real start routine and arg */
|
||||
void *(*start_routine)(void *);
|
||||
void *arg;
|
||||
|
||||
/* whether to create the threaded in detached state */
|
||||
int detached;
|
||||
/* whether to create the threaded in detached state */
|
||||
int detached;
|
||||
|
||||
/* the other stuff we need to make sure this thread is inserted into
|
||||
** the thread tree
|
||||
*/
|
||||
thread_type *thread;
|
||||
pthread_t sys_thread;
|
||||
/* the other stuff we need to make sure this thread is inserted into
|
||||
** the thread tree
|
||||
*/
|
||||
thread_type *thread;
|
||||
pthread_t sys_thread;
|
||||
} thread_start_t;
|
||||
|
||||
static long _next_thread_id = 0;
|
||||
@ -143,69 +143,69 @@ static void _block_signals(void);
|
||||
|
||||
void thread_initialize(void)
|
||||
{
|
||||
thread_type *thread;
|
||||
thread_type *thread;
|
||||
|
||||
/* set up logging */
|
||||
/* set up logging */
|
||||
|
||||
#ifdef THREAD_DEBUG
|
||||
log_initialize();
|
||||
_logid = log_open("thread.log");
|
||||
log_set_level(_logid, THREAD_DEBUG);
|
||||
log_initialize();
|
||||
_logid = log_open("thread.log");
|
||||
log_set_level(_logid, THREAD_DEBUG);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_MUTEXES
|
||||
/* create all the internal mutexes, and initialize the mutex tree */
|
||||
/* create all the internal mutexes, and initialize the mutex tree */
|
||||
|
||||
_mutextree = avl_tree_new(_compare_mutexes, NULL);
|
||||
_mutextree = avl_tree_new(_compare_mutexes, NULL);
|
||||
|
||||
/* we have to create this one by hand, because there's no
|
||||
** mutextree_mutex to lock yet!
|
||||
*/
|
||||
_mutex_create(&_mutextree_mutex);
|
||||
/* we have to create this one by hand, because there's no
|
||||
** mutextree_mutex to lock yet!
|
||||
*/
|
||||
_mutex_create(&_mutextree_mutex);
|
||||
|
||||
_mutextree_mutex.mutex_id = _next_mutex_id++;
|
||||
avl_insert(_mutextree, (void *)&_mutextree_mutex);
|
||||
_mutextree_mutex.mutex_id = _next_mutex_id++;
|
||||
avl_insert(_mutextree, (void *)&_mutextree_mutex);
|
||||
#endif
|
||||
|
||||
thread_mutex_create(&_threadtree_mutex);
|
||||
thread_mutex_create(&_library_mutex);
|
||||
thread_mutex_create(&_threadtree_mutex);
|
||||
thread_mutex_create(&_library_mutex);
|
||||
|
||||
/* initialize the thread tree and insert the main thread */
|
||||
/* initialize the thread tree and insert the main thread */
|
||||
|
||||
_threadtree = avl_tree_new(_compare_threads, NULL);
|
||||
_threadtree = avl_tree_new(_compare_threads, NULL);
|
||||
|
||||
thread = (thread_type *)malloc(sizeof(thread_type));
|
||||
thread = (thread_type *)malloc(sizeof(thread_type));
|
||||
|
||||
thread->thread_id = _next_thread_id++;
|
||||
thread->line = 0;
|
||||
thread->file = strdup("main.c");
|
||||
thread->sys_thread = pthread_self();
|
||||
thread->create_time = time(NULL);
|
||||
thread->name = strdup("Main Thread");
|
||||
thread->thread_id = _next_thread_id++;
|
||||
thread->line = 0;
|
||||
thread->file = strdup("main.c");
|
||||
thread->sys_thread = pthread_self();
|
||||
thread->create_time = time(NULL);
|
||||
thread->name = strdup("Main Thread");
|
||||
|
||||
avl_insert(_threadtree, (void *)thread);
|
||||
avl_insert(_threadtree, (void *)thread);
|
||||
|
||||
_catch_signals();
|
||||
_catch_signals();
|
||||
|
||||
_initialized = 1;
|
||||
_initialized = 1;
|
||||
}
|
||||
|
||||
void thread_shutdown(void)
|
||||
{
|
||||
if (_initialized == 1) {
|
||||
thread_mutex_destroy(&_library_mutex);
|
||||
thread_mutex_destroy(&_threadtree_mutex);
|
||||
if (_initialized == 1) {
|
||||
thread_mutex_destroy(&_library_mutex);
|
||||
thread_mutex_destroy(&_threadtree_mutex);
|
||||
#ifdef THREAD_DEBUG
|
||||
thread_mutex_destroy(&_mutextree_mutex);
|
||||
|
||||
avl_tree_free(_mutextree, _free_mutex);
|
||||
thread_mutex_destroy(&_mutextree_mutex);
|
||||
|
||||
avl_tree_free(_mutextree, _free_mutex);
|
||||
#endif
|
||||
avl_tree_free(_threadtree, _free_thread);
|
||||
}
|
||||
avl_tree_free(_threadtree, _free_thread);
|
||||
}
|
||||
|
||||
#ifdef THREAD_DEBUG
|
||||
log_close(_logid);
|
||||
log_shutdown();
|
||||
log_close(_logid);
|
||||
log_shutdown();
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -268,44 +268,44 @@ static void _catch_signals(void)
|
||||
thread_type *thread_create_c(char *name, void *(*start_routine)(void *),
|
||||
void *arg, int detached, int line, char *file)
|
||||
{
|
||||
int created;
|
||||
thread_type *thread;
|
||||
thread_start_t *start;
|
||||
int created;
|
||||
thread_type *thread;
|
||||
thread_start_t *start;
|
||||
|
||||
thread = (thread_type *)malloc(sizeof(thread_type));
|
||||
start = (thread_start_t *)malloc(sizeof(thread_start_t));
|
||||
thread->line = line;
|
||||
thread->file = strdup(file);
|
||||
thread = (thread_type *)malloc(sizeof(thread_type));
|
||||
start = (thread_start_t *)malloc(sizeof(thread_start_t));
|
||||
thread->line = line;
|
||||
thread->file = strdup(file);
|
||||
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
thread->thread_id = _next_thread_id++;
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
thread->thread_id = _next_thread_id++;
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
|
||||
thread->name = strdup(name);
|
||||
thread->create_time = time(NULL);
|
||||
thread->name = strdup(name);
|
||||
thread->create_time = time(NULL);
|
||||
thread->detached = 0;
|
||||
|
||||
start->start_routine = start_routine;
|
||||
start->arg = arg;
|
||||
start->thread = thread;
|
||||
start->detached = detached;
|
||||
start->start_routine = start_routine;
|
||||
start->arg = arg;
|
||||
start->thread = thread;
|
||||
start->detached = detached;
|
||||
|
||||
created = 0;
|
||||
if (pthread_create(&thread->sys_thread, NULL, _start_routine, start) == 0)
|
||||
created = 1;
|
||||
created = 0;
|
||||
if (pthread_create(&thread->sys_thread, NULL, _start_routine, start) == 0)
|
||||
created = 1;
|
||||
#ifdef THREAD_DEBUG
|
||||
else
|
||||
LOG_ERROR("Could not create new thread");
|
||||
else
|
||||
LOG_ERROR("Could not create new thread");
|
||||
#endif
|
||||
|
||||
if (created == 0) {
|
||||
if (created == 0) {
|
||||
#ifdef THREAD_DEBUG
|
||||
LOG_ERROR("System won't let me create more threads, giving up");
|
||||
LOG_ERROR("System won't let me create more threads, giving up");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return thread;
|
||||
return thread;
|
||||
}
|
||||
|
||||
/* _mutex_create
|
||||
@ -315,193 +315,193 @@ thread_type *thread_create_c(char *name, void *(*start_routine)(void *),
|
||||
static void _mutex_create(mutex_t *mutex)
|
||||
{
|
||||
#ifdef DEBUG_MUTEXES
|
||||
mutex->thread_id = MUTEX_STATE_NEVERLOCKED;
|
||||
mutex->line = -1;
|
||||
mutex->thread_id = MUTEX_STATE_NEVERLOCKED;
|
||||
mutex->line = -1;
|
||||
#endif
|
||||
|
||||
pthread_mutex_init(&mutex->sys_mutex, NULL);
|
||||
pthread_mutex_init(&mutex->sys_mutex, NULL);
|
||||
}
|
||||
|
||||
void thread_mutex_create_c(mutex_t *mutex, int line, char *file)
|
||||
{
|
||||
_mutex_create(mutex);
|
||||
_mutex_create(mutex);
|
||||
|
||||
#ifdef DEBUG_MUTEXES
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
mutex->mutex_id = _next_mutex_id++;
|
||||
avl_insert(_mutextree, (void *)mutex);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
mutex->mutex_id = _next_mutex_id++;
|
||||
avl_insert(_mutextree, (void *)mutex);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread_mutex_destroy (mutex_t *mutex)
|
||||
{
|
||||
pthread_mutex_destroy(&mutex->sys_mutex);
|
||||
pthread_mutex_destroy(&mutex->sys_mutex);
|
||||
|
||||
#ifdef DEBUG_MUTEXES
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
avl_delete(_mutextree, mutex, _free_mutex);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
avl_delete(_mutextree, mutex, _free_mutex);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread_mutex_lock_c(mutex_t *mutex, int line, char *file)
|
||||
{
|
||||
#ifdef DEBUG_MUTEXES
|
||||
thread_type *th = thread_self();
|
||||
thread_type *th = thread_self();
|
||||
|
||||
if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line);
|
||||
if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line);
|
||||
|
||||
LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
||||
LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
||||
|
||||
# ifdef CHECK_MUTEXES
|
||||
/* Just a little sanity checking to make sure that we're locking
|
||||
** mutexes correctly
|
||||
*/
|
||||
/* Just a little sanity checking to make sure that we're locking
|
||||
** mutexes correctly
|
||||
*/
|
||||
|
||||
if (th) {
|
||||
int locks = 0;
|
||||
avl_node *node;
|
||||
mutex_t *tmutex;
|
||||
if (th) {
|
||||
int locks = 0;
|
||||
avl_node *node;
|
||||
mutex_t *tmutex;
|
||||
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
|
||||
node = avl_get_first (_mutextree);
|
||||
|
||||
while (node) {
|
||||
tmutex = (mutex_t *)node->key;
|
||||
node = avl_get_first (_mutextree);
|
||||
|
||||
while (node) {
|
||||
tmutex = (mutex_t *)node->key;
|
||||
|
||||
if (tmutex->mutex_id == mutex->mutex_id) {
|
||||
if (tmutex->thread_id == th->thread_id) {
|
||||
/* Deadlock, same thread can't lock the same mutex twice */
|
||||
LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]",
|
||||
tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
||||
if (tmutex->mutex_id == mutex->mutex_id) {
|
||||
if (tmutex->thread_id == th->thread_id) {
|
||||
/* Deadlock, same thread can't lock the same mutex twice */
|
||||
LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]",
|
||||
tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
return;
|
||||
}
|
||||
} else if (tmutex->thread_id == th->thread_id) {
|
||||
/* Mutex locked by this thread (not this mutex) */
|
||||
locks++;
|
||||
}
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
return;
|
||||
}
|
||||
} else if (tmutex->thread_id == th->thread_id) {
|
||||
/* Mutex locked by this thread (not this mutex) */
|
||||
locks++;
|
||||
}
|
||||
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
|
||||
if (locks > 0) {
|
||||
/* Has already got a mutex locked */
|
||||
if (_multi_mutex.thread_id != th->thread_id) {
|
||||
/* Tries to lock two mutexes, but has not got the double mutex, norty boy! */
|
||||
LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!",
|
||||
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
||||
}
|
||||
}
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
}
|
||||
if (locks > 0) {
|
||||
/* Has already got a mutex locked */
|
||||
if (_multi_mutex.thread_id != th->thread_id) {
|
||||
/* Tries to lock two mutexes, but has not got the double mutex, norty boy! */
|
||||
LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!",
|
||||
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
||||
}
|
||||
}
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
}
|
||||
# endif /* CHECK_MUTEXES */
|
||||
|
||||
_mutex_lock(mutex);
|
||||
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
|
||||
_mutex_lock(mutex);
|
||||
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
|
||||
LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1);
|
||||
mutex->line = line;
|
||||
if (th) {
|
||||
mutex->thread_id = th->thread_id;
|
||||
}
|
||||
LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1);
|
||||
mutex->line = line;
|
||||
if (th) {
|
||||
mutex->thread_id = th->thread_id;
|
||||
}
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
#else
|
||||
_mutex_lock(mutex);
|
||||
_mutex_lock(mutex);
|
||||
#endif /* DEBUG_MUTEXES */
|
||||
}
|
||||
|
||||
void thread_mutex_unlock_c(mutex_t *mutex, int line, char *file)
|
||||
{
|
||||
#ifdef DEBUG_MUTEXES
|
||||
thread_type *th = thread_self();
|
||||
thread_type *th = thread_self();
|
||||
|
||||
if (!th) {
|
||||
LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line);
|
||||
}
|
||||
if (!th) {
|
||||
LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line);
|
||||
}
|
||||
|
||||
LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
||||
LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1);
|
||||
|
||||
mutex->line = line;
|
||||
mutex->line = line;
|
||||
|
||||
# ifdef CHECK_MUTEXES
|
||||
if (th) {
|
||||
int locks = 0;
|
||||
avl_node *node;
|
||||
mutex_t *tmutex;
|
||||
if (th) {
|
||||
int locks = 0;
|
||||
avl_node *node;
|
||||
mutex_t *tmutex;
|
||||
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
|
||||
while (node) {
|
||||
tmutex = (mutex_t *)node->key;
|
||||
while (node) {
|
||||
tmutex = (mutex_t *)node->key;
|
||||
|
||||
if (tmutex->mutex_id == mutex->mutex_id) {
|
||||
if (tmutex->thread_id != th->thread_id) {
|
||||
LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id,
|
||||
mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
return;
|
||||
}
|
||||
} else if (tmutex->thread_id == th->thread_id) {
|
||||
locks++;
|
||||
}
|
||||
if (tmutex->mutex_id == mutex->mutex_id) {
|
||||
if (tmutex->thread_id != th->thread_id) {
|
||||
LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id,
|
||||
mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
return;
|
||||
}
|
||||
} else if (tmutex->thread_id == th->thread_id) {
|
||||
locks++;
|
||||
}
|
||||
|
||||
node = avl_get_next (node);
|
||||
}
|
||||
node = avl_get_next (node);
|
||||
}
|
||||
|
||||
if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) {
|
||||
/* Don't have double mutex, has more than this mutex left */
|
||||
|
||||
LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!",
|
||||
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
||||
}
|
||||
if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) {
|
||||
/* Don't have double mutex, has more than this mutex left */
|
||||
|
||||
LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!",
|
||||
_multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line);
|
||||
}
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
}
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
}
|
||||
# endif /* CHECK_MUTEXES */
|
||||
|
||||
_mutex_unlock(mutex);
|
||||
_mutex_unlock(mutex);
|
||||
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
|
||||
LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1);
|
||||
mutex->line = -1;
|
||||
if (mutex->thread_id == th->thread_id) {
|
||||
mutex->thread_id = MUTEX_STATE_NOTLOCKED;
|
||||
}
|
||||
LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1);
|
||||
mutex->line = -1;
|
||||
if (mutex->thread_id == th->thread_id) {
|
||||
mutex->thread_id = MUTEX_STATE_NOTLOCKED;
|
||||
}
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
#else
|
||||
_mutex_unlock(mutex);
|
||||
_mutex_unlock(mutex);
|
||||
#endif /* DEBUG_MUTEXES */
|
||||
}
|
||||
|
||||
void thread_cond_create_c(cond_t *cond, int line, char *file)
|
||||
{
|
||||
pthread_cond_init(&cond->sys_cond, NULL);
|
||||
pthread_mutex_init(&cond->cond_mutex, NULL);
|
||||
pthread_cond_init(&cond->sys_cond, NULL);
|
||||
pthread_mutex_init(&cond->cond_mutex, NULL);
|
||||
}
|
||||
|
||||
void thread_cond_destroy(cond_t *cond)
|
||||
{
|
||||
pthread_mutex_destroy(&cond->cond_mutex);
|
||||
pthread_cond_destroy(&cond->sys_cond);
|
||||
pthread_mutex_destroy(&cond->cond_mutex);
|
||||
pthread_cond_destroy(&cond->sys_cond);
|
||||
}
|
||||
|
||||
void thread_cond_signal_c(cond_t *cond, int line, char *file)
|
||||
{
|
||||
pthread_cond_signal(&cond->sys_cond);
|
||||
pthread_cond_signal(&cond->sys_cond);
|
||||
}
|
||||
|
||||
void thread_cond_broadcast_c(cond_t *cond, int line, char *file)
|
||||
{
|
||||
pthread_cond_broadcast(&cond->sys_cond);
|
||||
pthread_cond_broadcast(&cond->sys_cond);
|
||||
}
|
||||
|
||||
void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file)
|
||||
@ -518,223 +518,223 @@ void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file)
|
||||
|
||||
void thread_cond_wait_c(cond_t *cond, int line, char *file)
|
||||
{
|
||||
pthread_mutex_lock(&cond->cond_mutex);
|
||||
pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex);
|
||||
pthread_mutex_unlock(&cond->cond_mutex);
|
||||
pthread_mutex_lock(&cond->cond_mutex);
|
||||
pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex);
|
||||
pthread_mutex_unlock(&cond->cond_mutex);
|
||||
}
|
||||
|
||||
void thread_rwlock_create_c(rwlock_t *rwlock, int line, char *file)
|
||||
{
|
||||
pthread_rwlock_init(&rwlock->sys_rwlock, NULL);
|
||||
pthread_rwlock_init(&rwlock->sys_rwlock, NULL);
|
||||
}
|
||||
|
||||
void thread_rwlock_destroy(rwlock_t *rwlock)
|
||||
{
|
||||
pthread_rwlock_destroy(&rwlock->sys_rwlock);
|
||||
pthread_rwlock_destroy(&rwlock->sys_rwlock);
|
||||
}
|
||||
|
||||
void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, char *file)
|
||||
{
|
||||
pthread_rwlock_rdlock(&rwlock->sys_rwlock);
|
||||
pthread_rwlock_rdlock(&rwlock->sys_rwlock);
|
||||
}
|
||||
|
||||
void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, char *file)
|
||||
{
|
||||
pthread_rwlock_wrlock(&rwlock->sys_rwlock);
|
||||
pthread_rwlock_wrlock(&rwlock->sys_rwlock);
|
||||
}
|
||||
|
||||
void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, char *file)
|
||||
{
|
||||
pthread_rwlock_unlock(&rwlock->sys_rwlock);
|
||||
pthread_rwlock_unlock(&rwlock->sys_rwlock);
|
||||
}
|
||||
|
||||
void thread_exit_c(int val, int line, char *file)
|
||||
{
|
||||
thread_type *th = thread_self();
|
||||
thread_type *th = thread_self();
|
||||
|
||||
#if defined(DEBUG_MUTEXES) && defined(CHECK_MUTEXES)
|
||||
if (th) {
|
||||
avl_node *node;
|
||||
mutex_t *tmutex;
|
||||
char name[40];
|
||||
if (th) {
|
||||
avl_node *node;
|
||||
mutex_t *tmutex;
|
||||
char name[40];
|
||||
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
_mutex_lock(&_mutextree_mutex);
|
||||
|
||||
while (node) {
|
||||
tmutex = (mutex_t *)node->key;
|
||||
while (node) {
|
||||
tmutex = (mutex_t *)node->key;
|
||||
|
||||
if (tmutex->thread_id == th->thread_id) {
|
||||
LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]",
|
||||
th->thread_id, th->name, file, line, mutex_to_string(tmutex, name));
|
||||
}
|
||||
if (tmutex->thread_id == th->thread_id) {
|
||||
LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]",
|
||||
th->thread_id, th->name, file, line, mutex_to_string(tmutex, name));
|
||||
}
|
||||
|
||||
node = avl_get_next (node);
|
||||
}
|
||||
node = avl_get_next (node);
|
||||
}
|
||||
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
}
|
||||
_mutex_unlock(&_mutextree_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (th) {
|
||||
|
||||
if (th) {
|
||||
#ifdef THREAD_DEBUG
|
||||
LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line);
|
||||
LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line);
|
||||
#endif
|
||||
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
avl_delete(_threadtree, th, _free_thread_if_detached);
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
}
|
||||
|
||||
pthread_exit((void *)val);
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
avl_delete(_threadtree, th, _free_thread_if_detached);
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
}
|
||||
|
||||
pthread_exit((void *)val);
|
||||
}
|
||||
|
||||
/* sleep for a number of microseconds */
|
||||
void thread_sleep(unsigned long len)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Sleep(len / 1000);
|
||||
Sleep(len / 1000);
|
||||
#else
|
||||
# ifdef HAVE_NANOSLEEP
|
||||
struct timespec time_sleep;
|
||||
struct timespec time_remaining;
|
||||
int ret;
|
||||
struct timespec time_sleep;
|
||||
struct timespec time_remaining;
|
||||
int ret;
|
||||
|
||||
time_sleep.tv_sec = len / 1000000;
|
||||
time_sleep.tv_nsec = (len % 1000000) * 1000;
|
||||
time_sleep.tv_sec = len / 1000000;
|
||||
time_sleep.tv_nsec = (len % 1000000) * 1000;
|
||||
|
||||
ret = nanosleep(&time_sleep, &time_remaining);
|
||||
while (ret != 0 && errno == EINTR) {
|
||||
time_sleep.tv_sec = time_remaining.tv_sec;
|
||||
time_sleep.tv_nsec = time_remaining.tv_nsec;
|
||||
|
||||
ret = nanosleep(&time_sleep, &time_remaining);
|
||||
}
|
||||
ret = nanosleep(&time_sleep, &time_remaining);
|
||||
while (ret != 0 && errno == EINTR) {
|
||||
time_sleep.tv_sec = time_remaining.tv_sec;
|
||||
time_sleep.tv_nsec = time_remaining.tv_nsec;
|
||||
|
||||
ret = nanosleep(&time_sleep, &time_remaining);
|
||||
}
|
||||
# else
|
||||
struct timeval tv;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = len / 1000000;
|
||||
tv.tv_usec = (len % 1000000);
|
||||
tv.tv_sec = len / 1000000;
|
||||
tv.tv_usec = (len % 1000000);
|
||||
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *_start_routine(void *arg)
|
||||
{
|
||||
thread_start_t *start = (thread_start_t *)arg;
|
||||
void *(*start_routine)(void *) = start->start_routine;
|
||||
void *real_arg = start->arg;
|
||||
thread_type *thread = start->thread;
|
||||
thread_start_t *start = (thread_start_t *)arg;
|
||||
void *(*start_routine)(void *) = start->start_routine;
|
||||
void *real_arg = start->arg;
|
||||
thread_type *thread = start->thread;
|
||||
int detach = start->detached;
|
||||
|
||||
_block_signals();
|
||||
_block_signals();
|
||||
|
||||
free(start);
|
||||
free(start);
|
||||
|
||||
/* insert thread into thread tree here */
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
thread->sys_thread = pthread_self();
|
||||
avl_insert(_threadtree, (void *)thread);
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
/* insert thread into thread tree here */
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
thread->sys_thread = pthread_self();
|
||||
avl_insert(_threadtree, (void *)thread);
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
|
||||
#ifdef THREAD_DEBUG
|
||||
LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line);
|
||||
LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line);
|
||||
#endif
|
||||
|
||||
if (detach) {
|
||||
pthread_detach(thread->sys_thread);
|
||||
if (detach) {
|
||||
pthread_detach(thread->sys_thread);
|
||||
thread->detached = 1;
|
||||
}
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
}
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
|
||||
/* call the real start_routine and start the thread
|
||||
** this should never exit!
|
||||
*/
|
||||
(start_routine)(real_arg);
|
||||
/* call the real start_routine and start the thread
|
||||
** this should never exit!
|
||||
*/
|
||||
(start_routine)(real_arg);
|
||||
|
||||
#ifdef THREAD_DEBUG
|
||||
LOG_WARN("Thread x should never exit from here!!!");
|
||||
LOG_WARN("Thread x should never exit from here!!!");
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
thread_type *thread_self(void)
|
||||
{
|
||||
avl_node *node;
|
||||
thread_type *th;
|
||||
pthread_t sys_thread = pthread_self();
|
||||
avl_node *node;
|
||||
thread_type *th;
|
||||
pthread_t sys_thread = pthread_self();
|
||||
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
|
||||
if (_threadtree == NULL) {
|
||||
if (_threadtree == NULL) {
|
||||
#ifdef THREAD_DEBUG
|
||||
LOG_WARN("Thread tree is empty, this must be wrong!");
|
||||
LOG_WARN("Thread tree is empty, this must be wrong!");
|
||||
#endif
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = avl_get_first(_threadtree);
|
||||
|
||||
while (node) {
|
||||
th = (thread_type *)node->key;
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = avl_get_first(_threadtree);
|
||||
|
||||
while (node) {
|
||||
th = (thread_type *)node->key;
|
||||
|
||||
if (th && pthread_equal(sys_thread, th->sys_thread)) {
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
return th;
|
||||
}
|
||||
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
if (th && pthread_equal(sys_thread, th->sys_thread)) {
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
return th;
|
||||
}
|
||||
|
||||
node = avl_get_next(node);
|
||||
}
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
|
||||
|
||||
#ifdef THREAD_DEBUG
|
||||
LOG_ERROR("Nonexistant thread alive...");
|
||||
LOG_ERROR("Nonexistant thread alive...");
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void thread_rename(const char *name)
|
||||
{
|
||||
thread_type *th;
|
||||
thread_type *th;
|
||||
|
||||
th = thread_self();
|
||||
if (th->name) free(th->name);
|
||||
th = thread_self();
|
||||
if (th->name) free(th->name);
|
||||
|
||||
th->name = strdup(name);
|
||||
th->name = strdup(name);
|
||||
}
|
||||
|
||||
static void _mutex_lock(mutex_t *mutex)
|
||||
{
|
||||
pthread_mutex_lock(&mutex->sys_mutex);
|
||||
pthread_mutex_lock(&mutex->sys_mutex);
|
||||
}
|
||||
|
||||
static void _mutex_unlock(mutex_t *mutex)
|
||||
{
|
||||
pthread_mutex_unlock(&mutex->sys_mutex);
|
||||
pthread_mutex_unlock(&mutex->sys_mutex);
|
||||
}
|
||||
|
||||
|
||||
void thread_library_lock(void)
|
||||
{
|
||||
_mutex_lock(&_library_mutex);
|
||||
_mutex_lock(&_library_mutex);
|
||||
}
|
||||
|
||||
void thread_library_unlock(void)
|
||||
{
|
||||
_mutex_unlock(&_library_mutex);
|
||||
_mutex_unlock(&_library_mutex);
|
||||
}
|
||||
|
||||
void thread_join(thread_type *thread)
|
||||
{
|
||||
void *ret;
|
||||
int i;
|
||||
void *ret;
|
||||
int i;
|
||||
|
||||
i = pthread_join(thread->sys_thread, &ret);
|
||||
i = pthread_join(thread->sys_thread, &ret);
|
||||
_mutex_lock(&_threadtree_mutex);
|
||||
avl_delete(_threadtree, thread, _free_thread);
|
||||
_mutex_unlock(&_threadtree_mutex);
|
||||
@ -745,65 +745,65 @@ void thread_join(thread_type *thread)
|
||||
#ifdef DEBUG_MUTEXES
|
||||
static int _compare_mutexes(void *compare_arg, void *a, void *b)
|
||||
{
|
||||
mutex_t *m1, *m2;
|
||||
mutex_t *m1, *m2;
|
||||
|
||||
m1 = (mutex_t *)a;
|
||||
m2 = (mutex_t *)b;
|
||||
m1 = (mutex_t *)a;
|
||||
m2 = (mutex_t *)b;
|
||||
|
||||
if (m1->mutex_id > m2->mutex_id)
|
||||
return 1;
|
||||
if (m1->mutex_id < m2->mutex_id)
|
||||
return -1;
|
||||
return 0;
|
||||
if (m1->mutex_id > m2->mutex_id)
|
||||
return 1;
|
||||
if (m1->mutex_id < m2->mutex_id)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _compare_threads(void *compare_arg, void *a, void *b)
|
||||
{
|
||||
thread_type *t1, *t2;
|
||||
thread_type *t1, *t2;
|
||||
|
||||
t1 = (thread_type *)a;
|
||||
t2 = (thread_type *)b;
|
||||
t1 = (thread_type *)a;
|
||||
t2 = (thread_type *)b;
|
||||
|
||||
if (t1->thread_id > t2->thread_id)
|
||||
return 1;
|
||||
if (t1->thread_id < t2->thread_id)
|
||||
return -1;
|
||||
return 0;
|
||||
if (t1->thread_id > t2->thread_id)
|
||||
return 1;
|
||||
if (t1->thread_id < t2->thread_id)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MUTEXES
|
||||
static int _free_mutex(void *key)
|
||||
{
|
||||
mutex_t *m;
|
||||
mutex_t *m;
|
||||
|
||||
m = (mutex_t *)key;
|
||||
m = (mutex_t *)key;
|
||||
|
||||
if (m && m->file) {
|
||||
free(m->file);
|
||||
m->file = NULL;
|
||||
}
|
||||
if (m && m->file) {
|
||||
free(m->file);
|
||||
m->file = NULL;
|
||||
}
|
||||
|
||||
/* all mutexes are static. don't need to free them */
|
||||
/* all mutexes are static. don't need to free them */
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _free_thread(void *key)
|
||||
{
|
||||
thread_type *t;
|
||||
thread_type *t;
|
||||
|
||||
t = (thread_type *)key;
|
||||
t = (thread_type *)key;
|
||||
|
||||
if (t->file)
|
||||
free(t->file);
|
||||
if (t->name)
|
||||
free(t->name);
|
||||
if (t->file)
|
||||
free(t->file);
|
||||
if (t->name)
|
||||
free(t->name);
|
||||
|
||||
free(t);
|
||||
free(t);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _free_thread_if_detached(void *key)
|
||||
|
@ -27,67 +27,67 @@
|
||||
/* renamed from thread_t due to conflict on OS X */
|
||||
|
||||
typedef struct {
|
||||
/* the local id for the thread, and it's name */
|
||||
long thread_id;
|
||||
char *name;
|
||||
/* the local id for the thread, and it's name */
|
||||
long thread_id;
|
||||
char *name;
|
||||
|
||||
/* the time the thread was created */
|
||||
time_t create_time;
|
||||
|
||||
/* the file and line which created this thread */
|
||||
char *file;
|
||||
int line;
|
||||
/* the time the thread was created */
|
||||
time_t create_time;
|
||||
|
||||
/* the file and line which created this thread */
|
||||
char *file;
|
||||
int line;
|
||||
|
||||
/* is the thread running detached? */
|
||||
int detached;
|
||||
/* is the thread running detached? */
|
||||
int detached;
|
||||
|
||||
/* the system specific thread */
|
||||
pthread_t sys_thread;
|
||||
/* the system specific thread */
|
||||
pthread_t sys_thread;
|
||||
} thread_type;
|
||||
|
||||
typedef struct {
|
||||
#ifdef DEBUG_MUTEXES
|
||||
/* the local id and name of the mutex */
|
||||
long mutex_id;
|
||||
char *name;
|
||||
/* the local id and name of the mutex */
|
||||
long mutex_id;
|
||||
char *name;
|
||||
|
||||
/* the thread which is currently locking this mutex */
|
||||
long thread_id;
|
||||
/* the thread which is currently locking this mutex */
|
||||
long thread_id;
|
||||
|
||||
/* the file and line where the mutex was locked */
|
||||
char *file;
|
||||
int line;
|
||||
/* the file and line where the mutex was locked */
|
||||
char *file;
|
||||
int line;
|
||||
|
||||
#endif
|
||||
|
||||
/* the system specific mutex */
|
||||
pthread_mutex_t sys_mutex;
|
||||
/* the system specific mutex */
|
||||
pthread_mutex_t sys_mutex;
|
||||
} mutex_t;
|
||||
|
||||
typedef struct {
|
||||
#ifdef THREAD_DEBUG
|
||||
long cond_id;
|
||||
char *name;
|
||||
long cond_id;
|
||||
char *name;
|
||||
#endif
|
||||
|
||||
pthread_mutex_t cond_mutex;
|
||||
pthread_cond_t sys_cond;
|
||||
pthread_mutex_t cond_mutex;
|
||||
pthread_cond_t sys_cond;
|
||||
} cond_t;
|
||||
|
||||
typedef struct {
|
||||
#ifdef THREAD_DEBUG
|
||||
long rwlock_id;
|
||||
char *name;
|
||||
long rwlock_id;
|
||||
char *name;
|
||||
|
||||
/* information on which thread and where in the code
|
||||
** this rwlock was write locked
|
||||
*/
|
||||
long thread_id;
|
||||
char *file;
|
||||
int line;
|
||||
/* information on which thread and where in the code
|
||||
** this rwlock was write locked
|
||||
*/
|
||||
long thread_id;
|
||||
char *file;
|
||||
int line;
|
||||
#endif
|
||||
|
||||
pthread_rwlock_t sys_rwlock;
|
||||
pthread_rwlock_t sys_rwlock;
|
||||
} rwlock_t;
|
||||
|
||||
#define thread_create(n,x,y,z) thread_create_c(n,x,y,z,__LINE__,__FILE__)
|
||||
|
@ -28,27 +28,27 @@
|
||||
uint64_t timing_get_time(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return timeGetTime();
|
||||
return timeGetTime();
|
||||
#else
|
||||
struct timeval mtv;
|
||||
struct timeval mtv;
|
||||
|
||||
gettimeofday(&mtv, NULL);
|
||||
gettimeofday(&mtv, NULL);
|
||||
|
||||
return (uint64_t)(mtv.tv_sec) * 1000 + (uint64_t)(mtv.tv_usec) / 1000;
|
||||
return (uint64_t)(mtv.tv_sec) * 1000 + (uint64_t)(mtv.tv_usec) / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void timing_sleep(uint64_t sleeptime)
|
||||
{
|
||||
struct timeval sleeper;
|
||||
struct timeval sleeper;
|
||||
|
||||
sleeper.tv_sec = sleeptime / 1000;
|
||||
sleeper.tv_usec = (sleeptime % 1000) * 1000;
|
||||
sleeper.tv_sec = sleeptime / 1000;
|
||||
sleeper.tv_usec = (sleeptime % 1000) * 1000;
|
||||
|
||||
/* NOTE:
|
||||
* This should be 0 for the first argument. The linux manpage
|
||||
* says so. The solaris manpage also says this is a legal
|
||||
* value. If you think differerntly, please provide references.
|
||||
*/
|
||||
select(0, NULL, NULL, NULL, &sleeper);
|
||||
/* NOTE:
|
||||
* This should be 0 for the first argument. The linux manpage
|
||||
* says so. The solaris manpage also says this is a legal
|
||||
* value. If you think differerntly, please provide references.
|
||||
*/
|
||||
select(0, NULL, NULL, NULL, &sleeper);
|
||||
}
|
||||
|
262
src/util.c
262
src/util.c
@ -70,40 +70,40 @@ int util_timed_wait_for_fd(int fd, int timeout)
|
||||
|
||||
int util_read_header(int sock, char *buff, unsigned long len)
|
||||
{
|
||||
int read_bytes, ret;
|
||||
unsigned long pos;
|
||||
char c;
|
||||
ice_config_t *config;
|
||||
int read_bytes, ret;
|
||||
unsigned long pos;
|
||||
char c;
|
||||
ice_config_t *config;
|
||||
int header_timeout;
|
||||
|
||||
config = config_get_config();
|
||||
config = config_get_config();
|
||||
header_timeout = config->header_timeout;
|
||||
config_release_config();
|
||||
|
||||
read_bytes = 1;
|
||||
pos = 0;
|
||||
ret = 0;
|
||||
read_bytes = 1;
|
||||
pos = 0;
|
||||
ret = 0;
|
||||
|
||||
while ((read_bytes == 1) && (pos < (len - 1))) {
|
||||
read_bytes = 0;
|
||||
while ((read_bytes == 1) && (pos < (len - 1))) {
|
||||
read_bytes = 0;
|
||||
|
||||
if (util_timed_wait_for_fd(sock, header_timeout*1000) > 0) {
|
||||
|
||||
if ((read_bytes = recv(sock, &c, 1, 0))) {
|
||||
if (c != '\r') buff[pos++] = c;
|
||||
if ((pos > 1) && (buff[pos - 1] == '\n' && buff[pos - 2] == '\n')) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((read_bytes = recv(sock, &c, 1, 0))) {
|
||||
if (c != '\r') buff[pos++] = c;
|
||||
if ((pos > 1) && (buff[pos - 1] == '\n' && buff[pos - 2] == '\n')) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) buff[pos] = '\0';
|
||||
|
||||
return ret;
|
||||
if (ret) buff[pos] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *util_get_extension(char *path) {
|
||||
@ -116,35 +116,35 @@ char *util_get_extension(char *path) {
|
||||
}
|
||||
|
||||
int util_check_valid_extension(char *uri) {
|
||||
int ret = 0;
|
||||
char *p2;
|
||||
int ret = 0;
|
||||
char *p2;
|
||||
|
||||
if (uri) {
|
||||
p2 = strrchr(uri, '.');
|
||||
if (p2) {
|
||||
p2++;
|
||||
if (strncmp(p2, "xsl", strlen("xsl")) == 0) {
|
||||
/* Build the full path for the request, concatenating the webroot from the config.
|
||||
** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch.
|
||||
*/
|
||||
ret = XSLT_CONTENT;
|
||||
}
|
||||
if (strncmp(p2, "htm", strlen("htm")) == 0) {
|
||||
/* Build the full path for the request, concatenating the webroot from the config.
|
||||
** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch.
|
||||
*/
|
||||
ret = HTML_CONTENT;
|
||||
}
|
||||
if (strncmp(p2, "html", strlen("html")) == 0) {
|
||||
/* Build the full path for the request, concatenating the webroot from the config.
|
||||
** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch.
|
||||
*/
|
||||
ret = HTML_CONTENT;
|
||||
}
|
||||
if (uri) {
|
||||
p2 = strrchr(uri, '.');
|
||||
if (p2) {
|
||||
p2++;
|
||||
if (strncmp(p2, "xsl", strlen("xsl")) == 0) {
|
||||
/* Build the full path for the request, concatenating the webroot from the config.
|
||||
** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch.
|
||||
*/
|
||||
ret = XSLT_CONTENT;
|
||||
}
|
||||
if (strncmp(p2, "htm", strlen("htm")) == 0) {
|
||||
/* Build the full path for the request, concatenating the webroot from the config.
|
||||
** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch.
|
||||
*/
|
||||
ret = HTML_CONTENT;
|
||||
}
|
||||
if (strncmp(p2, "html", strlen("html")) == 0) {
|
||||
/* Build the full path for the request, concatenating the webroot from the config.
|
||||
** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch.
|
||||
*/
|
||||
ret = HTML_CONTENT;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hex(char c)
|
||||
@ -442,7 +442,7 @@ char *util_base64_decode(unsigned char *input)
|
||||
|
||||
util_dict *util_dict_new(void)
|
||||
{
|
||||
return (util_dict *)calloc(1, sizeof(util_dict));
|
||||
return (util_dict *)calloc(1, sizeof(util_dict));
|
||||
}
|
||||
|
||||
void util_dict_free(util_dict *dict)
|
||||
@ -464,59 +464,59 @@ void util_dict_free(util_dict *dict)
|
||||
|
||||
const char *util_dict_get(util_dict *dict, const char *key)
|
||||
{
|
||||
while (dict) {
|
||||
if (!strcmp(key, dict->key))
|
||||
return dict->val;
|
||||
dict = dict->next;
|
||||
}
|
||||
while (dict) {
|
||||
if (!strcmp(key, dict->key))
|
||||
return dict->val;
|
||||
dict = dict->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int util_dict_set(util_dict *dict, const char *key, const char *val)
|
||||
{
|
||||
util_dict *prev;
|
||||
util_dict *prev;
|
||||
|
||||
if (!dict || !key) {
|
||||
if (!dict || !key) {
|
||||
ERROR0("NULL values passed to util_dict_set()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
while (dict) {
|
||||
if (!dict->key || !strcmp(dict->key, key))
|
||||
break;
|
||||
prev = dict;
|
||||
dict = dict->next;
|
||||
}
|
||||
prev = NULL;
|
||||
while (dict) {
|
||||
if (!dict->key || !strcmp(dict->key, key))
|
||||
break;
|
||||
prev = dict;
|
||||
dict = dict->next;
|
||||
}
|
||||
|
||||
if (!dict) {
|
||||
dict = util_dict_new();
|
||||
if (!dict) {
|
||||
if (!dict) {
|
||||
dict = util_dict_new();
|
||||
if (!dict) {
|
||||
ERROR0("unable to allocate new dictionary");
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
if (prev)
|
||||
prev->next = dict;
|
||||
}
|
||||
if (prev)
|
||||
prev->next = dict;
|
||||
}
|
||||
|
||||
if (dict->key)
|
||||
free (dict->val);
|
||||
else if (!(dict->key = strdup(key))) {
|
||||
if (prev)
|
||||
prev->next = NULL;
|
||||
util_dict_free (dict);
|
||||
if (dict->key)
|
||||
free (dict->val);
|
||||
else if (!(dict->key = strdup(key))) {
|
||||
if (prev)
|
||||
prev->next = NULL;
|
||||
util_dict_free (dict);
|
||||
|
||||
ERROR0("unable to allocate new dictionary key");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dict->val = strdup(val);
|
||||
if (!dict->val) {
|
||||
dict->val = strdup(val);
|
||||
if (!dict->val) {
|
||||
ERROR0("unable to allocate new dictionary value");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* given a dictionary, URL-encode each key and val and
|
||||
@ -525,56 +525,56 @@ int util_dict_set(util_dict *dict, const char *key, const char *val)
|
||||
TODO: Memory management needs overhaul. */
|
||||
char *util_dict_urlencode(util_dict *dict, char delim)
|
||||
{
|
||||
char *res, *tmp;
|
||||
char *enc;
|
||||
int start = 1;
|
||||
char *res, *tmp;
|
||||
char *enc;
|
||||
int start = 1;
|
||||
|
||||
for (res = NULL; dict; dict = dict->next) {
|
||||
/* encode key */
|
||||
if (!dict->key)
|
||||
continue;
|
||||
if (!(enc = util_url_escape(dict->key))) {
|
||||
if (res)
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
if (start) {
|
||||
if (!(res = malloc(strlen(enc) + 1))) {
|
||||
free(enc);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(res, "%s", enc);
|
||||
free(enc);
|
||||
start = 0;
|
||||
} else {
|
||||
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
||||
free(enc);
|
||||
free(res);
|
||||
return NULL;
|
||||
} else
|
||||
res = tmp;
|
||||
sprintf(res + strlen(res), "%c%s", delim, enc);
|
||||
free(enc);
|
||||
}
|
||||
for (res = NULL; dict; dict = dict->next) {
|
||||
/* encode key */
|
||||
if (!dict->key)
|
||||
continue;
|
||||
if (!(enc = util_url_escape(dict->key))) {
|
||||
if (res)
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
if (start) {
|
||||
if (!(res = malloc(strlen(enc) + 1))) {
|
||||
free(enc);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(res, "%s", enc);
|
||||
free(enc);
|
||||
start = 0;
|
||||
} else {
|
||||
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
||||
free(enc);
|
||||
free(res);
|
||||
return NULL;
|
||||
} else
|
||||
res = tmp;
|
||||
sprintf(res + strlen(res), "%c%s", delim, enc);
|
||||
free(enc);
|
||||
}
|
||||
|
||||
/* encode value */
|
||||
if (!dict->val)
|
||||
continue;
|
||||
if (!(enc = util_url_escape(dict->val))) {
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
/* encode value */
|
||||
if (!dict->val)
|
||||
continue;
|
||||
if (!(enc = util_url_escape(dict->val))) {
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
||||
free(enc);
|
||||
free(res);
|
||||
return NULL;
|
||||
} else
|
||||
res = tmp;
|
||||
sprintf(res + strlen(res), "=%s", enc);
|
||||
free(enc);
|
||||
}
|
||||
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
||||
free(enc);
|
||||
free(res);
|
||||
return NULL;
|
||||
} else
|
||||
res = tmp;
|
||||
sprintf(res + strlen(res), "=%s", enc);
|
||||
free(enc);
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
20
src/xslt.c
20
src/xslt.c
@ -134,27 +134,27 @@ static xsltStylesheetPtr xslt_get_stylesheet(char *fn) {
|
||||
void xslt_transform(xmlDocPtr doc, char *xslfilename, client_t *client)
|
||||
{
|
||||
xmlOutputBufferPtr outputBuffer;
|
||||
xmlDocPtr res;
|
||||
xsltStylesheetPtr cur;
|
||||
const char *params[16 + 1];
|
||||
xmlDocPtr res;
|
||||
xsltStylesheetPtr cur;
|
||||
const char *params[16 + 1];
|
||||
size_t count,bytes;
|
||||
|
||||
params[0] = NULL;
|
||||
params[0] = NULL;
|
||||
|
||||
xmlSubstituteEntitiesDefault(1);
|
||||
xmlLoadExtDtdDefaultValue = 1;
|
||||
xmlSubstituteEntitiesDefault(1);
|
||||
xmlLoadExtDtdDefaultValue = 1;
|
||||
|
||||
thread_mutex_lock(&xsltlock);
|
||||
cur = xslt_get_stylesheet(xslfilename);
|
||||
thread_mutex_unlock(&xsltlock);
|
||||
|
||||
if (cur == NULL) {
|
||||
bytes = sock_write_string(client->con->sock,
|
||||
if (cur == NULL) {
|
||||
bytes = sock_write_string(client->con->sock,
|
||||
(char *)"Could not parse XSLT file");
|
||||
if(bytes > 0) client->con->sent_bytes += bytes;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res = xsltApplyStylesheet(cur, doc, params);
|
||||
|
||||
@ -165,7 +165,7 @@ void xslt_transform(xmlDocPtr doc, char *xslfilename, client_t *client)
|
||||
/* Add null byte to end. */
|
||||
bytes = xmlOutputBufferWrite(outputBuffer, 1, "");
|
||||
|
||||
if(sock_write_string(client->con->sock,
|
||||
if(sock_write_string(client->con->sock,
|
||||
(char *)outputBuffer->buffer->content))
|
||||
client->con->sent_bytes += bytes;
|
||||
|
||||
|
30
src/yp.h
30
src/yp.h
@ -8,21 +8,21 @@ struct source_tag;
|
||||
#define YP_ADD_ALL -1
|
||||
typedef struct ypdata_tag
|
||||
{
|
||||
char *sid;
|
||||
char *server_name;
|
||||
char *server_desc;
|
||||
char *server_genre;
|
||||
char *cluster_password;
|
||||
char *server_url;
|
||||
char *listen_url;
|
||||
char *bitrate;
|
||||
char *audio_info;
|
||||
char *server_type;
|
||||
char *current_song;
|
||||
char *yp_url;
|
||||
int yp_url_timeout;
|
||||
long yp_last_touch;
|
||||
int yp_touch_interval;
|
||||
char *sid;
|
||||
char *server_name;
|
||||
char *server_desc;
|
||||
char *server_genre;
|
||||
char *cluster_password;
|
||||
char *server_url;
|
||||
char *listen_url;
|
||||
char *bitrate;
|
||||
char *audio_info;
|
||||
char *server_type;
|
||||
char *current_song;
|
||||
char *yp_url;
|
||||
int yp_url_timeout;
|
||||
long yp_last_touch;
|
||||
int yp_touch_interval;
|
||||
} ypdata_t;
|
||||
|
||||
void *yp_touch_thread(void *arg);
|
||||
|
Loading…
x
Reference in New Issue
Block a user