int fserve_query_count (fbinfo *finfo) { int ret = -1; fh_node *fh; if (finfo->flags & FS_FALLBACK && finfo->limit) { avl_tree_wlock (fh_cache); fh = open_fh (finfo); if (fh) { ret = fh->refcount; thread_mutex_unlock (&fh->lock); } } else { avl_tree_rlock (fh_cache); fh = find_fh (finfo); if (fh) { thread_mutex_lock (&fh->lock); ret = fh->refcount; thread_mutex_unlock (&fh->lock); } avl_tree_unlock (fh_cache); } return ret; }
int fserve_list_clients_xml (xmlNodePtr parent, fbinfo *finfo) { int ret = 0; fh_node *fh; avl_node *anode; avl_tree_rlock (fh_cache); fh = find_fh (finfo); if (fh == NULL) { avl_tree_unlock (fh_cache); return 0; } thread_mutex_lock (&fh->lock); avl_tree_unlock (fh_cache); anode = avl_get_first (fh->clients); while (anode) { client_t *listener = (client_t *)anode->key; stats_listener_to_xml (listener, parent); ret++; anode = avl_get_next (anode); } thread_mutex_unlock (&fh->lock); return ret; }
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_set_override (const char *mount, const char *dest, format_type_t type) { fh_node fh, *result; fh.finfo.flags = FS_FALLBACK; fh.finfo.mount = (char *)mount; fh.finfo.fallback = NULL; fh.finfo.type = type; avl_tree_wlock (fh_cache); result = find_fh (&fh.finfo); if (result) { thread_mutex_lock (&result->lock); if (result->refcount > 0) { fh_node *copy = calloc (1, sizeof (*copy)); avl_delete (fh_cache, result, NULL); copy->finfo = result->finfo; copy->finfo.mount = strdup (copy->finfo.mount); copy->prev_count = -1; // trigger stats update copy->expire = (time_t)-1; copy->stats = result->stats; copy->format = result->format; copy->f = result->f; thread_mutex_create (©->lock); copy->out_bitrate = rate_setup (10000, 1000); copy->clients = avl_tree_new (client_compare, NULL); avl_insert (fh_cache, copy); result->finfo.flags |= FS_DELETE; result->finfo.flags &= ~FS_FALLBACK; result->format = NULL; result->stats = 0; result->f = SOCK_ERROR; result->finfo.fallback = strdup (dest); result->finfo.type = type; } avl_tree_unlock (fh_cache); thread_mutex_unlock (&result->lock); INFO2 ("move clients from %s to %s", mount, dest); return 1; } avl_tree_unlock (fh_cache); return 0; }
int fserve_contains (const char *name) { int ret = -1; fbinfo finfo; memset (&finfo, 0, sizeof (finfo)); if (strncmp (name, "fallback-/", 10) == 0) { finfo.mount = (char*)name+9; finfo.flags = FS_FALLBACK; } else if (strncmp (name, "file-/", 6) == 0) finfo.mount = (char*)name; DEBUG1 ("looking for %s", name); avl_tree_rlock (fh_cache); if (find_fh (&finfo)) ret = 0; avl_tree_unlock (fh_cache); return ret; }
int fserve_setup_client_fb (client_t *client, fbinfo *finfo) { fh_node *fh = &no_file; int ret = 0; refbuf_t *refbuf; ssize_t bytes; if (finfo) { mount_proxy *minfo; if (finfo->flags & FS_FALLBACK && finfo->limit == 0) return -1; avl_tree_wlock (fh_cache); fh = find_fh (finfo); minfo = config_find_mount (config_get_config(), finfo->mount); if (fh) { thread_mutex_lock (&fh->lock); avl_tree_unlock (fh_cache); client->shared_data = NULL; if (minfo) { if (minfo->max_listeners >= 0 && fh->refcount > minfo->max_listeners) { thread_mutex_unlock (&fh->lock); config_release_config(); return client_send_403redirect (client, finfo->mount, "max listeners reached"); } if (check_duplicate_logins (finfo->mount, fh->clients, client, minfo->auth) == 0) { thread_mutex_unlock (&fh->lock); config_release_config(); return client_send_403 (client, "Account already in use"); } } config_release_config(); } else { if (minfo && minfo->max_listeners == 0) { avl_tree_unlock (fh_cache); config_release_config(); client->shared_data = NULL; return client_send_403redirect (client, finfo->mount, "max listeners reached"); } config_release_config(); fh = open_fh (finfo); if (fh == NULL) return client_send_404 (client, NULL); if (fh->finfo.limit) DEBUG2 ("request for throttled file %s (bitrate %d)", fh->finfo.mount, fh->finfo.limit*8); } if (fh->finfo.limit) { client->timer_start = client->worker->current_time.tv_sec; if (client->connection.sent_bytes == 0) client->timer_start -= 2; client->counter = 0; client->intro_offset = 0; global_reduce_bitrate_sampling (global.out_bitrate); } } else { if (client->mount && (client->flags & CLIENT_AUTHENTICATED) && (client->respcode >= 300 || client->respcode < 200)) { fh = calloc (1, sizeof (no_file)); fh->finfo.mount = strdup (client->mount); fh->finfo.flags |= FS_DELETE; fh->refcount = 1; fh->f = SOCK_ERROR; thread_mutex_create (&fh->lock); } thread_mutex_lock (&fh->lock); } client->mount = fh->finfo.mount; if (fh->finfo.type == FORMAT_TYPE_UNDEFINED) { if (client->respcode == 0) { client->refbuf->len = 0; ret = format_general_headers (fh->format, client); } } else { if (fh->format->create_client_data && client->format_data == NULL) ret = fh->format->create_client_data (fh->format, client); if (fh->format->write_buf_to_client) client->check_buffer = fh->format->write_buf_to_client; } if (ret < 0) { thread_mutex_unlock (&fh->lock); return client_send_416 (client); } fh_add_client (fh, client); thread_mutex_unlock (&fh->lock); client->shared_data = fh; if (client->check_buffer == NULL) client->check_buffer = format_generic_write_to_client; // workaround for #134: fill the preallocated, but empty, chained buffer in case a range request was made if (client->flags & CLIENT_RANGE_END) { if (client->refbuf && client->refbuf->next) { refbuf = client->refbuf->next; bytes = pread (fh->f, refbuf->data, refbuf->len, client->intro_offset); if (bytes < 0) return -1; } } client->ops = &buffer_content_ops; client->flags &= ~CLIENT_HAS_INTRO_CONTENT; client->flags |= CLIENT_IN_FSERVE; if (client->flags & CLIENT_ACTIVE) { client->schedule_ms = client->worker->time_ms; if (finfo && finfo->flags & FS_FALLBACK) return 0; // prevent a recursive loop return client->ops->process (client); } else { worker_t *worker = client->worker; ret = (fh->finfo.limit) ? 0 : -1; client->flags |= CLIENT_ACTIVE; worker_wakeup (worker); /* worker may of already processed client but make sure */ } return ret; }
int fserve_setup_client_fb (client_t *client, fbinfo *finfo) { fh_node *fh = &no_file; int ret = 0; if (finfo) { mount_proxy *minfo; if (finfo->flags & FS_FALLBACK && finfo->limit == 0) return -1; avl_tree_wlock (fh_cache); fh = find_fh (finfo); minfo = config_find_mount (config_get_config(), finfo->mount); if (fh) { thread_mutex_lock (&fh->lock); avl_tree_unlock (fh_cache); client->shared_data = NULL; if (minfo) { if (minfo->max_listeners >= 0 && fh->refcount > minfo->max_listeners) { thread_mutex_unlock (&fh->lock); config_release_config(); return client_send_403redirect (client, finfo->mount, "max listeners reached"); } if (check_duplicate_logins (finfo->mount, fh->clients, client, minfo->auth) == 0) { thread_mutex_unlock (&fh->lock); config_release_config(); return client_send_403 (client, "Account already in use"); } } config_release_config(); } else { if (minfo && minfo->max_listeners == 0) { avl_tree_unlock (fh_cache); config_release_config(); client->shared_data = NULL; return client_send_403redirect (client, finfo->mount, "max listeners reached"); } config_release_config(); fh = open_fh (finfo); if (fh == NULL) return client_send_404 (client, NULL); } if (fh->finfo.limit) { client->timer_start = client->worker->current_time.tv_sec; if (client->connection.sent_bytes == 0) client->timer_start -= 2; client->counter = 0; client->intro_offset = 0; global_reduce_bitrate_sampling (global.out_bitrate); } } else thread_mutex_lock (&fh->lock); client->mount = fh->finfo.mount; if (fh->finfo.type == FORMAT_TYPE_UNDEFINED) { if (client->respcode == 0) { client->refbuf->len = 0; ret = format_general_headers (fh->format, client); } } else { if (fh->format->create_client_data && client->format_data == NULL) ret = fh->format->create_client_data (fh->format, client); if (fh->format->write_buf_to_client) client->check_buffer = fh->format->write_buf_to_client; } if (ret < 0) { thread_mutex_unlock (&fh->lock); return client_send_416 (client); } fh_add_client (fh, client); thread_mutex_unlock (&fh->lock); client->shared_data = fh; if (client->check_buffer == NULL) client->check_buffer = format_generic_write_to_client; client->ops = &buffer_content_ops; client->flags &= ~CLIENT_HAS_INTRO_CONTENT; client->flags |= CLIENT_IN_FSERVE; if (client->flags & CLIENT_ACTIVE) { client->schedule_ms = client->worker->time_ms; if (finfo && finfo->flags & FS_FALLBACK) return 0; // prevent a recursive loop return client->ops->process (client); } else { worker_t *worker = client->worker; client->flags |= CLIENT_ACTIVE; worker_wakeup (worker); /* worker may of already processed client but make sure */ } return 0; }