static void _handle_get_request (client_t *client, char *passed_uri) { int port; char *serverhost = NULL; int serverport = 0; aliases *alias; ice_config_t *config; char *uri = passed_uri; listener_t *listen_sock; config = config_get_config(); port = config->port; listen_sock = config_get_listen_sock (config, client->con); if (listen_sock) { serverhost = listen_sock->bind_address; serverport = listen_sock->port; } alias = config->aliases; /* 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 directory 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 */ /* Handle aliases */ while(alias) { if(strcmp(uri, alias->source) == 0 && (alias->port == -1 || alias->port == serverport) && (alias->bind_address == NULL || (serverhost != NULL && strcmp(alias->bind_address, serverhost) == 0))) { uri = strdup (alias->destination); DEBUG2 ("alias has made %s into %s", passed_uri, uri); break; } alias = alias->next; } config_release_config(); stats_event_inc(NULL, "client_connections"); /* Dispatch all admin requests */ if ((strcmp(uri, "/admin.cgi") == 0) || (strncmp(uri, "/admin/", 7) == 0)) { admin_handle_request(client, uri); if (uri != passed_uri) free (uri); return; } auth_add_listener (uri, client); if (uri != passed_uri) free (uri); }
void admin_handle_request(client_t *client, const char *uri) { const char *mount, *command_string; int command; DEBUG1("Admin request (%s)", uri); if (!((strcmp(uri, "/admin.cgi") == 0) || (strncmp("/admin/", uri, 7) == 0))) { ERROR0("Internal error: admin request isn't"); client_send_401(client); return; } if (strcmp(uri, "/admin.cgi") == 0) { command_string = uri + 1; } else { command_string = uri + 7; } DEBUG1("Got command (%s)", command_string); command = admin_get_command(command_string); if(command < 0) { ERROR1("Error parsing command string or unrecognised command: %s", command_string); client_send_400(client, "Unrecognised command"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE) { ice_config_t *config; const char *sc_mount; const char *pass = httpp_get_query_param (client->parser, "pass"); listener_t *listener; if (pass == NULL) { client_send_400 (client, "missing pass parameter"); return; } config = config_get_config (); sc_mount = config->shoutcast_mount; listener = config_get_listen_sock (config, client->con); if (listener && listener->shoutcast_mount) sc_mount = listener->shoutcast_mount; httpp_set_query_param (client->parser, "mount", sc_mount); httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY"); httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass); config_release_config (); } mount = httpp_get_query_param(client->parser, "mount"); if(mount != NULL) { source_t *source; /* this request does not require auth but can apply to files on webroot */ if (command == COMMAND_BUILDM3U) { command_buildm3u (client, mount); return; } /* 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 " "request (command: %s)", command_string); client_send_401(client); return; } } avl_tree_rlock(global.source_tree); source = source_find_mount_raw(mount); if (source == NULL) { WARN2("Admin command %s on non-existent source %s", command_string, mount); avl_tree_unlock(global.source_tree); client_send_400(client, "Source does not exist"); } else { if (source->running == 0 && source->on_demand == 0) { avl_tree_unlock (global.source_tree); INFO2("Received admin command %s on unavailable mount \"%s\"", command_string, mount); client_send_400 (client, "Source is not available"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE && source->shoutcast_compat == 0) { avl_tree_unlock (global.source_tree); ERROR0 ("illegal change of metadata on non-shoutcast " "compatible stream"); client_send_400 (client, "illegal metadata call"); return; } INFO2("Received admin command %s on mount \"%s\"", command_string, mount); admin_handle_mount_request(client, source, command); avl_tree_unlock(global.source_tree); } } else { if (command == COMMAND_PLAINTEXT_LISTSTREAM) { /* this request is used by a slave relay to retrieve mounts from the master, so handle this request validating against the relay password */ if(!connection_check_relay_pass(client->parser)) { INFO1("Bad or missing password on admin command " "request (command: %s)", command_string); client_send_401(client); return; } } else { if(!connection_check_admin_pass(client->parser)) { INFO1("Bad or missing password on admin command " "request (command: %s)", command_string); client_send_401(client); return; } } admin_handle_general_request(client, command); } }
void connection_accept_loop (void) { connection_t *con; ice_config_t *config; int duration = 300; config = config_get_config (); get_ssl_certificate (config); config_release_config (); while (global.running == ICE_RUNNING) { con = _accept_connection (duration); if (con) { client_queue_t *node; ice_config_t *config; client_t *client = NULL; listener_t *listener; global_lock(); if (client_create (&client, con, NULL) < 0) { global_unlock(); client_send_403 (client, "Icecast connection limit reached"); /* don't be too eager as this is an imposed hard limit */ thread_sleep (400000); continue; } /* setup client for reading incoming http */ client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000'; if (sock_set_blocking (client->con->sock, 0) || sock_set_nodelay (client->con->sock)) { global_unlock(); WARN0 ("failed to set tcp options on client connection, dropping"); client_destroy (client); continue; } node = calloc (1, sizeof (client_queue_t)); if (node == NULL) { global_unlock(); client_destroy (client); continue; } node->client = client; config = config_get_config(); listener = config_get_listen_sock (config, client->con); if (listener) { if (listener->shoutcast_compat) node->shoutcast = 1; if (listener->ssl && ssl_ok) connection_uses_ssl (client->con); if (listener->shoutcast_mount) node->shoutcast_mount = strdup (listener->shoutcast_mount); } global_unlock(); config_release_config(); _add_request_queue (node); stats_event_inc (NULL, "connections"); duration = 5; } else { if (_req_queue == NULL) duration = 300; /* use longer timeouts when nothing waiting */ } process_request_queue (); } /* Give all the other threads notification to shut down */ thread_cond_broadcast(&global.shutdown_cond); /* wait for all the sources to shutdown */ thread_rwlock_wlock(&_source_shutdown_rwlock); thread_rwlock_unlock(&_source_shutdown_rwlock); }
/* we don't need to clean up on err, as we'll go through the node struct and clean all we have inside */ static int _connection_process (connection_queue_t *node) { refbuf_t *header; http_parser_t *parser = NULL; int hdrsize = 0; int shoutcast = 0; int err; char *shoutcast_mount = NULL; mount_proxy *mountinfo; ice_config_t *config; listener_t *listener; if (!node->refbuf) node->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); header = node->refbuf; { /* this code tests for shoutcastness */ config = config_get_config(); listener = config_get_listen_sock (config, node->con); if (listener) { WARN("listner"); if (listener->shoutcast_compat) shoutcast = 1; if (listener->ssl && ssl_ok) connection_uses_ssl (node->con); if (listener->shoutcast_mount) { shoutcast_mount = strdup (listener->shoutcast_mount); } else { shoutcast_mount = config->shoutcast_mount; } } WARN("shoutcast %d, mount %s", shoutcast, shoutcast_mount); mountinfo = config_find_mount (config, shoutcast_mount); config_release_config(); } if (shoutcast && !header->sync_point) { /* stage2 is actually handled by generic code */ err = _handle_shoutcast_stage1 (node, shoutcast_mount, mountinfo); if (err < 0) return err; } hdrsize = util_read_header (node->con, header, HEADER_READ_ENTIRE); if (hdrsize < 0) { ERROR ("Header read failed"); return hdrsize; } /* process normal HTTP headers */ if (node->parser) { parser = node->parser; } else { parser = node->parser = httpp_create_parser(); httpp_initialize(parser, NULL); } err = httpp_parse (parser, header->data, hdrsize); if (err == 0) { ERROR0("HTTP request parsing failed"); return -EINVAL; } /* XXX what happens when error in http ??? is err set ? */ if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE)) { ERROR("Error(%s)", httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE)); return err; } if (header->sync_point && (parser->req_type == httpp_req_source || parser->req_type == httpp_req_post)) { hdrsize = util_read_header (node->con, header, HEADER_READ_ENTIRE); if (hdrsize < 0) { INFO ("Header read failed"); return hdrsize; } } if (! node->client) { err = connection_client_setup (node); if (err < 0) return err; header->len -= hdrsize; if (header->len) { memmove(header->data, header->data + hdrsize, header->len); client_set_queue (node->client, header); } refbuf_release(header); } stats_event_inc (NULL, "connections"); WARN("shoutcast = %d", shoutcast); return _handle_client (node->client); }
void connection_accept_loop(void) { connection_t *con; ice_config_t *config; config = config_get_config (); get_ssl_certificate (config); config_release_config (); tid = thread_create ("connection thread", _handle_connection, NULL, THREAD_ATTACHED); while (global.running == ICE_RUNNING) { con = _accept_connection(); if (con) { client_queue_t *node; ice_config_t *config; client_t *client = NULL; listener_t *listener; global_lock(); if (client_create (&client, con, NULL) < 0) { global_unlock(); client_send_403 (client, "Icecast connection limit reached"); /* don't be too eager as this is an imposed hard limit */ thread_sleep (400000); continue; } global_unlock(); /* setup client for reading incoming http */ client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000'; node = calloc (1, sizeof (client_queue_t)); if (node == NULL) { client_destroy (client); continue; } node->client = client; config = config_get_config(); listener = config_get_listen_sock (config, client->con); if (listener) { if (listener->shoutcast_compat) node->shoutcast = 1; if (listener->ssl && ssl_ok) connection_uses_ssl (client->con); if (listener->shoutcast_mount) node->shoutcast_mount = strdup (listener->shoutcast_mount); } config_release_config(); sock_set_blocking (client->con->sock, SOCK_NONBLOCK); sock_set_nodelay (client->con->sock); _add_request_queue (node); stats_event_inc (NULL, "connections"); } process_request_queue (); } /* Give all the other threads notification to shut down */ thread_cond_broadcast(&global.shutdown_cond); if (tid) thread_join (tid); /* wait for all the sources to shutdown */ thread_rwlock_wlock(&_source_shutdown_rwlock); thread_rwlock_unlock(&_source_shutdown_rwlock); }