static void queue_auth_client (auth_client *auth_user, mount_proxy *mountinfo) { auth_t *auth; client_t *failed = NULL; auth_client **old_tail; if (auth_user == NULL || mountinfo == NULL) return; auth = mountinfo->auth; thread_mutex_lock (&auth->lock); auth_user->next = NULL; auth_user->auth = auth; old_tail = auth->tailp; *auth->tailp = auth_user; auth->tailp = &auth_user->next; auth->pending_count++; if (auth->refcount > auth->handlers) DEBUG0 ("max authentication handlers allocated"); else { int i; for (i=0; i<auth->handlers; i++) { if (auth->handles [i].thread == NULL) { DEBUG1 ("starting auth thread %d", i); auth->refcount++; auth->handles [i].thread = thread_create ("auth thread", auth_run_thread, &auth->handles [i], THREAD_DETACHED); if (auth->handles [i].thread == NULL) { auth->tailp = old_tail; *old_tail = NULL; auth->pending_count--; auth->refcount--; failed = auth_user->client; auth_user->client = NULL; ERROR0 ("failed to start auth thread, system limit probably reached"); } break; } } } DEBUG2 ("auth on %s has %d pending", auth->mount, auth->pending_count); thread_mutex_unlock (&auth->lock); if (failed) { client_send_403redirect (failed, auth_user->mount, "system limit reached"); auth_client_free (auth_user); } }
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; }