static void worker_stop (void) { worker_t *handler; if (workers == NULL) return; thread_rwlock_wlock (&workers_lock); handler = workers; workers = handler->next; worker_least_used = worker_balance_to_check = workers; if (workers) workers->move_allocations = 100; worker_count--; thread_rwlock_unlock (&workers_lock); handler->running = 0; worker_wakeup (handler); thread_join (handler->thread); thread_spin_destroy (&handler->lock); sock_close (handler->wakeup_fd[1]); sock_close (handler->wakeup_fd[0]); free (handler); }
void connection_accept_loop(void) { connection_t *con; _build_pool(); while (global.running == ICE_RUNNING) { if (global . schedule_config_reread) { /* reread config file */ INFO0("Scheduling config reread ..."); connection_inject_event(EVENT_CONFIG_READ, NULL); global . schedule_config_reread = 0; } con = _accept_connection(); if (con) { _add_connection(con); } } /* Give all the other threads notification to shut down */ thread_cond_broadcast(&global.shutdown_cond); _destroy_pool(); /* wait for all the sources to shutdown */ thread_rwlock_wlock(&_source_shutdown_rwlock); thread_rwlock_unlock(&_source_shutdown_rwlock); }
static void worker_start (void) { worker_t *handler = calloc (1, sizeof(worker_t)); worker_control_create (&handler->wakeup_fd[0]); handler->pending_clients_tail = &handler->pending_clients; thread_spin_create (&handler->lock); handler->last_p = &handler->clients; thread_rwlock_wlock (&workers_lock); if (worker_incoming == NULL) { worker_incoming = handler; handler->thread = thread_create ("worker", worker, handler, THREAD_ATTACHED); thread_rwlock_unlock (&workers_lock); INFO0 ("starting incoming worker thread"); worker_start(); // single level recursion, just get a special worker thread set up return; } handler->next = workers; workers = handler; worker_count++; worker_least_used = worker_balance_to_check = workers; thread_rwlock_unlock (&workers_lock); handler->thread = thread_create ("worker", worker, handler, THREAD_ATTACHED); }
void auth_shutdown (void) { if (allow_auth == 0) return; allow_auth = 0; thread_rwlock_wlock (&auth_lock); thread_rwlock_unlock (&auth_lock); thread_rwlock_destroy (&auth_lock); INFO0 ("Auth shutdown complete"); }
static void *yp_update_thread(void *arg) { if (!kitsune_is_updating()) { /**DSU control */ INFO0("YP update thread started"); yp_running = 1; } while (yp_running) { kitsune_update("yp_update"); /**DSU updatepoint */ struct yp_server *server; thread_sleep (200000); /* do the YP communication */ thread_rwlock_rlock (&yp_lock); server = (struct yp_server *)active_yps; while (server) { /* DEBUG1 ("trying %s", server->url); */ yp_process_server (server); server = server->next; } thread_rwlock_unlock (&yp_lock); /* update the local YP structure */ if (yp_update) { thread_rwlock_wlock (&yp_lock); check_servers (); server = (struct yp_server *)active_yps; while (server) { /* DEBUG1 ("Checking yps %s", server->url); */ add_pending_yp (server); delete_marked_yp (server); server = server->next; } yp_update = 0; thread_rwlock_unlock (&yp_lock); } } thread_rwlock_destroy (&yp_lock); thread_mutex_destroy (&yp_pending_lock); /* free server and ypdata left */ while (active_yps) { struct yp_server *server = (struct yp_server *)active_yps; active_yps = server->next; destroy_yp_server (server); } return NULL; }
static void worker_stop (void) { worker_t *handler; thread_rwlock_wlock (&workers_lock); do { if (worker_count > 0) { handler = workers; workers = handler->next; worker_least_used = worker_balance_to_check = workers; if (workers) workers->move_allocations = 100; worker_count--; } else { handler = worker_incoming; worker_incoming = NULL; INFO0 ("stopping incoming worker thread"); } thread_rwlock_unlock (&workers_lock); if (handler) { handler->running = 0; worker_wakeup (handler); thread_join (handler->thread); thread_spin_destroy (&handler->lock); sock_close (handler->wakeup_fd[1]); sock_close (handler->wakeup_fd[0]); free (handler); } thread_rwlock_wlock (&workers_lock); } while (workers == NULL && worker_incoming); }
int auth_deleteuser(source_t *source, char *username) { htpasswd_auth_state *state; int ret = 0; if (source->authenticator) { if (!strcmp(source->authenticator->type, "htpasswd")) { state = source->authenticator->state; thread_rwlock_wlock(&state->file_rwlock); ret = auth_htpasswd_deleteuser(source->authenticator, username); thread_rwlock_unlock(&state->file_rwlock); } } return ret; }
/* thread to read xsl file and add to the cache */ void *xslt_update (void *arg) { xsl_req *x = arg; client_t *client = x->client; char *fn = x->cache.filename; xsltStylesheetPtr sheet; xmlSetStructuredErrorFunc ("xsl/file", config_xml_parse_failure); xsltSetGenericErrorFunc ("", log_parse_failure); sheet = x->cache.stylesheet = xsltParseStylesheetFile (XMLSTR(fn)); if (sheet) { int i; INFO1 ("loaded stylesheet %s", x->cache.filename); if (sheet->mediaType && strcmp ((char*)sheet->mediaType, "text/html") != 0) { // avoid this lookup for html pages const char _hdr[] = "Content-Disposition: attachment; filename=\"file."; const size_t _hdrlen = sizeof (_hdr); size_t len = _hdrlen + 12; char *filename = malloc (len); // enough for name and extension strcpy (filename, _hdr); fserve_write_mime_ext ((char*)sheet->mediaType, filename + _hdrlen - 1, len - _hdrlen - 4); strcat (filename, "\"\r\n"); x->cache.disposition = filename; } // we now have a sheet, find and update. thread_rwlock_wlock (&xslt_lock); i = xslt_cached (fn, &x->cache, time(NULL)); xslt_send_sheet (client, x->doc, i); } else { WARN1 ("problem reading stylesheet \"%s\"", x->cache.filename); free (fn); xmlFreeDoc (x->doc); free (x->cache.disposition); client->shared_data = NULL; client_send_404 (client, "Could not parse XSLT file"); } thread_spin_lock (&update_lock); xsl_updating--; thread_spin_unlock (&update_lock); free (x); return NULL; }
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_rwlock_wlock (&source->lock); if (source_available (source) == 0) { thread_rwlock_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 void worker_start (void) { worker_t *handler = calloc (1, sizeof(worker_t)); worker_control_create (handler); handler->pending_clients_tail = &handler->pending_clients; thread_spin_create (&handler->lock); thread_rwlock_wlock (&workers_lock); handler->last_p = &handler->clients; handler->next = workers; workers = handler; worker_count++; worker_least_used = worker_balance_to_check = workers; handler->thread = thread_create ("worker", worker, handler, THREAD_ATTACHED); thread_rwlock_unlock (&workers_lock); }
static void *yp_update_thread(void *arg) { struct yp_server *server; yp_thread = thread_self(); /* DEBUG0("YP thread started"); */ /* do the YP communication */ thread_rwlock_rlock (&yp_lock); ypclient.counter = -1; server = (struct yp_server *)active_yps; while (server) { /* DEBUG1 ("trying %s", server->url); */ yp_process_server (server); server = server->next; } thread_rwlock_unlock (&yp_lock); /* update the local YP structure */ if (yp_update) { thread_rwlock_wlock (&yp_lock); check_servers (); server = (struct yp_server *)active_yps; while (server) { /* DEBUG1 ("Checking yps %s", server->url); */ add_pending_yp (server); delete_marked_yp (server); server = server->next; } yp_update = 0; thread_rwlock_unlock (&yp_lock); } yp_thread = NULL; /* DEBUG0("YP thread shutdown"); */ ypclient.flags |= CLIENT_ACTIVE; worker_wakeup (ypclient.worker); return NULL; }
int relay_toggle (relay_server *relay) { source_t *source = relay->source; client_t *client; int ret = 0; thread_rwlock_wlock (&source->lock); client = source->client; thread_rwlock_unlock (&source->lock); if (relay->running == 0) { client->ops = &relay_init_ops; ret = 1; } relay->running = relay->running ? 0 : 1; client->schedule_ms = 0; worker_wakeup (client->worker); slave_update_all_mounts(); return ret; }
/* thread to read xsl file and add to the cache */ void *xslt_update (void *arg) { xsl_req *x = arg; client_t *client = x->client; worker_t *worker = client ? client->worker : NULL; char *fn = x->cache.filename; x->cache.stylesheet = xsltParseStylesheetFile (XMLSTR(fn)); if (x->cache.stylesheet) { int i = x->index; if (client) fn = strdup (fn); // need to copy the filename if another lookup is to do INFO1 ("loaded stylesheet %s", x->cache.filename); thread_rwlock_wlock (&xslt_lock); free (cache[i].filename); xsltFreeStylesheet (cache[i].stylesheet); memcpy (&cache[i], &x->cache, sizeof (stylesheet_cache_t)); thread_rwlock_unlock (&xslt_lock); memset (&x->cache, 0, sizeof (stylesheet_cache_t)); if (client) { x->cache.filename = fn; client->flags |= CLIENT_ACTIVE; } } else { WARN1 ("problem reading stylesheet \"%s\"", x->cache.filename); free (fn); if (client) client_send_404 (client, "Could not parse XSLT file"); } thread_spin_lock (&update_lock); xsl_updating--; thread_spin_unlock (&update_lock); if (worker) worker_wakeup (worker); // wakeup after the decrease or it may delay if (client == NULL) free (x); return NULL; }
static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password) { FILE *passwdfile; char *hashed_password = NULL; htpasswd_auth_state *state = auth->state; htpasswd_user entry; void *result; htpasswd_recheckfile (state); thread_rwlock_wlock (&state->file_rwlock); entry.name = (char*)username; if (avl_get_by_key (state->users, &entry, &result) == 0) { thread_rwlock_unlock (&state->file_rwlock); return AUTH_USEREXISTS; } passwdfile = fopen(state->filename, "ab"); if (passwdfile == NULL) { thread_rwlock_unlock (&state->file_rwlock); WARN2("Failed to open authentication database \"%s\": %s", state->filename, strerror(errno)); return AUTH_FAILED; } hashed_password = get_hash(password, strlen(password)); if (hashed_password) { fprintf(passwdfile, "%s:%s\n", username, hashed_password); free(hashed_password); } fclose(passwdfile); thread_rwlock_unlock (&state->file_rwlock); return AUTH_USERADDED; }
void connection_accept_loop (void) { connection_queue_t *node; connection_t *con; ice_config_t *config; int duration = 3000; int timeout = 0; config = config_get_config (); get_ssl_certificate (config); timeout = config->header_timeout; config_release_config (); while (global.running == ICE_RUNNING) { con = _accept_connection (duration); if (!con) { duration = 30000; /* use longer timeouts when nothing waiting */ continue; } con->con_timeout = time(NULL) + timeout; /* add connection async to the connection queue, then the * connection loop will do all the dirty work */ node =_connection_node_new (con); _add_connection (node); duration = 3000; } /* 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); }
/* This does the actual connection for a relay. A thread is * started off if a connection can be acquired */ int open_relay (relay_server *relay) { source_t *src = relay->source; relay_server_master *master = relay->masters; client_t *client = src->client; do { int ret; if (master->skip) { INFO3 ("skipping %s:%d for %s", master->ip, master->port, relay->localmount); continue; } thread_rwlock_unlock (&src->lock); ret = open_relay_connection (client, relay, master); thread_rwlock_wlock (&src->lock); if (ret < 0) continue; return 1; } while ((master = master->next) && global.running == ICE_RUNNING); return -1; }
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); }
static auth_result htpasswd_deleteuser(auth_t *auth, const char *username) { FILE *passwdfile; FILE *tmp_passwdfile; htpasswd_auth_state *state; char line[MAX_LINE_LEN]; char *sep; char *tmpfile = NULL; int tmpfile_len = 0; struct stat file_info; state = auth->state; thread_rwlock_wlock (&state->file_rwlock); passwdfile = fopen(state->filename, "rb"); if(passwdfile == NULL) { WARN2("Failed to open authentication database \"%s\": %s", state->filename, strerror(errno)); thread_rwlock_unlock (&state->file_rwlock); return AUTH_FAILED; } tmpfile_len = strlen(state->filename) + 6; tmpfile = calloc(1, tmpfile_len); snprintf (tmpfile, tmpfile_len, "%s.tmp", state->filename); if (stat (tmpfile, &file_info) == 0) { WARN1 ("temp file \"%s\" exists, rejecting operation", tmpfile); free (tmpfile); fclose (passwdfile); thread_rwlock_unlock (&state->file_rwlock); return AUTH_FAILED; } tmp_passwdfile = fopen(tmpfile, "wb"); if(tmp_passwdfile == NULL) { WARN2("Failed to open temporary authentication database \"%s\": %s", tmpfile, strerror(errno)); fclose(passwdfile); free(tmpfile); thread_rwlock_unlock (&state->file_rwlock); return AUTH_FAILED; } while(get_line(passwdfile, line, MAX_LINE_LEN)) { if(!line[0] || line[0] == '#') continue; sep = strchr(line, ':'); if(sep == NULL) { DEBUG0("No separator in line"); continue; } *sep = 0; if (strcmp(username, line)) { /* We did not match on the user, so copy it to the temp file */ /* and put the : back in */ *sep = ':'; fprintf(tmp_passwdfile, "%s\n", line); } } fclose(tmp_passwdfile); fclose(passwdfile); /* Now move the contents of the tmp file to the original */ /* Windows won't let us rename a file if the destination file exists...so, lets remove the original first */ if (remove(state->filename) != 0) { ERROR3("Problem moving temp authentication file to original \"%s\" - \"%s\": %s", tmpfile, state->filename, strerror(errno)); } else { if (rename(tmpfile, state->filename) != 0) { ERROR3("Problem moving temp authentication file to original \"%s\" - \"%s\": %s", tmpfile, state->filename, strerror(errno)); } } free(tmpfile); thread_rwlock_unlock (&state->file_rwlock); htpasswd_recheckfile (state); return AUTH_USERDELETED; }
int move_listener (client_t *client, struct _fbinfo *finfo) { source_t *source; mount_proxy *minfo; int rate = finfo->limit, loop = 20, ret = -1; ice_config_t *config = config_get_config(); struct _fbinfo where; unsigned int len = 4096; char buffer [len]; memcpy (&where, finfo, sizeof (where)); if (finfo->fallback) where.fallback = strdup (finfo->fallback); avl_tree_rlock (global.source_tree); do { len = sizeof buffer; util_expand_pattern (where.fallback, where.mount, buffer, &len); where.mount = buffer; minfo = config_find_mount (config, where.mount); if (rate == 0 && minfo && minfo->limit_rate) rate = minfo->limit_rate; source = source_find_mount_raw (where.mount); if (source == NULL && minfo == NULL) break; if (source) { thread_rwlock_wlock (&source->lock); if (source_available (source)) { // an unused on-demand relay will still have an unitialised type if (source->format->type == finfo->type || source->format->type == FORMAT_TYPE_UNDEFINED) { config_release_config(); avl_tree_unlock (global.source_tree); source_setup_listener (source, client); source->listeners++; client->flags |= CLIENT_HAS_MOVED; thread_rwlock_unlock (&source->lock); free (where.fallback); return 0; } } thread_rwlock_unlock (&source->lock); } if (minfo && minfo->fallback_mount) { free (where.fallback); where.fallback = strdup (where.mount); where.mount = minfo->fallback_mount; } else break; } while (loop--); avl_tree_unlock (global.source_tree); config_release_config(); if (where.mount && ((client->flags & CLIENT_IS_SLAVE) == 0)) { if (where.limit == 0) { if (rate == 0) if (sscanf (where.mount, "%*[^[][%d]", &rate) == 1) rate = rate * 1000/8; where.limit = rate; } client->intro_offset = 0; ret = fserve_setup_client_fb (client, &where); } free (where.fallback); return ret; }
ice_config_t *config_grab_config(void) { thread_rwlock_wlock(&(_locks.config_lock)); return &_current_configuration; }
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"); }
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); }
static void *start_relay_stream (void *arg) { client_t *client = arg; relay_server *relay; source_t *src; int failed = 1, sources; global_lock(); sources = ++global.sources; stats_event_args (NULL, "sources", "%d", global.sources); global_unlock(); /* set the start time, because we want to decrease the sources on all failures */ client->connection.con_time = time (NULL); do { ice_config_t *config = config_get_config(); mount_proxy *mountinfo; relay = client->shared_data; src = relay->source; thread_rwlock_wlock (&src->lock); src->flags |= SOURCE_PAUSE_LISTENERS; if (sources > config->source_limit) { config_release_config(); WARN1 ("starting relayed mountpoint \"%s\" requires a higher sources limit", relay->localmount); break; } config_release_config(); INFO1("Starting relayed source at mountpoint \"%s\"", relay->localmount); if (open_relay (relay) < 0) break; if (connection_complete_source (src) < 0) { WARN1 ("Failed to complete initialisation on %s", relay->localmount); break; } stats_event_inc (NULL, "source_relay_connections"); source_init (src); config = config_get_config(); mountinfo = config_find_mount (config, src->mount); source_update_settings (config, src, mountinfo); INFO1 ("source %s is ready to start", src->mount); config_release_config(); failed = 0; } while (0); client->ops = &relay_client_ops; client->schedule_ms = timing_get_time(); if (failed) { /* failed to start any connection, better clean up and reset */ if (relay->on_demand == 0) { yp_remove (relay->localmount); src->yp_public = -1; } relay->in_use = NULL; INFO2 ("listener count remaining on %s is %d", src->mount, src->listeners); src->flags &= ~(SOURCE_PAUSE_LISTENERS|SOURCE_RUNNING); } thread_rwlock_unlock (&src->lock); thread_spin_lock (&relay_start_lock); relays_connecting--; thread_spin_unlock (&relay_start_lock); client->flags |= CLIENT_ACTIVE; worker_wakeup (client->worker); return NULL; }
/* Actually open the connection and do some http parsing, handle any 302 * responses within here. */ static int open_relay_connection (client_t *client, relay_server *relay, relay_server_master *master) { int redirects = 0; http_parser_t *parser = NULL; connection_t *con = &client->connection; char *server = strdup (master->ip); char *mount = strdup (master->mount); int port = master->port, timeout = master->timeout, ask_for_metadata = relay->mp3metadata; char *auth_header = NULL; if (relay->username && relay->password) { char *esc_authorisation; unsigned len = strlen(relay->username) + strlen(relay->password) + 2; DEBUG2 ("using username %s for %s", relay->username, relay->localmount); auth_header = malloc (len); snprintf (auth_header, len, "%s:%s", relay->username, relay->password); esc_authorisation = util_base64_encode(auth_header); free(auth_header); len = strlen (esc_authorisation) + 24; auth_header = malloc (len); snprintf (auth_header, len, "Authorization: Basic %s\r\n", esc_authorisation); free(esc_authorisation); } while (redirects < 10) { sock_t streamsock; char *bind = NULL; /* policy decision, we assume a source bind even after redirect, possible option */ if (master->bind) bind = strdup (master->bind); if (bind) INFO4 ("connecting to %s:%d for %s, bound to %s", server, port, relay->localmount, bind); else INFO3 ("connecting to %s:%d for %s", server, port, relay->localmount); con->con_time = time (NULL); relay->in_use = master; streamsock = sock_connect_wto_bind (server, port, bind, timeout); free (bind); if (connection_init (con, streamsock, server) < 0) { WARN2 ("Failed to connect to %s:%d", server, port); break; } parser = get_relay_response (con, mount, server, ask_for_metadata, auth_header); if (parser == NULL) { ERROR4 ("Problem trying to start relay on %s (%s:%d%s)", relay->localmount, server, port, mount); break; } if (strcmp (httpp_getvar (parser, HTTPP_VAR_ERROR_CODE), "302") == 0) { /* better retry the connection again but with different details */ const char *uri, *mountpoint; int len; uri = httpp_getvar (parser, "location"); INFO1 ("redirect received %s", uri); if (strncmp (uri, "http://", 7) != 0) break; uri += 7; mountpoint = strchr (uri, '/'); free (mount); if (mountpoint) mount = strdup (mountpoint); else mount = strdup ("/"); len = strcspn (uri, ":/"); port = 80; if (uri [len] == ':') port = atoi (uri+len+1); free (server); server = calloc (1, len+1); strncpy (server, uri, len); connection_close (con); httpp_destroy (parser); parser = NULL; } else { if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE)) { ERROR3 ("Error from relay request on %s (%s %s)", relay->localmount, master->mount, httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE)); client->parser = NULL; break; } sock_set_blocking (streamsock, 0); thread_rwlock_wlock (&relay->source->lock); client->parser = parser; // old parser will be free in the format clear thread_rwlock_unlock (&relay->source->lock); client->connection.discon_time = 0; client->connection.con_time = time (NULL); client_set_queue (client, NULL); free (server); free (mount); free (auth_header); return 0; } redirects++; } /* failed, better clean up */ free (server); free (mount); free (auth_header); if (parser) httpp_destroy (parser); connection_close (con); con->con_time = time (NULL); // sources count needs to drop in such cases if (relay->in_use) relay->in_use->skip = 1; return -1; }
void avl_node_wlock(avl_node *node) { thread_rwlock_wlock(&node->rwlock); }
void avl_tree_wlock(avl_tree *tree) { thread_rwlock_wlock(&tree->rwlock); }
void connection_accept_loop(void) { connection_t *con; if (!kitsune_is_updating()) /**DSU control */ tid = thread_create("connection thread", _handle_connection, NULL, THREAD_ATTACHED); while (global.running == ICE_RUNNING) { kitsune_update("connection_accept"); /**DSU updatepoint */ con = _accept_connection(); if (con) { client_queue_t *node; ice_config_t *config; int i; client_t *client = NULL; global_lock(); if (client_create (&client, con, NULL) < 0) { global_unlock(); client_send_404 (client, "Icecast connection limit reached"); 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; /* Check for special shoutcast compatability processing */ config = config_get_config(); for (i = 0; i < global.server_sockets; i++) { if (global.serversock[i] == con->serversock) { if (config->listeners[i].shoutcast_compat) node->shoutcast = 1; } } 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); }
static void htpasswd_recheckfile (htpasswd_auth_state *htpasswd) { FILE *passwdfile; avl_tree *new_users; int num = 0; struct stat file_stat; char *sep; char line [MAX_LINE_LEN]; if (stat (htpasswd->filename, &file_stat) < 0) { WARN1 ("failed to check status of %s", htpasswd->filename); return; } if (file_stat.st_mtime == htpasswd->mtime) { /* common case, no update to file */ return; } INFO1 ("re-reading htpasswd file \"%s\"", htpasswd->filename); passwdfile = fopen (htpasswd->filename, "rb"); if (passwdfile == NULL) { WARN2("Failed to open authentication database \"%s\": %s", htpasswd->filename, strerror(errno)); return; } htpasswd->mtime = file_stat.st_mtime; new_users = avl_tree_new (compare_users, NULL); while (get_line(passwdfile, line, MAX_LINE_LEN)) { int len; htpasswd_user *entry; num++; if(!line[0] || line[0] == '#') continue; sep = strrchr (line, ':'); if (sep == NULL) { WARN2("No separator on line %d (%s)", num, htpasswd->filename); continue; } entry = calloc (1, sizeof (htpasswd_user)); len = strlen (line) + 1; entry->name = malloc (len); *sep = 0; memcpy (entry->name, line, len); entry->pass = entry->name + (sep-line) + 1; avl_insert (new_users, entry); } fclose (passwdfile); thread_rwlock_wlock (&htpasswd->file_rwlock); if (htpasswd->users) avl_tree_free (htpasswd->users, _free_user); htpasswd->users = new_users; thread_rwlock_unlock (&htpasswd->file_rwlock); }