void fserve_scan (time_t now) { avl_node *node; avl_tree_wlock (fh_cache); node = avl_get_first (fh_cache); while (node) { fh_node *fh = node->key; node = avl_get_next (node); thread_mutex_lock (&fh->lock); if (global.running != ICE_RUNNING) fh->expire = 0; if (now == (time_t)0) { fh->expire = 0; thread_mutex_unlock (&fh->lock); continue; } if (fh->finfo.limit) { fbinfo *finfo = &fh->finfo; if (fh->stats == 0) { int len = strlen (finfo->mount) + 10; char *str = alloca (len); char buf[20]; snprintf (str, len, "%s-%s", (finfo->flags & FS_FALLBACK) ? "fallback" : "file", finfo->mount); fh->stats = stats_handle (str); stats_set_flags (fh->stats, "fallback", "file", STATS_COUNTERS|STATS_HIDDEN); stats_set_flags (fh->stats, "outgoing_kbitrate", "0", STATS_COUNTERS|STATS_HIDDEN); snprintf (buf, sizeof (buf), "%d", fh->refcount); stats_set_flags (fh->stats, "listeners", buf, STATS_GENERAL|STATS_HIDDEN); snprintf (buf, sizeof (buf), "%d", fh->peak); stats_set_flags (fh->stats, "listener_peak", buf, STATS_GENERAL|STATS_HIDDEN); fh->prev_count = fh->refcount; } else { stats_lock (fh->stats, NULL); if (fh->prev_count != fh->refcount) { fh->prev_count = fh->refcount; stats_set_args (fh->stats, "listeners", "%ld", fh->refcount); stats_set_args (fh->stats, "listener_peak", "%ld", fh->peak); } } if (fh->stats_update <= now) { fh->stats_update = now + 5; stats_set_args (fh->stats, "outgoing_kbitrate", "%ld", (long)((8 * rate_avg (fh->out_bitrate))/1024)); } stats_release (fh->stats); } if (fh->refcount == 0 && fh->expire >= 0 && now >= fh->expire) { DEBUG1 ("timeout of %s", fh->finfo.mount); if (fh->stats) { stats_lock (fh->stats, NULL); stats_set (fh->stats, NULL, NULL); } remove_fh_from_cache (fh); thread_mutex_unlock (&fh->lock); _delete_fh (fh); continue; } thread_mutex_unlock (&fh->lock); } avl_tree_unlock (fh_cache); }
static void process_source_stat (stats_source_t *src_stats, stats_event_t *event) { if (event->name) { stats_node_t *node = _find_node (src_stats->stats_tree, event->name); if (node == NULL) { /* adding node */ if (event->action != STATS_EVENT_REMOVE && event->value) { DEBUG3 ("new node on %s \"%s\" (%s)", src_stats->source, event->name, event->value); node = (stats_node_t *)calloc (1,sizeof(stats_node_t)); node->name = (char *)strdup (event->name); node->value = (char *)strdup (event->value); node->flags = event->flags; if (src_stats->flags & STATS_HIDDEN) node->flags |= STATS_HIDDEN; stats_listener_send (node->flags, "EVENT %s %s %s\n", src_stats->source, event->name, event->value); avl_insert (src_stats->stats_tree, (void *)node); } return; } if (event->action == STATS_EVENT_REMOVE) { DEBUG2 ("delete node %s from %s", event->name, src_stats->source); stats_listener_send (node->flags, "DELETE %s %s\n", src_stats->source, event->name); avl_delete (src_stats->stats_tree, (void *)node, _free_stats); return; } modify_node_event (node, event); stats_listener_send (node->flags, "EVENT %s %s %s\n", src_stats->source, node->name, node->value); return; } if (event->action == STATS_EVENT_REMOVE && event->name == NULL) { avl_tree_unlock (src_stats->stats_tree); avl_tree_wlock (_stats.source_tree); avl_tree_wlock (src_stats->stats_tree); avl_delete (_stats.source_tree, (void *)src_stats, _free_source_stats); avl_tree_unlock (_stats.source_tree); return; } /* change source flags status */ if (event->action & STATS_EVENT_HIDDEN) { avl_node *node = avl_get_first (src_stats->stats_tree); int visible = 0; if ((event->flags&STATS_HIDDEN) == (src_stats->flags&STATS_HIDDEN)) return; if (src_stats->flags & STATS_HIDDEN) { stats_node_t *ct = _find_node (src_stats->stats_tree, "server_type"); const char *type = "audio/mpeg"; if (ct) type = ct->value; src_stats->flags &= ~STATS_HIDDEN; stats_listener_send (src_stats->flags, "NEW %s %s\n", type, src_stats->source); visible = 1; } else { stats_listener_send (src_stats->flags, "DELETE %s\n", src_stats->source); src_stats->flags |= STATS_HIDDEN; } while (node) { stats_node_t *stats = (stats_node_t*)node->key; if (visible) { stats->flags &= ~STATS_HIDDEN; stats_listener_send (stats->flags, "EVENT %s %s %s\n", src_stats->source, stats->name, stats->value); } else stats->flags |= STATS_HIDDEN; node = avl_get_next (node); } } }
/* build an XML doc containing information about currently running sources. * If a mountpoint is passed then that source will not be added to the XML * doc even if the source is running */ xmlDocPtr admin_build_sourcelist (const char *mount) { avl_node *node; source_t *source; xmlNodePtr xmlnode, srcnode; xmlDocPtr doc; char buf[22]; time_t now = time(NULL); doc = xmlNewDoc (XMLSTR("1.0")); xmlnode = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL); xmlDocSetRootElement(doc, xmlnode); if (mount) { xmlNewChild (xmlnode, NULL, XMLSTR("current_source"), XMLSTR(mount)); } node = avl_get_first(global.source_tree); while(node) { source = (source_t *)node->key; if (mount && strcmp (mount, source->mount) == 0) { node = avl_get_next (node); continue; } if (source->running || source->on_demand) { ice_config_t *config; mount_proxy *mountinfo; srcnode = xmlNewChild(xmlnode, NULL, XMLSTR("source"), NULL); xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount)); xmlNewChild(srcnode, NULL, XMLSTR("fallback"), (source->fallback_mount != NULL)? XMLSTR(source->fallback_mount):XMLSTR("")); snprintf (buf, sizeof(buf), "%lu", source->listeners); xmlNewChild(srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf)); config = config_get_config(); mountinfo = config_find_mount (config, source->mount); if (mountinfo && mountinfo->auth) { xmlNewChild(srcnode, NULL, XMLSTR("authenticator"), XMLSTR(mountinfo->auth->type)); } config_release_config(); if (source->running) { if (source->client) { snprintf (buf, sizeof(buf), "%lu", (unsigned long)(now - source->con->con_time)); xmlNewChild (srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf)); } xmlNewChild (srcnode, NULL, XMLSTR("content-type"), XMLSTR(source->format->contenttype)); } } node = avl_get_next(node); } return(doc); }
static int format_prepare_headers (source_t *source, client_t *client) { unsigned remaining; char *ptr; int bytes; int bitrate_filtered = 0; avl_node *node; remaining = client->refbuf->len; ptr = client->refbuf->data; client->respcode = 200; bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source, client); if (bytes == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_error(client, 500, 0, "Header generation failed."); return -1; } else if ((bytes + 1024) >= remaining) { /* we don't know yet how much to follow but want at least 1kB free space */ void *new_ptr = realloc(ptr, bytes + 1024); if (new_ptr) { ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); client->refbuf->data = ptr = new_ptr; client->refbuf->len = remaining = bytes + 1024; bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source, client); if (bytes == -1 ) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_error(client, 500, 0, "Header generation failed."); return -1; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); client_send_error(client, 500, 0, "Buffer reallocation failed."); return -1; } } remaining -= bytes; ptr += 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) { int next = 1; http_var_t *var = (http_var_t *) node->key; bytes = 0; if (!strcasecmp(var->name, "ice-audio-info")) { /* convert ice-audio-info to icy-br */ char *brfield = NULL; unsigned int bitrate; if (bitrate_filtered == 0) brfield = strstr(var->value, "bitrate="); if (brfield && sscanf (brfield, "bitrate=%u", &bitrate)) { bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate); next = 0; bitrate_filtered = 1; } else /* show ice-audio_info header as well because of relays */ bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value); } else { if (strcasecmp(var->name, "ice-password") && strcasecmp(var->name, "icy-metaint")) { if (!strcasecmp(var->name, "ice-name")) { ice_config_t *config; mount_proxy *mountinfo; config = config_get_config(); mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL); if (mountinfo && mountinfo->stream_name) bytes = snprintf (ptr, remaining, "icy-name:%s\r\n", mountinfo->stream_name); else bytes = snprintf (ptr, remaining, "icy-name:%s\r\n", var->value); config_release_config(); } else if (!strncasecmp("ice-", var->name, 4)) { if (!strcasecmp("ice-public", var->name)) bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value); else if (!strcasecmp ("ice-bitrate", var->name)) bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value); else bytes = snprintf (ptr, remaining, "icy%s:%s\r\n", var->name + 3, var->value); } else if (!strncasecmp("icy-", var->name, 4)) { bytes = snprintf (ptr, remaining, "icy%s:%s\r\n", var->name + 3, var->value); } } } remaining -= bytes; ptr += bytes; if (next) node = avl_get_next(node); } avl_tree_unlock(source->parser->vars); bytes = snprintf(ptr, remaining, "\r\n"); remaining -= bytes; ptr += bytes; client->refbuf->len -= remaining; if (source->format->create_client_data) if (source->format->create_client_data (source, client) < 0) return -1; return 0; }
// requires xslt_lock before being called, released on return static int xslt_send_sheet (client_t *client, xmlDocPtr doc, int idx) { xmlDocPtr res; xsltStylesheetPtr cur = cache [idx].stylesheet; char **params = NULL; refbuf_t *content = NULL; int len; if (client->parser->queryvars) { // annoying but we need to surround the args with ' when passing them in int j, arg_count = client->parser->queryvars->length * 2; avl_node *node = avl_get_first (client->parser->queryvars); params = calloc (arg_count+1, sizeof (char *)); for (j = 0; node && j < arg_count; node = avl_get_next (node)) { http_var_t *param = (http_var_t *)node->key; char *tmp = util_url_escape (param->value); params[j++] = param->name; // use alloca for now, should really url esc into a supplied buffer params[j] = (char*)alloca (strlen (tmp) + 3); sprintf (params[j++], "\'%s\'", tmp); free (tmp); } params[j] = NULL; } res = xsltApplyStylesheet (cur, doc, (const char **)params); free (params); client->shared_data = NULL; if (res == NULL || xslt_SaveResultToBuf (&content, &len, res, cur) < 0) { thread_rwlock_unlock (&xslt_lock); xmlFreeDoc (res); xmlFreeDoc (doc); WARN1 ("problem applying stylesheet \"%s\"", cache [idx].filename); return client_send_404 (client, "XSLT problem"); } else { /* the 100 is to allow for the hardcoded headers */ refbuf_t *refbuf = refbuf_new (500); const char *mediatype = NULL; /* lets find out the content type to use */ if (cur->mediaType) mediatype = (char *)cur->mediaType; else { /* check method for the default, a missing method assumes xml */ if (cur->method && xmlStrcmp (cur->method, XMLSTR("html")) == 0) mediatype = "text/html"; else if (cur->method && xmlStrcmp (cur->method, XMLSTR("text")) == 0) mediatype = "text/plain"; else mediatype = "text/xml"; } snprintf (refbuf->data, 500, "HTTP/1.0 200 OK\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s" "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" "Cache-Control: no-store, no-cache, must-revalidate\r\n" "Pragma: no-cache\r\n%s\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type\r\n" "Access-Control-Allow-Methods: GET, OPTIONS, HEAD\r\n" "\r\n", mediatype, len, cache[idx].disposition ? cache[idx].disposition : "", client_keepalive_header (client)); thread_rwlock_unlock (&xslt_lock); client->respcode = 200; client_set_queue (client, NULL); client->refbuf = refbuf; refbuf->len = strlen (refbuf->data); refbuf->next = content; } xmlFreeDoc(res); xmlFreeDoc(doc); return fserve_setup_client (client); }
static void process_source_event (stats_event_t *event) { stats_source_t *snode = _find_source(_stats.source_tree, event->source); if (snode == NULL) { if (event->action == STATS_EVENT_REMOVE) return; snode = (stats_source_t *)calloc(1,sizeof(stats_source_t)); if (snode == NULL) return; DEBUG1 ("new source stat %s", event->source); snode->source = (char *)strdup(event->source); snode->stats_tree = avl_tree_new(_compare_stats, NULL); if (event->action == STATS_EVENT_HIDDEN) snode->hidden = 1; else snode->hidden = 0; avl_insert(_stats.source_tree, (void *)snode); } if (event->name) { stats_node_t *node = _find_node(snode->stats_tree, event->name); if (node == NULL) { if (event->action == STATS_EVENT_REMOVE) return; /* adding node */ if (event->value) { DEBUG2 ("new node %s (%s)", event->name, event->value); node = (stats_node_t *)calloc(1,sizeof(stats_node_t)); node->name = (char *)strdup(event->name); node->value = (char *)strdup(event->value); node->hidden = snode->hidden; avl_insert(snode->stats_tree, (void *)node); } return; } if (event->action == STATS_EVENT_REMOVE) { DEBUG1 ("delete node %s", event->name); avl_delete(snode->stats_tree, (void *)node, _free_stats); return; } modify_node_event (node, event); return; } if (event->action == STATS_EVENT_HIDDEN) { avl_node *node = avl_get_first (snode->stats_tree); if (event->value) snode->hidden = 1; else snode->hidden = 0; while (node) { stats_node_t *stats = (stats_node_t*)node->key; stats->hidden = snode->hidden; node = avl_get_next (node); } return; } if (event->action == STATS_EVENT_REMOVE) { DEBUG1 ("delete source node %s", event->source); avl_delete(_stats.source_tree, (void *)snode, _free_source_stats); } }
/* factoring out code for stats loops ** this function copies all stats to queue, and registers */ static void _register_listener (client_t *client) { event_listener_t *listener = client->shared_data; avl_node *node; stats_event_t stats_count; refbuf_t *refbuf; size_t size = 8192; char buffer[20]; build_event (&stats_count, NULL, "stats_connections", buffer); stats_count.action = STATS_EVENT_INC; process_event (&stats_count); /* first we fill our queue with the current stats */ refbuf = refbuf_new (size); refbuf->len = 0; /* the global stats */ avl_tree_rlock (_stats.global_tree); node = avl_get_first(_stats.global_tree); while (node) { stats_node_t *stat = node->key; if (stat->flags & listener->mask) { if (_append_to_buffer (refbuf, size, "EVENT global %s %s\n", stat->name, stat->value) < 0) { _add_node_to_stats_client (client, refbuf); refbuf = refbuf_new (size); refbuf->len = 0; continue; } } node = avl_get_next(node); } avl_tree_unlock (_stats.global_tree); /* now the stats for each source */ avl_tree_rlock (_stats.source_tree); node = avl_get_first(_stats.source_tree); while (node) { avl_node *node2; stats_node_t *metadata_stat = NULL; stats_source_t *snode = (stats_source_t *)node->key; if (snode->flags & listener->mask) { stats_node_t *ct = _find_node (snode->stats_tree, "content-type"); const char *type = "audio/mpeg"; if (ct) type = ct->name; if (_append_to_buffer (refbuf, size, "NEW %s %s\n", type, snode->source) < 0) { _add_node_to_stats_client (client, refbuf); refbuf = refbuf_new (size); refbuf->len = 0; continue; } } node = avl_get_next(node); avl_tree_rlock (snode->stats_tree); node2 = avl_get_first(snode->stats_tree); while (node2) { stats_node_t *stat = node2->key; if (metadata_stat == NULL && strcmp (stat->name, "metadata_updated") == 0) metadata_stat = stat; else if (stat->flags & listener->mask) { if (_append_to_buffer (refbuf, size, "EVENT %s %s %s\n", snode->source, stat->name, stat->value) < 0) { _add_node_to_stats_client (client, refbuf); refbuf = refbuf_new (size); refbuf->len = 0; continue; } } node2 = avl_get_next (node2); } while (metadata_stat) { if (_append_to_buffer (refbuf, size, "EVENT %s %s %s\n", snode->source, metadata_stat->name, metadata_stat->value) < 0) { _add_node_to_stats_client (client, refbuf); refbuf = refbuf_new (size); refbuf->len = 0; continue; } break; } avl_tree_unlock (snode->stats_tree); } avl_tree_unlock (_stats.source_tree); _add_node_to_stats_client (client, refbuf); /* now we register to receive future event notices */ thread_mutex_lock (&_stats.listeners_lock); listener->next = _stats.event_listeners; _stats.event_listeners = listener; thread_mutex_unlock (&_stats.listeners_lock); }
void source_main (source_t *source) { unsigned int listeners; refbuf_t *refbuf; client_t *client; avl_node *client_node; source_init (source); while (global.running == ICE_RUNNING && source->running) { int remove_from_q; refbuf = get_next_buffer (source); remove_from_q = 0; source->short_delay = 0; if (refbuf) { /* append buffer to the in-flight data queue, */ if (source->stream_data == NULL) { source->stream_data = refbuf; source->burst_point = refbuf; } if (source->stream_data_tail) source->stream_data_tail->next = refbuf; source->stream_data_tail = refbuf; source->queue_size += refbuf->len; /* new buffer is referenced for burst */ refbuf_addref (refbuf); /* new data on queue, so check the burst point */ source->burst_offset += refbuf->len; if (source->burst_offset > source->burst_size) { if (source->burst_point->next) { refbuf_release (source->burst_point); source->burst_point = source->burst_point->next; source->burst_offset -= source->burst_point->len; } } /* save stream to file */ if (source->dumpfile && source->format->write_buf_to_file) source->format->write_buf_to_file (source, refbuf); } /* lets see if we have too much data in the queue, but don't remove it until later */ if (source->queue_size > source->queue_size_limit) remove_from_q = 1; /* acquire write lock on client_tree */ avl_tree_wlock(source->client_tree); listeners = source->listeners; client_node = avl_get_first(source->client_tree); while (client_node) { client = (client_t *)client_node->key; send_to_listener (source, client, remove_from_q); if (client->con->error) { client_node = avl_get_next(client_node); avl_delete(source->client_tree, (void *)client, _free_client); source->listeners--; DEBUG0("Client removed"); continue; } client_node = avl_get_next(client_node); } /* 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) { if(source->max_listeners != -1 && source->listeners >= source->max_listeners) { /* The common case is caught in the main connection handler, * this deals with rarer cases (mostly concerning fallbacks) * and doesn't give the listening client any information about * why they were disconnected */ client = (client_t *)client_node->key; client_node = avl_get_next(client_node); avl_delete(source->pending_tree, (void *)client, _free_client); INFO0("Client deleted, exceeding maximum listeners for this " "mountpoint."); continue; } /* Otherwise, the client is accepted, add it */ avl_insert(source->client_tree, client_node->key); source->listeners++; DEBUG0("Client added"); stats_event_inc(NULL, "clients"); stats_event_inc(source->mount, "connections"); 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); } /* release write lock on pending_tree */ avl_tree_unlock(source->pending_tree); /* update the stats if need be */ if (source->listeners != listeners) { INFO2("listener count on %s now %d", source->mount, source->listeners); stats_event_args (source->mount, "listeners", "%d", source->listeners); } /* lets reduce the queue, any lagging clients should of been * terminated by now */ if (source->stream_data) { /* normal unreferenced queue data will have a refcount 1, but * burst queue data will be at least 2, active clients will also * increase refcount */ while (source->stream_data->_count == 1) { refbuf_t *to_go = source->stream_data; if (to_go->next == NULL || source->burst_point == to_go) { /* this should not happen */ ERROR0 ("queue state is unexpected"); source->running = 0; break; } source->stream_data = to_go->next; source->queue_size -= to_go->len; refbuf_release (to_go); } } /* release write lock on client_tree */ avl_tree_unlock(source->client_tree); } source_shutdown (source); }
/* Move clients from source to dest provided dest is running * and that the stream format is the same. * The only lock that should be held when this is called is the * source tree lock */ void source_move_clients (source_t *source, source_t *dest) { /* we don't want the two write locks to deadlock in here */ thread_mutex_lock (&move_clients_mutex); /* if the destination is not running then we can't move clients */ if (dest->running == 0) { WARN1 ("destination mount %s not running, unable to move clients ", dest->mount); thread_mutex_unlock (&move_clients_mutex); return; } avl_tree_wlock (dest->pending_tree); do { client_t *client; /* we need to move the client and pending trees */ avl_tree_wlock (source->pending_tree); if (source->format == NULL) { INFO1 ("source mount %s is not available", source->mount); break; } if (source->format->type != dest->format->type) { WARN2 ("stream %s and %s are of different types, ignored", source->mount, dest->mount); break; } while (1) { avl_node *node = avl_get_first (source->pending_tree); if (node == NULL) break; client = (client_t *)(node->key); avl_delete (source->pending_tree, client, NULL); /* switch client to different queue */ client_set_queue (client, dest->stream_data_tail); avl_insert (dest->pending_tree, (void *)client); } avl_tree_wlock (source->client_tree); while (1) { avl_node *node = avl_get_first (source->client_tree); if (node == NULL) break; client = (client_t *)(node->key); avl_delete (source->client_tree, client, NULL); /* switch client to different queue */ client_set_queue (client, dest->stream_data_tail); avl_insert (dest->pending_tree, (void *)client); } source->listeners = 0; stats_event (source->mount, "listeners", "0"); avl_tree_unlock (source->client_tree); } while (0); avl_tree_unlock (source->pending_tree); avl_tree_unlock (dest->pending_tree); thread_mutex_unlock (&move_clients_mutex); }
void source_clear_source (source_t *source) { DEBUG1 ("clearing source \"%s\"", source->mount); client_destroy(source->client); source->client = NULL; source->parser = NULL; source->con = NULL; if (source->dumpfile) { INFO1 ("Closing dumpfile for %s", source->mount); fclose (source->dumpfile); source->dumpfile = NULL; } /* lets kick off any clients that are left on here */ avl_tree_rlock (source->client_tree); while (avl_get_first (source->client_tree)) { avl_delete (source->client_tree, avl_get_first (source->client_tree)->key, _free_client); } avl_tree_unlock (source->client_tree); avl_tree_rlock (source->pending_tree); while (avl_get_first (source->pending_tree)) { avl_delete (source->pending_tree, avl_get_first(source->pending_tree)->key, _free_client); } avl_tree_unlock (source->pending_tree); if (source->format && source->format->free_plugin) { source->format->free_plugin (source->format); } source->format = NULL; if (source->yp_public) yp_remove (source->mount); source->burst_point = NULL; source->burst_size = 0; source->burst_offset = 0; source->queue_size = 0; source->queue_size_limit = 0; source->listeners = 0; source->no_mount = 0; source->shoutcast_compat = 0; source->max_listeners = -1; source->yp_public = 0; source->yp_prevent = 0; source->hidden = 0; util_dict_free (source->audio_info); source->audio_info = NULL; free(source->fallback_mount); source->fallback_mount = NULL; free(source->dumpfilename); source->dumpfilename = NULL; /* Lets clear out the source queue too */ while (source->stream_data) { refbuf_t *p = source->stream_data; source->stream_data = p->next; /* can be referenced by burst handler as well */ while (p->_count > 1) refbuf_release (p); refbuf_release (p); } source->stream_data_tail = NULL; }
static int command_manage_relay (client_t *client, int response) { const char *relay_mount, *enable; const char *msg; relay_server *relay; xmlDocPtr doc; xmlNodePtr node; COMMAND_OPTIONAL (client, "relay", relay_mount); COMMAND_OPTIONAL (client, "enable", enable); if (relay_mount == NULL || enable == NULL) { avl_node *relaynode; doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode (doc, NULL, XMLSTR("icerelaystats"), NULL); xmlDocSetRootElement(doc, node); avl_tree_rlock (global.relays); relaynode = avl_get_first (global.relays); while (relaynode) { relay_server *relay = (relay_server*)relaynode->key; add_relay_xmlnode (node, relay); relaynode = avl_get_next (relaynode); } avl_tree_unlock (global.relays); return admin_send_response (doc, client, response, "managerelays.xsl"); } avl_tree_rlock (global.relays); relay = slave_find_relay (relay_mount); msg = "no such relay"; if (relay) { source_t *source = relay->source; client_t *client; thread_rwlock_wlock (&source->lock); client = source->client; if (atoi (enable)) relay->flags |= RELAY_RUNNING; else relay->flags &= ~RELAY_RUNNING; if (client) { client->schedule_ms = 0; worker_wakeup (client->worker); } thread_rwlock_unlock (&source->lock); msg = "relay has been changed"; } avl_tree_unlock (global.relays); doc = xmlNewDoc(XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(msg)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); return admin_send_response(doc, client, response, "response.xsl"); }