diff --git a/src/connection.c b/src/connection.c index 1b2a1ba8..87795d03 100644 --- a/src/connection.c +++ b/src/connection.c @@ -310,161 +310,140 @@ static void *_handle_connection(void *arg) if (global.running != ICE_RUNNING) break; /* grab a connection and set the socket to blocking */ - con = _get_connection(); + while (con = _get_connection()) { + 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; - } - - 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)) != 0 && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0) { - printf("DEBUG: bad protocol\n"); + /* 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); - httpp_destroy(parser); continue; } - if (parser->req_type == httpp_req_source) { - char *contenttype; - - printf("DEBUG: source logging in\n"); - stats_event_inc(NULL, "source_connections"); + parser = httpp_create_parser(); + httpp_initialize(parser, NULL); + if (httpp_parse(parser, header, strlen(header))) { + /* handle the connection or something */ - if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) { - printf("DEBUG: bad password\n"); - INFO1("Source (%s) attempted to login with bad password", httpp_getvar(parser, HTTPP_VAR_URI)); + if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0 && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0) { + printf("DEBUG: bad protocol\n"); connection_close(con); httpp_destroy(parser); continue; } - /* check to make sure this source has - ** a unique mountpoint - */ + if (parser->req_type == httpp_req_source) { + char *contenttype; - avl_tree_rlock(global.source_tree); - if (source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI)) != NULL) { - printf("Source attempted to connect with an already used mountpoint.\n"); - INFO1("Source tried to log in as %s, but is already used", httpp_getvar(parser, HTTPP_VAR_URI)); - connection_close(con); - httpp_destroy(parser); - avl_tree_unlock(global.source_tree); - continue; - } - avl_tree_unlock(global.source_tree); - - /* check to make sure this source wouldn't - ** be over the limit - */ - global_lock(); - if (global.sources >= config_get_config()->source_limit) { - printf("TOO MANY SOURCE, KICKING THIS ONE\n"); - INFO1("Source (%s) logged in, but there are too many sources", httpp_getvar(parser, HTTPP_VAR_URI)); - connection_close(con); - httpp_destroy(parser); - global_unlock(); - continue; - } - global.sources++; - global_unlock(); - - stats_event_inc(NULL, "sources"); - - contenttype = httpp_getvar(parser, "content-type"); - - if (contenttype != NULL) { - format_type_t format = format_get_type(contenttype); - if(format < 0) { - WARN1("Content-type \"%s\" not supported, dropping source", contenttype); - continue; - } - else - source = source_create(con, parser, httpp_getvar(parser, HTTPP_VAR_URI), format); - } - else { - WARN0("No content-type header, cannot handle source"); - continue; - } - - source->shutdown_rwlock = &_source_shutdown_rwlock; - - sock_set_blocking(con->sock, SOCK_NONBLOCK); + printf("DEBUG: source logging in\n"); + stats_event_inc(NULL, "source_connections"); - thread_create("Source Thread", source_main, (void *)source, THREAD_DETACHED); - - continue; - } else if (parser->req_type == httpp_req_stats) { - printf("DEBUG: stats connection...\n"); - stats_event_inc(NULL, "stats_connections"); - - if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) { - printf("DEBUG: bad password\n"); - connection_close(con); - httpp_destroy(parser); - continue; - } - - 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); - - continue; - } else if (parser->req_type == httpp_req_play || parser->req_type == httpp_req_get) { - printf("DEBUG: client coming in...\n"); - - /* 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 /stats.xml - ** and director server authorizers, which are looking for /GUID-xxxxxxxx (where xxxxxx is the GUID in question - ** we need to handle the latter two before the former, as the latter two - ** aren't subject to the limits. - */ - // TODO: add GUID-xxxxxx - if (strcmp(httpp_getvar(parser, HTTPP_VAR_URI), "/stats.xml") == 0) { - printf("sending stats.xml\n"); - stats_sendxml(client); - continue; - } - - global_lock(); - if (global.clients >= config_get_config()->client_limit) { - if (parser->req_type == httpp_req_get) { - client->respcode = 504; - bytes = sock_write(client->con->sock, "HTTP/1.0 504 Server Full\r\nContent-Type: text/html\r\n\r\n"\ - "The server is already full. Try again later.\r\n"); - if (bytes > 0) client->con->sent_bytes = bytes; + if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) { + printf("DEBUG: bad password\n"); + INFO1("Source (%s) attempted to login with bad password", httpp_getvar(parser, HTTPP_VAR_URI)); + connection_close(con); + httpp_destroy(parser); + continue; } - client_destroy(client); - global_unlock(); - continue; - } - global_unlock(); - - avl_tree_rlock(global.source_tree); - source = source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI)); - if (source) { - printf("DEBUG: source found for client\n"); + /* check to make sure this source has + ** a unique mountpoint + */ + + avl_tree_rlock(global.source_tree); + if (source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI)) != NULL) { + printf("Source attempted to connect with an already used mountpoint.\n"); + INFO1("Source tried to log in as %s, but is already used", httpp_getvar(parser, HTTPP_VAR_URI)); + connection_close(con); + httpp_destroy(parser); + avl_tree_unlock(global.source_tree); + continue; + } + avl_tree_unlock(global.source_tree); + + /* check to make sure this source wouldn't + ** be over the limit + */ + global_lock(); + if (global.sources >= config_get_config()->source_limit) { + printf("TOO MANY SOURCE, KICKING THIS ONE\n"); + INFO1("Source (%s) logged in, but there are too many sources", httpp_getvar(parser, HTTPP_VAR_URI)); + connection_close(con); + httpp_destroy(parser); + global_unlock(); + continue; + } + global.sources++; + global_unlock(); + + stats_event_inc(NULL, "sources"); + + contenttype = httpp_getvar(parser, "content-type"); + + if (contenttype != NULL) { + format_type_t format = format_get_type(contenttype); + if (format < 0) { + WARN1("Content-type \"%s\" not supported, dropping source", contenttype); + continue; + } else { + source = source_create(con, parser, httpp_getvar(parser, HTTPP_VAR_URI), format); + } + } else { + WARN0("No content-type header, cannot handle source"); + continue; + } + + source->shutdown_rwlock = &_source_shutdown_rwlock; + + sock_set_blocking(con->sock, SOCK_NONBLOCK); + + thread_create("Source Thread", source_main, (void *)source, THREAD_DETACHED); + + continue; + } else if (parser->req_type == httpp_req_stats) { + printf("DEBUG: stats connection...\n"); + stats_event_inc(NULL, "stats_connections"); + + if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) { + printf("DEBUG: bad password\n"); + connection_close(con); + httpp_destroy(parser); + continue; + } + + 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); + + continue; + } else if (parser->req_type == httpp_req_play || parser->req_type == httpp_req_get) { + printf("DEBUG: client coming in...\n"); + + /* 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 /stats.xml + ** and director server authorizers, which are looking for /GUID-xxxxxxxx (where xxxxxx is the GUID in question + ** we need to handle the latter two before the former, as the latter two + ** aren't subject to the limits. + */ + // TODO: add GUID-xxxxxx + if (strcmp(httpp_getvar(parser, HTTPP_VAR_URI), "/stats.xml") == 0) { + printf("sending stats.xml\n"); + stats_sendxml(client); + continue; + } + global_lock(); if (global.clients >= config_get_config()->client_limit) { if (parser->req_type == httpp_req_get) { @@ -477,60 +456,80 @@ static void *_handle_connection(void *arg) global_unlock(); continue; } - global.clients++; global_unlock(); - - if (parser->req_type == httpp_req_get) { - client->respcode = 200; - sock_write(client->con->sock, "HTTP/1.0 200 OK\r\nContent-Type: application/x-ogg\r\n"); - /* 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)) { - printf("DEBUG: sending %s: %s\n", var->name, var->value); - sock_write(client->con->sock, "%s: %s\r\n", var->name, var->value); - } - node = avl_get_next(node); - } - avl_tree_unlock(source->parser->vars); - - sock_write(client->con->sock, "\r\n"); + + avl_tree_rlock(global.source_tree); + source = source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI)); + if (source) { + printf("DEBUG: source found for client\n"); - sock_set_blocking(client->con->sock, SOCK_NONBLOCK); + global_lock(); + if (global.clients >= config_get_config()->client_limit) { + if (parser->req_type == httpp_req_get) { + client->respcode = 504; + bytes = sock_write(client->con->sock, "HTTP/1.0 504 Server Full\r\nContent-Type: text/html\r\n\r\n"\ + "The server is already full. Try again later.\r\n"); + if (bytes > 0) client->con->sent_bytes = bytes; + } + client_destroy(client); + global_unlock(); + continue; + } + global.clients++; + global_unlock(); + + if (parser->req_type == httpp_req_get) { + client->respcode = 200; + sock_write(client->con->sock, "HTTP/1.0 200 OK\r\nContent-Type: application/x-ogg\r\n"); + /* 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)) { + printf("DEBUG: sending %s: %s\n", var->name, var->value); + sock_write(client->con->sock, "%s: %s\r\n", var->name, var->value); + } + node = avl_get_next(node); + } + avl_tree_unlock(source->parser->vars); + + sock_write(client->con->sock, "\r\n"); + + sock_set_blocking(client->con->sock, SOCK_NONBLOCK); + } + + avl_tree_wlock(source->pending_tree); + avl_insert(source->pending_tree, (void *)client); + avl_tree_unlock(source->pending_tree); } - - 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) { - printf("DEBUG: source not found for client\n"); - if (parser->req_type == httpp_req_get) { - client->respcode = 404; - bytes = sock_write(client->con->sock, "HTTP/1.0 404 Source Not Found\r\nContent-Type: text/html\r\n\r\n"\ - "The source you requested could not be found.\r\n"); - if (bytes > 0) client->con->sent_bytes = bytes; + + avl_tree_unlock(global.source_tree); + + if (!source) { + printf("DEBUG: source not found for client\n"); + if (parser->req_type == httpp_req_get) { + client->respcode = 404; + bytes = sock_write(client->con->sock, "HTTP/1.0 404 Source Not Found\r\nContent-Type: text/html\r\n\r\n"\ + "The source you requested could not be found.\r\n"); + if (bytes > 0) client->con->sent_bytes = bytes; + } + client_destroy(client); } - client_destroy(client); + + continue; + } else { + printf("DEBUG: wrong request type\n"); + connection_close(con); + httpp_destroy(parser); + continue; } - - continue; } else { - printf("DEBUG: wrong request type\n"); + printf("DEBUG: parsing failed\n"); connection_close(con); httpp_destroy(parser); continue; } - } else { - printf("DEBUG: parsing failed\n"); - connection_close(con); - httpp_destroy(parser); - continue; } }