static int command_fallback (client_t *client, source_t *source, int response) { char *mount = strdup (source->mount); mount_proxy *mountinfo; ice_config_t *config; thread_mutex_unlock (&source->lock); DEBUG0("Got fallback request"); config = config_grab_config(); mountinfo = config_find_mount (config, mount); free (mount); if (mountinfo) { const char *fallback; char buffer[200]; if (COMMAND_REQUIRE(client, "fallback", fallback) < 0) return client_send_400 (client, "missing arg, fallback"); xmlFree (mountinfo->fallback_mount); mountinfo->fallback_mount = (char *)xmlCharStrdup (fallback); snprintf (buffer, sizeof (buffer), "Fallback for \"%s\" configured", mountinfo->mountname); config_release_config (); return html_success (client, buffer); } config_release_config (); return client_send_400 (client, "no mount details available"); }
static void command_shoutcast_metadata(client_t *client, source_t *source) { const char *action; const char *value; DEBUG0("Got shoutcast metadata update request"); COMMAND_REQUIRE(client, "mode", action); COMMAND_REQUIRE(client, "song", value); if (strcmp (action, "updinfo") != 0) { client_send_400 (client, "No such action"); return; } if (source->format && source->format->set_tag) { source->format->set_tag (source->format, "title", value, NULL); DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); html_success(client, "Metadata update successful"); } else { client_send_400 (client, "mountpoint will not accept URL updates"); } }
static void command_shoutcast_metadata(client_t *client, source_t *source) { char *action; char *value; mp3_state *state; DEBUG0("Got shoutcast metadata update request"); COMMAND_REQUIRE(client, "mode", action); COMMAND_REQUIRE(client, "song", value); if (source->format->type == FORMAT_TYPE_OGG) { client_send_400 (client, "Cannot update metadata on vorbis streams"); return; } if (strcmp (action, "updinfo") != 0) { client_send_400 (client, "No such action"); return; } state = source->format->_state; mp3_set_tag (source->format, "title", value); DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); html_success(client, "Metadata update successful"); }
static int command_shoutcast_metadata (client_t *client, source_t *source) { const char *action; const char *value; int same_ip = 1; if (COMMAND_REQUIRE(client, "mode", action) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, mode"); } if ((source->flags & SOURCE_SHOUTCAST_COMPAT) == 0) { thread_mutex_unlock (&source->lock); ERROR0 ("illegal request on non-shoutcast compatible stream"); return client_send_400 (client, "Not a shoutcast compatible stream"); } if (strcmp (action, "updinfo") == 0) { DEBUG0("Got shoutcast metadata update request"); if (COMMAND_REQUIRE (client, "song", value) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, song"); } if (source->client && strcmp (client->connection.ip, source->client->connection.ip) != 0) if (connection_check_admin_pass (client->parser) == 0) same_ip = 0; if (same_ip && source->format && source->format->set_tag) { httpp_set_query_param (client->parser, "mount", client->server_conn->shoutcast_mount); source->format->set_tag (source->format, "title", value, NULL); source->format->set_tag (source->format, NULL, NULL, NULL); DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); thread_mutex_unlock (&source->lock); return html_success(client, "Metadata update successful"); } thread_mutex_unlock (&source->lock); return client_send_400 (client, "mountpoint will not accept URL updates"); } if (strcmp (action, "viewxml") == 0) { xmlDocPtr doc; DEBUG0("Got shoutcast viewxml request"); thread_mutex_unlock (&source->lock); doc = stats_get_xml (STATS_ALL, source->mount); return admin_send_response (doc, client, XSLT, "viewxml.xsl"); } thread_mutex_unlock (&source->lock); return client_send_400 (client, "No such action"); }
static int command_list_log (client_t *client, int response) { refbuf_t *content; const char *logname = httpp_get_query_param (client->parser, "log"); int log = -1; ice_config_t *config; if (logname == NULL) return client_send_400 (client, "No log specified"); config = config_get_config (); if (strcmp (logname, "errorlog") == 0) log = config->error_log.logid; else if (strcmp (logname, "accesslog") == 0) log = config->access_log.logid; else if (strcmp (logname, "playlistlog") == 0) log = config->playlist_log.logid; if (log < 0) { config_release_config(); WARN1 ("request to show unknown log \"%s\"", logname); return client_send_400 (client, "unknown"); } content = refbuf_new (0); log_contents (log, &content->data, &content->len); config_release_config(); if (response == XSLT) { xmlNodePtr xmlnode; xmlDocPtr doc; doc = xmlNewDoc(XMLSTR("1.0")); xmlnode = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL); xmlDocSetRootElement(doc, xmlnode); xmlNewTextChild (xmlnode, NULL, XMLSTR("log"), XMLSTR(content->data)); refbuf_release (content); return admin_send_response (doc, client, XSLT, "showlog.xsl"); } else { refbuf_t *http = refbuf_new (100); int len = snprintf (http->data, 100, "%s", "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n"); http->len = len; http->next = content; client->respcode = 200; client_set_queue (client, http); return fserve_setup_client (client); } }
static void admin_handle_general_request(client_t *client, int command) { switch(command) { case COMMAND_RAW_STATS: command_stats(client, NULL, RAW); break; case COMMAND_RAW_LIST_MOUNTS: command_list_mounts(client, RAW); break; case COMMAND_RAW_LISTSTREAM: command_list_mounts(client, RAW); break; case COMMAND_PLAINTEXT_LISTSTREAM: command_list_mounts(client, PLAINTEXT); break; case COMMAND_TRANSFORMED_STATS: command_stats(client, NULL, TRANSFORMED); break; case COMMAND_TRANSFORMED_LIST_MOUNTS: command_list_mounts(client, TRANSFORMED); break; case COMMAND_TRANSFORMED_LISTSTREAM: command_list_mounts(client, TRANSFORMED); break; case COMMAND_TRANSFORMED_MOVE_CLIENTS: command_list_mounts(client, TRANSFORMED); break; default: WARN0("General admin request not recognised"); client_send_400(client, "Unknown admin request"); return; } }
int fserve_kill_client (client_t *client, const char *mount, int response) { int loop = 2, id; fbinfo finfo; xmlDocPtr doc; xmlNodePtr node; const char *idtext, *v = "0"; char buf[50]; finfo.flags = 0; finfo.mount = (char*)mount; finfo.limit = 0; finfo.fallback = NULL; idtext = httpp_get_query_param (client->parser, "id"); if (idtext == NULL) return client_send_400 (client, "missing parameter id"); id = atoi(idtext); doc = xmlNewDoc(XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); snprintf (buf, sizeof(buf), "Client %d not found", id); avl_tree_rlock (fh_cache); while (1) { avl_node *node; fh_node *fh = find_fh (&finfo); if (fh) { thread_mutex_lock (&fh->lock); avl_tree_unlock (fh_cache); node = avl_get_first (fh->clients); while (node) { client_t *listener = (client_t *)node->key; if (listener->connection.id == id) { listener->connection.error = 1; snprintf (buf, sizeof(buf), "Client %d removed", id); v = "1"; loop = 0; break; } node = avl_get_next (node); } thread_mutex_unlock (&fh->lock); avl_tree_rlock (fh_cache); } if (loop == 0) break; loop--; if (loop == 1) finfo.flags = FS_FALLBACK; } avl_tree_unlock (fh_cache); xmlNewChild (node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild (node, NULL, XMLSTR("return"), XMLSTR(v)); return admin_send_response (doc, client, response, "response.xsl"); }
int fserve_list_clients (client_t *client, const char *mount, int response, int show_listeners) { int ret; fbinfo finfo; xmlDocPtr doc; xmlNodePtr node, srcnode; finfo.flags = 0; finfo.mount = (char*)mount; finfo.limit = 0; finfo.fallback = NULL; doc = xmlNewDoc(XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL); xmlDocSetRootElement(doc, node); srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL); xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(mount)); ret = fserve_list_clients_xml (srcnode, &finfo); if (ret == 0 && finfo.flags&FS_FALLBACK) { finfo.flags = 0; // retry ret = fserve_list_clients_xml (srcnode, &finfo); } if (ret) { char buf [20]; snprintf (buf, sizeof(buf), "%d", ret); xmlNewChild (srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf)); return admin_send_response (doc, client, response, "listclients.xsl"); } xmlFreeDoc (doc); return client_send_400 (client, "mount does not exist"); }
int admin_mount_request (client_t *client, const char *uri) { source_t *source; const char *mount = httpp_get_query_param (client->parser, "mount"); struct admin_command *cmd = find_admin_command (admin_mount, uri); if (cmd == NULL) return command_stats (client, uri); if (cmd == NULL || cmd->handle.source == NULL) { INFO0("mount request not recognised"); return client_send_400 (client, "unknown request"); } avl_tree_rlock(global.source_tree); source = source_find_mount_raw(mount); if (source == NULL) { avl_tree_unlock(global.source_tree); if (strncmp (cmd->request, "stats", 5) == 0) return command_stats (client, uri); if (strncmp (cmd->request, "listclients", 11) == 0) return fserve_list_clients (client, mount, cmd->response, 1); if (strncmp (cmd->request, "killclient", 10) == 0) return fserve_kill_client (client, mount, cmd->response); WARN1("Admin command on non-existent source %s", mount); return client_send_400 (client, "Source does not exist"); } else { int ret = 0; thread_mutex_lock (&source->lock); if (source_available (source) == 0) { thread_mutex_unlock (&source->lock); avl_tree_unlock (global.source_tree); INFO1("Received admin command on unavailable mount \"%s\"", mount); return client_send_400 (client, "Source is not available"); } ret = cmd->handle.source (client, source, cmd->response); avl_tree_unlock(global.source_tree); return ret; } }
static int command_admin_function (client_t *client, int response) { xmlDocPtr doc; xmlNodePtr node; const char *perform; char buf[256]; if (COMMAND_REQUIRE (client, "perform", perform) < 0) return client_send_400 (client, "missing arg, perform"); if (admin_function (perform, buf, sizeof buf) < 0) return client_send_400 (client, "No such handler"); doc = xmlNewDoc(XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); return admin_send_response (doc, client, response, "response.xsl"); }
static int _handle_client (client_t *client) { const char *rawuri; http_parser_t *parser = client->parser; char *uri; rawuri = httpp_getvar(parser, HTTPP_VAR_URI); if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) { client_send_400 (client, "Bad HTTP protocol"); return -EINPROGRESS; } uri = util_normalise_uri(rawuri); if (uri == NULL) { client_send_400 (client, "Couldn't normalize uri"); return -EINPROGRESS; } if (parser->req_type == httpp_req_source) { _handle_source_request (client, uri); } else if (parser->req_type == httpp_req_post) { _handle_post_request (client, uri); } else if (parser->req_type == httpp_req_stats) { _handle_stats_request (client, uri); } else if (parser->req_type == httpp_req_get) { _handle_get_request (client, uri); } else { client_send_400 (client, "Wrong request type from client"); return -EINPROGRESS; } free(uri); return 1; }
static int command_kill_client (client_t *client, source_t *source, int response) { const char *idtext; int id; client_t *listener; xmlDocPtr doc; xmlNodePtr node; char buf[50] = ""; if (COMMAND_REQUIRE(client, "id", idtext) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, id"); } id = atoi(idtext); listener = source_find_client(source, id); doc = xmlNewDoc(XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); if(listener != NULL) { INFO1("Admin request: client %d removed", id); /* This tags it for removal on the next iteration of the main source * loop */ listener->connection.error = 1; snprintf(buf, sizeof(buf), "Client %d removed", id); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); } else { snprintf(buf, sizeof(buf), "Client %d not found", id); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("0")); } thread_mutex_unlock (&source->lock); return admin_send_response (doc, client, response, "response.xsl"); }
static int admin_handle_general_request (client_t *client, const char *uri) { struct admin_command *cmd; if ((client->flags & CLIENT_AUTHENTICATED) == 0) { INFO1("Bad or missing password on admin command request (%s)", uri); return client_send_401 (client, NULL); } cmd = find_admin_command (admin_general, uri); if (cmd == NULL) { INFO1 ("processing file %s", uri); return command_stats (client, uri); } if (cmd->handle.general == NULL) return client_send_400 (client, "unknown request"); return cmd->handle.general (client, cmd->response); }
static int command_buildm3u (client_t *client, const char *mount) { const char *username = NULL; const char *password = NULL; ice_config_t *config; const char *host = httpp_getvar (client->parser, "host"); if (COMMAND_REQUIRE(client, "username", username) < 0 || COMMAND_REQUIRE(client, "password", password) < 0) return client_send_400 (client, "missing arg, username/password"); client->respcode = 200; config = config_get_config(); if (host) { char port[10] = ""; if (strchr (host, ':') == NULL) snprintf (port, sizeof (port), ":%u", config->port); snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\n" "Content-Type: audio/x-mpegurl\r\n" "Content-Disposition = attachment; filename=listen.m3u\r\n\r\n" "http://%s:%s@%s%s%s\r\n", username, password, host, port, mount); } else { snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\n" "Content-Type: audio/x-mpegurl\r\n" "Content-Disposition = attachment; filename=listen.m3u\r\n\r\n" "http://%s:%s@%s:%d%s\r\n", username, password, config->hostname, config->port, mount); } config_release_config(); client->refbuf->len = strlen (client->refbuf->data); return fserve_setup_client (client); }
/* Connection thread. Here we take clients off the connection queue and check * the contents provided. We set up the parser then hand off to the specific * request handler. */ static void *_handle_connection(void *arg) { http_parser_t *parser; char *rawuri, *uri; while (global.running == ICE_RUNNING) { kitsune_update("connection_handle"); /**DSU updatepoint */ client_queue_t *node = _get_connection(); if (node) { client_t *client = node->client; /* Check for special shoutcast compatability processing */ if (node->shoutcast) { _handle_shoutcast_compatible (node); continue; } /* process normal HTTP headers */ parser = httpp_create_parser(); httpp_initialize(parser, NULL); client->parser = parser; if (httpp_parse (parser, client->refbuf->data, node->offset)) { /* we may have more than just headers, so prepare for it */ if (node->stream_offset == node->offset) client->refbuf->len = 0; else { char *ptr = client->refbuf->data; client->refbuf->len = node->offset - node->stream_offset; memmove (ptr, ptr + node->stream_offset, client->refbuf->len); } free (node); if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) { ERROR0("Bad HTTP protocol detected"); client_destroy (client); continue; } rawuri = httpp_getvar(parser, HTTPP_VAR_URI); uri = util_normalise_uri(rawuri); if (uri == NULL) { client_destroy (client); continue; } if (parser->req_type == httpp_req_source) { _handle_source_request (client, uri, ICECAST_SOURCE_AUTH); } else if (parser->req_type == httpp_req_stats) { _handle_stats_request (client, uri); } else if (parser->req_type == httpp_req_get) { _handle_get_request (client, uri); } else { ERROR0("Wrong request type from client"); client_send_400 (client, "unknown request"); } free(uri); } else { free (node); ERROR0("HTTP request parsing failed"); client_destroy (client); } continue; } thread_sleep (50000); } DEBUG0 ("Connection thread done"); return NULL; }
int admin_handle_request (client_t *client, const char *uri) { const char *mount = httpp_get_query_param(client->parser, "mount"); if (strcmp (uri, "/admin.cgi") == 0) { const char *pass = httpp_get_query_param (client->parser, "pass"); if (pass == NULL) return client_send_400 (client, "missing pass parameter"); uri++; if (mount == NULL) { if (client->server_conn && client->server_conn->shoutcast_mount) httpp_set_query_param (client->parser, "mount", client->server_conn->shoutcast_mount); mount = httpp_get_query_param (client->parser, "mount"); } httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY"); httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass); client->username = strdup ("source"); client->password = strdup (pass); } else uri += 7; if (connection_check_admin_pass (client->parser)) client->flags |= CLIENT_AUTHENTICATED; else { /* special case for slaves requesting a streamlist for authenticated relaying */ if (strcmp (uri, "streams") == 0 || strcmp (uri, "streamlist.txt") == 0) { if (connection_check_relay_pass (client->parser)) client->flags |= CLIENT_AUTHENTICATED; } } if (mount) { /* no auth/stream required for this */ if (strcmp (uri, "buildm3u") == 0) return command_buildm3u (client, mount); if (strcmp (uri, "showimage") == 0) return command_show_image (client, mount); /* This is a mount request, but admin user is allowed */ if ((client->flags & CLIENT_AUTHENTICATED) == 0) { switch (auth_check_source (client, mount)) { case 0: break; default: INFO1("Bad or missing password on mount modification " "admin request (%s)", uri); return client_send_401 (client, NULL); /* fall through */ case 1: return 0; } } if (strcmp (uri, "streams") == 0) return auth_add_listener ("/admin/streams", client); return admin_mount_request (client, uri); } return admin_handle_general_request (client, uri); }
static void command_manageauth(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node, srcnode, msgnode; const char *action = NULL; const char *username = NULL; char *message = NULL; int ret = AUTH_OK; ice_config_t *config = config_get_config (); mount_proxy *mountinfo = config_find_mount (config, source->mount); do { if (mountinfo == NULL || mountinfo->auth == NULL) { WARN1 ("manage auth request for %s but no facility available", source->mount); break; } COMMAND_OPTIONAL(client, "action", action); COMMAND_OPTIONAL (client, "username", username); if (action == NULL) action = "list"; if (!strcmp(action, "add")) { const char *password = NULL; COMMAND_OPTIONAL (client, "password", password); if (username == NULL || password == NULL) { WARN1 ("manage auth request add for %s but no user/pass", source->mount); break; } ret = mountinfo->auth->adduser(mountinfo->auth, username, password); if (ret == AUTH_FAILED) { message = strdup("User add failed - check the icecast error log"); } if (ret == AUTH_USERADDED) { message = strdup("User added"); } if (ret == AUTH_USEREXISTS) { message = strdup("User already exists - not added"); } } if (!strcmp(action, "delete")) { if (username == NULL) { WARN1 ("manage auth request delete for %s but no username", source->mount); break; } ret = mountinfo->auth->deleteuser(mountinfo->auth, username); if (ret == AUTH_FAILED) { message = strdup("User delete failed - check the icecast error log"); } if (ret == AUTH_USERDELETED) { message = strdup("User deleted"); } } doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL); srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL); xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount)); if (message) { msgnode = xmlNewChild(node, NULL, XMLSTR("iceresponse"), NULL); xmlNewChild(msgnode, NULL, XMLSTR("message"), XMLSTR(message)); } xmlDocSetRootElement(doc, node); if (mountinfo && mountinfo->auth && mountinfo->auth->listuser) mountinfo->auth->listuser (mountinfo->auth, srcnode); config_release_config (); admin_send_response(doc, client, response, MANAGEAUTH_TRANSFORMED_REQUEST); free (message); xmlFreeDoc(doc); return; } while (0); config_release_config (); client_send_400 (client, "missing parameter"); }
static void command_move_clients(client_t *client, source_t *source, int response) { const char *dest_source; source_t *dest; xmlDocPtr doc; xmlNodePtr node; char buf[255]; int parameters_passed = 0; DEBUG0("Doing optional check"); if((COMMAND_OPTIONAL(client, "destination", dest_source))) { parameters_passed = 1; } DEBUG1("Done optional check (%d)", parameters_passed); if (!parameters_passed) { doc = admin_build_sourcelist(source->mount); admin_send_response(doc, client, response, MOVECLIENTS_TRANSFORMED_REQUEST); xmlFreeDoc(doc); return; } dest = source_find_mount (dest_source); if (dest == NULL) { client_send_400 (client, "No such destination"); return; } if (strcmp (dest->mount, source->mount) == 0) { client_send_400 (client, "supplied mountpoints are identical"); return; } if (dest->running == 0 && dest->on_demand == 0) { client_send_400 (client, "Destination not running"); return; } INFO2 ("source is \"%s\", destination is \"%s\"", source->mount, dest->mount); doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); source_move_clients (source, dest); memset(buf, '\000', sizeof(buf)); snprintf (buf, sizeof(buf), "Clients moved from %s to %s", source->mount, dest_source); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); }
static void admin_handle_mount_request(client_t *client, source_t *source, int command) { switch(command) { case COMMAND_RAW_STATS: command_stats(client, source->mount, RAW); break; case COMMAND_RAW_FALLBACK: command_fallback(client, source, RAW); break; case COMMAND_RAW_METADATA_UPDATE: command_metadata(client, source, RAW); break; case COMMAND_TRANSFORMED_METADATA_UPDATE: command_metadata(client, source, TRANSFORMED); break; case COMMAND_SHOUTCAST_METADATA_UPDATE: command_shoutcast_metadata(client, source); break; case COMMAND_RAW_SHOW_LISTENERS: command_show_listeners(client, source, RAW); break; case COMMAND_RAW_MOVE_CLIENTS: command_move_clients(client, source, RAW); break; case COMMAND_RAW_KILL_CLIENT: command_kill_client(client, source, RAW); break; case COMMAND_RAW_KILL_SOURCE: command_kill_source(client, source, RAW); break; case COMMAND_TRANSFORMED_STATS: command_stats(client, source->mount, TRANSFORMED); break; case COMMAND_TRANSFORMED_FALLBACK: command_fallback(client, source, RAW); break; case COMMAND_TRANSFORMED_SHOW_LISTENERS: command_show_listeners(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_MOVE_CLIENTS: command_move_clients(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_KILL_CLIENT: command_kill_client(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_KILL_SOURCE: command_kill_source(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_MANAGEAUTH: command_manageauth(client, source, TRANSFORMED); break; case COMMAND_RAW_MANAGEAUTH: command_manageauth(client, source, RAW); break; case COMMAND_TRANSFORMED_UPDATEMETADATA: command_updatemetadata(client, source, TRANSFORMED); break; case COMMAND_RAW_UPDATEMETADATA: command_updatemetadata(client, source, RAW); break; default: WARN0("Mount request not recognised"); client_send_400(client, "Mount request unknown"); break; } }
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); } }
/* Connection thread. Here we take clients off the connection queue and check * the contents provided. We set up the parser then hand off to the specific * request handler. */ static void _handle_connection(void) { http_parser_t *parser; const char *rawuri; client_queue_t *node; while (1) { node = _get_connection(); if (node) { client_t *client = node->client; /* Check for special shoutcast compatability processing */ if (node->shoutcast) { _handle_shoutcast_compatible (node); continue; } /* process normal HTTP headers */ parser = httpp_create_parser(); httpp_initialize(parser, NULL); client->parser = parser; if (httpp_parse (parser, client->refbuf->data, node->offset)) { char *uri; /* we may have more than just headers, so prepare for it */ if (node->stream_offset == node->offset) client->refbuf->len = 0; else { char *ptr = client->refbuf->data; client->refbuf->len = node->offset - node->stream_offset; memmove (ptr, ptr + node->stream_offset, client->refbuf->len); } rawuri = httpp_getvar(parser, HTTPP_VAR_URI); /* assign a port-based shoutcast mountpoint if required */ if (node->shoutcast_mount && strcmp (rawuri, "/admin.cgi") == 0) httpp_set_query_param (client->parser, "mount", node->shoutcast_mount); free (node->shoutcast_mount); free (node); if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) { ERROR0("Bad HTTP protocol detected"); client_destroy (client); continue; } uri = util_normalise_uri(rawuri); if (uri == NULL) { client_destroy (client); continue; } if (parser->req_type == httpp_req_source || parser->req_type == httpp_req_put) { _handle_source_request (client, uri); } else if (parser->req_type == httpp_req_stats) { _handle_stats_request (client, uri); } else if (parser->req_type == httpp_req_get) { _handle_get_request (client, uri); } else { ERROR0("Wrong request type from client"); client_send_400 (client, "unknown request"); } free(uri); } else { free (node); ERROR0("HTTP request parsing failed"); client_destroy (client); } continue; } break; } }