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); }
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 _handle_shoutcast_compatible (client_queue_t *node) { char *http_compliant; int http_compliant_len = 0; http_parser_t *parser; ice_config_t *config = config_get_config (); char *shoutcast_mount; client_t *client = node->client; if (node->shoutcast_mount) shoutcast_mount = node->shoutcast_mount; else shoutcast_mount = config->shoutcast_mount; if (node->shoutcast == 1) { char *source_password, *ptr, *headers; mount_proxy *mountinfo = config_find_mount (config, shoutcast_mount, MOUNT_TYPE_NORMAL); if (mountinfo && mountinfo->password) source_password = strdup (mountinfo->password); else { if (config->source_password) source_password = strdup (config->source_password); else source_password = NULL; } config_release_config(); /* Get rid of trailing \r\n or \n after password */ ptr = strstr (client->refbuf->data, "\r\r\n"); if (ptr) headers = ptr+3; else { ptr = strstr (client->refbuf->data, "\r\n"); if (ptr) headers = ptr+2; else { ptr = strstr (client->refbuf->data, "\n"); if (ptr) headers = ptr+1; } } if (ptr == NULL) { client_destroy (client); free (source_password); free (node->shoutcast_mount); free (node); return; } *ptr = '\0'; if (source_password && strcmp (client->refbuf->data, source_password) == 0) { client->respcode = 200; /* send this non-blocking but if there is only a partial write * then leave to header timeout */ sock_write (client->con->sock, "OK2\r\nicy-caps:11\r\n\r\n"); node->offset -= (headers - client->refbuf->data); memmove (client->refbuf->data, headers, node->offset+1); node->shoutcast = 2; /* we've checked the password, now send it back for reading headers */ _add_request_queue (node); free (source_password); return; } else INFO1 ("password does not match \"%s\"", client->refbuf->data); client_destroy (client); free (source_password); free (node->shoutcast_mount); free (node); return; } /* actually make a copy as we are dropping the config lock */ shoutcast_mount = strdup (shoutcast_mount); config_release_config(); /* Here we create a valid HTTP request based of the information that was passed in via the non-HTTP style protocol above. This means we can use some of our existing code to handle this case */ http_compliant_len = 20 + strlen (shoutcast_mount) + node->offset; http_compliant = (char *)calloc(1, http_compliant_len); snprintf (http_compliant, http_compliant_len, "SOURCE %s HTTP/1.0\r\n%s", shoutcast_mount, client->refbuf->data); parser = httpp_create_parser(); httpp_initialize(parser, NULL); if (httpp_parse (parser, http_compliant, strlen(http_compliant))) { /* 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); } client->parser = parser; source_startup (client, shoutcast_mount, SHOUTCAST_SOURCE_AUTH); } else { httpp_destroy (parser); client_destroy (client); } free (http_compliant); free (shoutcast_mount); free (node->shoutcast_mount); free (node); return; }
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); }