icecast-2.4.2/0000775000175000017500000000000012511177344010142 500000000000000icecast-2.4.2/src/0000775000175000017500000000000012511177344010731 500000000000000icecast-2.4.2/src/yp.c0000664000175000017500000006545612511160565011462 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "thread/thread.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "logging.h" #include "format.h" #include "source.h" #include "cfgfile.h" #include "stats.h" #ifdef WIN32 #define snprintf _snprintf #endif #define CATMODULE "yp" struct yp_server { char *url; char *server_id; unsigned url_timeout; unsigned touch_interval; int remove; CURL *curl; struct ypdata_tag *mounts, *pending_mounts; struct yp_server *next; char curl_error[CURL_ERROR_SIZE]; }; typedef struct ypdata_tag { int remove; int release; int cmd_ok; char *sid; char *mount; char *url; char *listen_url; char *server_name; char *server_desc; char *server_genre; char *cluster_password; char *bitrate; char *audio_info; char *server_type; char *current_song; char *subtype; struct yp_server *server; time_t next_update; unsigned touch_interval; char *error_msg; int (*process)(struct ypdata_tag *yp, char *s, unsigned len); struct ypdata_tag *next; } ypdata_t; static rwlock_t yp_lock; static mutex_t yp_pending_lock; static volatile struct yp_server *active_yps = NULL, *pending_yps = NULL; static volatile int yp_update = 0; static int yp_running; static time_t now; static thread_type *yp_thread; static volatile unsigned client_limit = 0; static volatile char *server_version = NULL; static void *yp_update_thread(void *arg); static void add_yp_info (ypdata_t *yp, void *info, int type); static int do_yp_remove (ypdata_t *yp, char *s, unsigned len); static int do_yp_add (ypdata_t *yp, char *s, unsigned len); static int do_yp_touch (ypdata_t *yp, char *s, unsigned len); static void yp_destroy_ypdata(ypdata_t *ypdata); /* curl callback used to parse headers coming back from the YP server */ static int handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream) { ypdata_t *yp = stream; unsigned bytes = size * nmemb; /* ICECAST_LOG_DEBUG("header from YP is \"%.*s\"", bytes, ptr); */ if (strncasecmp (ptr, "YPResponse: 1", 13) == 0) yp->cmd_ok = 1; if (strncasecmp (ptr, "YPMessage: ", 11) == 0) { unsigned len = bytes - 11; free (yp->error_msg); yp->error_msg = calloc (1, len); if (yp->error_msg) sscanf (ptr + 11, "%[^\r\n]", yp->error_msg); } if (yp->process == do_yp_add) { if (strncasecmp (ptr, "SID: ", 5) == 0) { unsigned len = bytes - 5; free (yp->sid); yp->sid = calloc (1, len); if (yp->sid) sscanf (ptr + 5, "%[^\r\n]", yp->sid); } } if (strncasecmp (ptr, "TouchFreq: ", 11) == 0) { unsigned secs; if ( sscanf (ptr + 11, "%u", &secs) != 1 ) secs = 0; if (secs < 30) secs = 30; ICECAST_LOG_DEBUG("server touch interval is %u", secs); yp->touch_interval = secs; } return (int)bytes; } /* capture returned data, but don't do anything with it, shouldn't be any */ static int handle_returned_data (void *ptr, size_t size, size_t nmemb, void *stream) { return (int)(size*nmemb); } /* search the active and pending YP server lists */ static struct yp_server *find_yp_server (const char *url) { struct yp_server *server; server = (struct yp_server *)active_yps; while (server) { if (strcmp (server->url, url) == 0) return server; server = server->next; } server = (struct yp_server *)pending_yps; while (server) { if (strcmp (server->url, url) == 0) break; server = server->next; } return server; } static void destroy_yp_server (struct yp_server *server) { if (server == NULL) return; ICECAST_LOG_DEBUG("Removing YP server entry for %s", server->url); if (server->curl) curl_easy_cleanup (server->curl); if (server->mounts) ICECAST_LOG_WARN("active ypdata not freed up"); if (server->pending_mounts) ICECAST_LOG_WARN("pending ypdata not freed up"); free (server->url); free (server->server_id); free (server); } /* search for a ypdata entry corresponding to a specific mountpoint */ static ypdata_t *find_yp_mount (ypdata_t *mounts, const char *mount) { ypdata_t *yp = mounts; while (yp) { if (strcmp (yp->mount, mount) == 0) break; yp = yp->next; } return yp; } void yp_recheck_config (ice_config_t *config) { int i; struct yp_server *server; ICECAST_LOG_DEBUG("Updating YP configuration"); thread_rwlock_rlock (&yp_lock); server = (struct yp_server *)active_yps; while (server) { server->remove = 1; server = server->next; } client_limit = config->client_limit; free ((char*)server_version); server_version = strdup (config->server_id); /* for each yp url in config, check to see if one exists if not, then add it. */ for (i=0 ; i < config->num_yp_directories; i++) { server = find_yp_server (config->yp_url[i]); if (server == NULL) { server = calloc (1, sizeof (struct yp_server)); if (server == NULL) { destroy_yp_server (server); break; } server->server_id = strdup ((char *)server_version); server->url = strdup (config->yp_url[i]); server->url_timeout = config->yp_url_timeout[i]; server->touch_interval = config->yp_touch_interval[i]; server->curl = curl_easy_init(); if (server->curl == NULL) { destroy_yp_server (server); break; } if (server->url_timeout > 10 || server->url_timeout < 1) server->url_timeout = 6; if (server->touch_interval < 30) server->touch_interval = 30; curl_easy_setopt (server->curl, CURLOPT_USERAGENT, server->server_id); curl_easy_setopt (server->curl, CURLOPT_URL, server->url); curl_easy_setopt (server->curl, CURLOPT_HEADERFUNCTION, handle_returned_header); curl_easy_setopt (server->curl, CURLOPT_WRITEFUNCTION, handle_returned_data); curl_easy_setopt (server->curl, CURLOPT_WRITEDATA, server->curl); curl_easy_setopt (server->curl, CURLOPT_TIMEOUT, server->url_timeout); curl_easy_setopt (server->curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (server->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt (server->curl, CURLOPT_MAXREDIRS, 3L); curl_easy_setopt (server->curl, CURLOPT_ERRORBUFFER, &(server->curl_error[0])); server->next = (struct yp_server *)pending_yps; pending_yps = server; ICECAST_LOG_INFO("Adding new YP server \"%s\" (timeout %ds, default interval %ds)", server->url, server->url_timeout, server->touch_interval); } else { server->remove = 0; } } thread_rwlock_unlock (&yp_lock); yp_update = 1; } void yp_initialize(void) { ice_config_t *config = config_get_config(); thread_rwlock_create (&yp_lock); thread_mutex_create (&yp_pending_lock); yp_recheck_config (config); config_release_config (); yp_thread = thread_create("YP Touch Thread", yp_update_thread, (void *)NULL, THREAD_ATTACHED); } /* handler for curl, checks if successful handling occurred * return 0 for ok, -1 for this entry failed, -2 for server fail. * On failure case, update and process are modified */ static int send_to_yp (const char *cmd, ypdata_t *yp, char *post) { int curlcode; struct yp_server *server = yp->server; /* ICECAST_LOG_DEBUG("send YP (%s):%s", cmd, post); */ yp->cmd_ok = 0; curl_easy_setopt (server->curl, CURLOPT_POSTFIELDS, post); curl_easy_setopt (server->curl, CURLOPT_WRITEHEADER, yp); curlcode = curl_easy_perform (server->curl); if (curlcode) { yp->process = do_yp_add; yp->next_update = now + 1200; ICECAST_LOG_ERROR("connection to %s failed with \"%s\"", server->url, server->curl_error); return -2; } if (yp->cmd_ok == 0) { if (yp->error_msg == NULL) yp->error_msg = strdup ("no response from server"); if (yp->process == do_yp_add) { ICECAST_LOG_ERROR("YP %s on %s failed: %s", cmd, server->url, yp->error_msg); yp->next_update = now + 7200; } if (yp->process == do_yp_touch) { /* At this point the touch request failed, either because they rejected our session * or the server isn't accessible. This means we have to wait before doing another * add request. We have a minimum delay but we could allow the directory server to * give us a wait time using the TouchFreq header. This time could be given in such * cases as a firewall block or incorrect listenurl. */ if (yp->touch_interval < 1200) yp->next_update = now + 1200; else yp->next_update = now + yp->touch_interval; ICECAST_LOG_INFO("YP %s on %s failed: %s", cmd, server->url, yp->error_msg); } yp->process = do_yp_add; free (yp->sid); yp->sid = NULL; return -1; } ICECAST_LOG_DEBUG("YP %s at %s succeeded", cmd, server->url); return 0; } /* routines for building and issues requests to the YP server */ static int do_yp_remove (ypdata_t *yp, char *s, unsigned len) { int ret = 0; if (yp->sid) { ret = snprintf (s, len, "action=remove&sid=%s", yp->sid); if (ret >= (signed)len) return ret+1; ICECAST_LOG_INFO("clearing up YP entry for %s", yp->mount); ret = send_to_yp ("remove", yp, s); free (yp->sid); yp->sid = NULL; } yp->remove = 1; yp->process = do_yp_add; yp_update = 1; return ret; } static int do_yp_add (ypdata_t *yp, char *s, unsigned len) { int ret; char *value; value = stats_get_value (yp->mount, "server_type"); add_yp_info (yp, value, YP_SERVER_TYPE); free (value); value = stats_get_value (yp->mount, "server_name"); add_yp_info (yp, value, YP_SERVER_NAME); free (value); value = stats_get_value (yp->mount, "server_url"); add_yp_info (yp, value, YP_SERVER_URL); free (value); value = stats_get_value (yp->mount, "genre"); add_yp_info (yp, value, YP_SERVER_GENRE); free (value); value = stats_get_value (yp->mount, "bitrate"); if (value == NULL) value = stats_get_value (yp->mount, "ice-bitrate"); add_yp_info (yp, value, YP_BITRATE); free (value); value = stats_get_value (yp->mount, "server_description"); add_yp_info (yp, value, YP_SERVER_DESC); free (value); value = stats_get_value (yp->mount, "subtype"); add_yp_info (yp, value, YP_SUBTYPE); free (value); value = stats_get_value (yp->mount, "audio_info"); add_yp_info (yp, value, YP_AUDIO_INFO); free (value); ret = snprintf (s, len, "action=add&sn=%s&genre=%s&cpswd=%s&desc=" "%s&url=%s&listenurl=%s&type=%s&stype=%s&b=%s&%s\r\n", yp->server_name, yp->server_genre, yp->cluster_password, yp->server_desc, yp->url, yp->listen_url, yp->server_type, yp->subtype, yp->bitrate, yp->audio_info); if (ret >= (signed)len) return ret+1; ret = send_to_yp ("add", yp, s); if (ret == 0) { yp->process = do_yp_touch; /* force first touch in 5 secs */ yp->next_update = time(NULL) + 5; } return ret; } static int do_yp_touch (ypdata_t *yp, char *s, unsigned len) { unsigned listeners = 0, max_listeners = 1; char *val, *artist, *title; int ret; artist = (char *)stats_get_value (yp->mount, "artist"); title = (char *)stats_get_value (yp->mount, "title"); if (artist || title) { char *song; char *separator = " - "; if (artist == NULL) { artist = strdup(""); separator = ""; } if (title == NULL) title = strdup(""); song = malloc (strlen (artist) + strlen (title) + strlen (separator) +1); if (song) { sprintf (song, "%s%s%s", artist, separator, title); add_yp_info(yp, song, YP_CURRENT_SONG); stats_event (yp->mount, "yp_currently_playing", song); free (song); } } free (artist); free (title); val = (char *)stats_get_value (yp->mount, "listeners"); if (val) { listeners = atoi (val); free (val); } val = stats_get_value (yp->mount, "max_listeners"); if (val == NULL || strcmp (val, "unlimited") == 0 || atoi(val) < 0) max_listeners = client_limit; else max_listeners = atoi (val); free (val); val = stats_get_value (yp->mount, "subtype"); if (val) { add_yp_info (yp, val, YP_SUBTYPE); free (val); } ret = snprintf (s, len, "action=touch&sid=%s&st=%s" "&listeners=%u&max_listeners=%u&stype=%s\r\n", yp->sid, yp->current_song, listeners, max_listeners, yp->subtype); if (ret >= (signed)len) return ret+1; /* space required for above text and nul*/ if (send_to_yp ("touch", yp, s) == 0) { yp->next_update = now + yp->touch_interval; return 0; } return -1; } static int process_ypdata (struct yp_server *server, ypdata_t *yp) { unsigned len = 1024; char *s = NULL, *tmp; if (now < yp->next_update) return 0; /* loop just in case the memory area isn't big enough */ while (1) { int ret; if ((tmp = realloc (s, len)) == NULL) return 0; s = tmp; if (yp->release) { yp->process = do_yp_remove; yp->next_update = 0; } ret = yp->process (yp, s, len); if (ret <= 0) { free (s); return ret; } len = ret; } return 0; } static void yp_process_server (struct yp_server *server) { ypdata_t *yp; int state = 0; /* ICECAST_LOG_DEBUG("processing yp server %s", server->url); */ yp = server->mounts; while (yp) { now = time (NULL); /* if one of the streams shows that the server cannot be contacted then mark the * other entries for an update later. Assume YP server is dead and skip it for now */ if (state == -2) { ICECAST_LOG_DEBUG("skiping %s on %s", yp->mount, server->url); yp->process = do_yp_add; yp->next_update += 900; } else state = process_ypdata (server, yp); yp = yp->next; } } static ypdata_t *create_yp_entry (const char *mount) { ypdata_t *yp; char *s; yp = calloc (1, sizeof (ypdata_t)); do { unsigned len = 512; int ret; char *url; mount_proxy *mountproxy = NULL; ice_config_t *config; if (yp == NULL) break; yp->mount = strdup (mount); yp->server_name = strdup (""); yp->server_desc = strdup (""); yp->server_genre = strdup (""); yp->bitrate = strdup (""); yp->server_type = strdup (""); yp->cluster_password = strdup (""); yp->url = strdup (""); yp->current_song = strdup (""); yp->audio_info = strdup (""); yp->subtype = strdup (""); yp->process = do_yp_add; url = malloc (len); if (url == NULL) break; config = config_get_config(); ret = snprintf (url, len, "http://%s:%d%s", config->hostname, config->port, mount); if (ret >= (signed)len) { s = realloc (url, ++ret); if (s) url = s; snprintf (url, ret, "http://%s:%d%s", config->hostname, config->port, mount); } mountproxy = config_find_mount (config, mount, MOUNT_TYPE_NORMAL); if (mountproxy && mountproxy->cluster_password) add_yp_info (yp, mountproxy->cluster_password, YP_CLUSTER_PASSWORD); config_release_config(); yp->listen_url = util_url_escape (url); free (url); if (yp->listen_url == NULL) break; return yp; } while (0); yp_destroy_ypdata (yp); return NULL; } /* Check for changes in the YP servers configured */ static void check_servers (void) { struct yp_server *server = (struct yp_server *)active_yps, **server_p = (struct yp_server **)&active_yps; while (server) { if (server->remove) { struct yp_server *to_go = server; ICECAST_LOG_DEBUG("YP server \"%s\"removed", server->url); *server_p = server->next; server = server->next; destroy_yp_server (to_go); continue; } server_p = &server->next; server = server->next; } /* add new server entries */ while (pending_yps) { avl_node *node; server = (struct yp_server *)pending_yps; pending_yps = server->next; ICECAST_LOG_DEBUG("Add pending yps %s", server->url); server->next = (struct yp_server *)active_yps; active_yps = server; /* new YP server configured, need to populate with existing sources */ avl_tree_rlock (global.source_tree); node = avl_get_first (global.source_tree); while (node) { ypdata_t *yp; source_t *source = node->key; if (source->yp_public && (yp = create_yp_entry (source->mount)) != NULL) { ICECAST_LOG_DEBUG("Adding existing mount %s", source->mount); yp->server = server; yp->touch_interval = server->touch_interval; yp->next = server->mounts; server->mounts = yp; } node = avl_get_next (node); } avl_tree_unlock (global.source_tree); } } static void add_pending_yp (struct yp_server *server) { ypdata_t *current, *yp; unsigned count = 0; if (server->pending_mounts == NULL) return; current = server->mounts; server->mounts = server->pending_mounts; server->pending_mounts = NULL; yp = server->mounts; while (1) { count++; if (yp->next == NULL) break; yp = yp->next; } yp->next = current; ICECAST_LOG_DEBUG("%u YP entries added to %s", count, server->url); } static void delete_marked_yp (struct yp_server *server) { ypdata_t *yp = server->mounts, **prev = &server->mounts; while (yp) { if (yp->remove) { ypdata_t *to_go = yp; ICECAST_LOG_DEBUG("removed %s from YP server %s", yp->mount, server->url); *prev = yp->next; yp = yp->next; yp_destroy_ypdata (to_go); continue; } prev = &yp->next; yp = yp->next; } } static void *yp_update_thread(void *arg) { ICECAST_LOG_INFO("YP update thread started"); yp_running = 1; while (yp_running) { struct yp_server *server; thread_sleep (200000); /* do the YP communication */ thread_rwlock_rlock (&yp_lock); server = (struct yp_server *)active_yps; while (server) { /* ICECAST_LOG_DEBUG("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) { /* ICECAST_LOG_DEBUG("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 yp_destroy_ypdata(ypdata_t *ypdata) { if (ypdata) { if (ypdata->mount) { free (ypdata->mount); } if (ypdata->url) { free (ypdata->url); } if (ypdata->sid) { free(ypdata->sid); } if (ypdata->server_name) { free(ypdata->server_name); } if (ypdata->server_desc) { free(ypdata->server_desc); } if (ypdata->server_genre) { free(ypdata->server_genre); } if (ypdata->cluster_password) { free(ypdata->cluster_password); } if (ypdata->listen_url) { free(ypdata->listen_url); } if (ypdata->current_song) { free(ypdata->current_song); } if (ypdata->bitrate) { free(ypdata->bitrate); } if (ypdata->server_type) { free(ypdata->server_type); } if (ypdata->audio_info) { free(ypdata->audio_info); } free (ypdata->subtype); free (ypdata->error_msg); free (ypdata); } } static void add_yp_info (ypdata_t *yp, void *info, int type) { char *escaped; if (!info) return; escaped = util_url_escape(info); if (escaped == NULL) return; switch (type) { case YP_SERVER_NAME: free (yp->server_name); yp->server_name = escaped; break; case YP_SERVER_DESC: free (yp->server_desc); yp->server_desc = escaped; break; case YP_SERVER_GENRE: free (yp->server_genre); yp->server_genre = escaped; break; case YP_SERVER_URL: free (yp->url); yp->url = escaped; break; case YP_BITRATE: free (yp->bitrate); yp->bitrate = escaped; break; case YP_AUDIO_INFO: free (yp->audio_info); yp->audio_info = escaped; break; case YP_SERVER_TYPE: free (yp->server_type); yp->server_type = escaped; break; case YP_CURRENT_SONG: free (yp->current_song); yp->current_song = escaped; break; case YP_CLUSTER_PASSWORD: free (yp->cluster_password); yp->cluster_password = escaped; break; case YP_SUBTYPE: free (yp->subtype); yp->subtype = escaped; break; default: free (escaped); } } /* Add YP entries to active servers */ void yp_add (const char *mount) { struct yp_server *server; /* make sure YP thread is not modifying the lists */ thread_rwlock_rlock (&yp_lock); /* make sure we don't race against another yp_add */ thread_mutex_lock (&yp_pending_lock); server = (struct yp_server *)active_yps; while (server) { ypdata_t *yp; /* on-demand relays may already have a YP entry */ yp = find_yp_mount (server->mounts, mount); if (yp == NULL) { /* add new ypdata to each servers pending yp */ yp = create_yp_entry (mount); if (yp) { ICECAST_LOG_DEBUG("Adding %s to %s", mount, server->url); yp->server = server; yp->touch_interval = server->touch_interval; yp->next = server->pending_mounts; yp->next_update = time(NULL) + 60; server->pending_mounts = yp; yp_update = 1; } } else ICECAST_LOG_DEBUG("YP entry %s already exists", mount); server = server->next; } thread_mutex_unlock (&yp_pending_lock); thread_rwlock_unlock (&yp_lock); } /* Mark an existing entry in the YP list as to be marked for deletion */ void yp_remove (const char *mount) { struct yp_server *server = (struct yp_server *)active_yps; thread_rwlock_rlock (&yp_lock); while (server) { ypdata_t *list = server->mounts; while (1) { ypdata_t *yp = find_yp_mount (list, mount); if (yp == NULL) break; if (yp->release || yp->remove) { list = yp->next; continue; /* search again these are old entries */ } ICECAST_LOG_DEBUG("release %s on YP %s", mount, server->url); yp->release = 1; yp->next_update = 0; } server = server->next; } thread_rwlock_unlock (&yp_lock); } /* This is similar to yp_remove, but we force a touch * attempt */ void yp_touch (const char *mount) { struct yp_server *server = (struct yp_server *)active_yps; ypdata_t *search_list = NULL; thread_rwlock_rlock (&yp_lock); if (server) search_list = server->mounts; while (server) { ypdata_t *yp = find_yp_mount (search_list, mount); if (yp) { /* we may of found old entries not purged yet, so skip them */ if (yp->release != 0 || yp->remove != 0) { search_list = yp->next; continue; } /* don't update the directory if there is a touch scheduled soon */ if (yp->process == do_yp_touch && now + yp->touch_interval - yp->next_update > 60) yp->next_update = now + 3; } server = server->next; if (server) search_list = server->mounts; } thread_rwlock_unlock (&yp_lock); } void yp_shutdown (void) { yp_running = 0; yp_update = 1; if (yp_thread) thread_join (yp_thread); curl_global_cleanup(); free ((char*)server_version); server_version = NULL; ICECAST_LOG_INFO("YP thread down"); } icecast-2.4.2/src/format_midi.h0000664000175000017500000000114512511160565013312 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_MIDI_H #define __FORMAT_MIDI_H #include "format_ogg.h" ogg_codec_t *initial_midi_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_MIDI_H */ icecast-2.4.2/src/main.c0000664000175000017500000003376612511160565011755 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes , * and others (see AUTHORS for details). * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , * Copyright 2014, Thomas B. Ruecker . */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifdef WIN32 #define _WIN32_WINNT 0x0400 /* For getpid() */ #include #include #define snprintf _snprintf #define getpid _getpid #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_CURL #include #endif #include "thread/thread.h" #include "avl/avl.h" #include "net/sock.h" #include "net/resolver.h" #include "httpp/httpp.h" #if HAVE_SYS_TYPES_H #include #endif #if HAVE_GRP_H #include #endif #if HAVE_PWD_H #include #endif #include "cfgfile.h" #include "sighandler.h" #include "global.h" #include "compat.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "slave.h" #include "stats.h" #include "logging.h" #include "xslt.h" #include "fserve.h" #include "yp.h" #include "auth.h" #include #undef CATMODULE #define CATMODULE "main" static int background; static char *pidfile = NULL; static void _fatal_error(const char *perr) { #ifdef WIN32_SERVICE MessageBox(NULL, perr, "Error", MB_SERVICE_NOTIFICATION); #elif defined(WIN32) MessageBox(NULL, perr, "Error", MB_OK); #else fprintf(stdout, "%s\n", perr); #endif } static void _print_usage(void) { printf("%s\n\n", ICECAST_VERSION_STRING); printf("usage: icecast [-b] -c \n"); printf("or : icecast {-v|--version}\n"); printf("options:\n"); printf("\t-c Specify configuration file\n"); printf("\t-v or --version Display version info\n"); printf("\t-b Run icecast in the background\n"); printf("\n"); } static void _stop_logging(void) { log_close(errorlog); log_close(accesslog); log_close(playlistlog); } void initialize_subsystems(void) { log_initialize(); thread_initialize(); sock_initialize(); resolver_initialize(); config_initialize(); connection_initialize(); global_initialize(); refbuf_initialize(); xslt_initialize(); #ifdef HAVE_CURL_GLOBAL_INIT curl_global_init (CURL_GLOBAL_ALL); #endif } void shutdown_subsystems(void) { fserve_shutdown(); refbuf_shutdown(); slave_shutdown(); auth_shutdown(); yp_shutdown(); stats_shutdown(); global_shutdown(); connection_shutdown(); config_shutdown(); resolver_shutdown(); sock_shutdown(); thread_shutdown(); #ifdef HAVE_CURL curl_global_cleanup(); #endif /* Now that these are done, we can stop the loggers. */ _stop_logging(); log_shutdown(); xslt_shutdown(); } static int _parse_config_opts(int argc, char **argv, char *filename, int size) { int i = 1; int config_ok = 0; background = 0; if (argc < 2) return -1; while (i < argc) { if (strcmp(argv[i], "-b") == 0) { #ifndef WIN32 pid_t pid; fprintf(stdout, "Starting icecast2\nDetaching from the console\n"); pid = fork(); if (pid > 0) { /* exit the parent */ exit(0); } else if(pid < 0) { fprintf(stderr, "FATAL: Unable to fork child!"); exit(1); } background = 1; #endif } if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { fprintf(stdout, "%s\n", ICECAST_VERSION_STRING); exit(0); } if (strcmp(argv[i], "-c") == 0) { if (i + 1 < argc) { strncpy(filename, argv[i + 1], size-1); filename[size-1] = 0; config_ok = 1; } else { return -1; } } i++; } if(config_ok) return 1; else return -1; } static int _start_logging_stdout(void) { errorlog = log_open_file(stderr); if ( errorlog < 0 ) return 0; log_set_level(errorlog, 2 /* WARN */); return 1; } static int _start_logging(void) { char fn_error[FILENAME_MAX]; char fn_access[FILENAME_MAX]; char fn_playlist[FILENAME_MAX]; char buf[1024]; int log_to_stderr; ice_config_t *config = config_get_config_unlocked(); if(strcmp(config->error_log, "-")) { snprintf(fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log); errorlog = log_open(fn_error); log_to_stderr = 0; if (config->logsize) log_set_trigger (errorlog, config->logsize); log_set_archive_timestamp(errorlog, config->logarchive); } else { /* this is already in place because of _start_logging_stdout() */ } if (errorlog < 0) { buf[sizeof(buf)-1] = 0; snprintf(buf, sizeof(buf)-1, "FATAL: could not open error logging (%s): %s", log_to_stderr?"standard error":fn_error, strerror(errno)); _fatal_error(buf); } log_set_level(errorlog, config->loglevel); if(strcmp(config->access_log, "-")) { snprintf(fn_access, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->access_log); accesslog = log_open(fn_access); log_to_stderr = 0; if (config->logsize) log_set_trigger (accesslog, config->logsize); log_set_archive_timestamp(accesslog, config->logarchive); } else { accesslog = log_open_file(stderr); log_to_stderr = 1; } if (accesslog < 0) { buf[sizeof(buf)-1] = 0; snprintf(buf, sizeof(buf)-1, "FATAL: could not open access logging (%s): %s", log_to_stderr?"standard error":fn_access, strerror(errno)); _fatal_error(buf); } if(config->playlist_log) { snprintf(fn_playlist, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log); playlistlog = log_open(fn_playlist); if (playlistlog < 0) { buf[sizeof(buf)-1] = 0; snprintf(buf, sizeof(buf)-1, "FATAL: could not open playlist logging (%s): %s", log_to_stderr?"standard error":fn_playlist, strerror(errno)); _fatal_error(buf); } log_to_stderr = 0; if (config->logsize) log_set_trigger (playlistlog, config->logsize); log_set_archive_timestamp(playlistlog, config->logarchive); } else { playlistlog = -1; } log_set_level(errorlog, config->loglevel); log_set_level(accesslog, 4); log_set_level(playlistlog, 4); if (errorlog >= 0 && accesslog >= 0) return 1; return 0; } static int _start_listening(void) { int i; for(i=0; i < global.server_sockets; i++) { if (sock_listen(global.serversock[i], ICECAST_LISTEN_QUEUE) == SOCK_ERROR) return 0; sock_set_blocking(global.serversock[i], 0); } return 1; } /* bind the socket and start listening */ static int _server_proc_init(void) { ice_config_t *config = config_get_config_unlocked(); if (connection_setup_sockets (config) < 1) return 0; if (!_start_listening()) { _fatal_error("Failed trying to listen on server socket"); return 0; } /* recreate the pid file */ if (config->pidfile) { FILE *f; pidfile = strdup (config->pidfile); if (pidfile && (f = fopen (config->pidfile, "w")) != NULL) { fprintf (f, "%d\n", (int)getpid()); fclose (f); } } return 1; } /* this is the heart of the beast */ static void _server_proc(void) { if (background) { fclose (stdin); fclose (stdout); fclose (stderr); } connection_accept_loop(); connection_setup_sockets (NULL); } /* chroot the process. Watch out - we need to do this before starting other * threads. Change uid as well, after figuring out uid _first_ */ #if defined(HAVE_SETUID) || defined(HAVE_CHROOT) || defined(HAVE_SETUID) static void _ch_root_uid_setup(void) { ice_config_t *conf = config_get_config_unlocked(); #ifdef HAVE_SETUID struct passwd *user; struct group *group; uid_t uid=-1; gid_t gid=-1; if(conf->chuid) { if(conf->user) { user = getpwnam(conf->user); if(user) uid = user->pw_uid; else fprintf(stderr, "Couldn't find user \"%s\" in password file\n", conf->user); } if(conf->group) { group = getgrnam(conf->group); if(group) gid = group->gr_gid; else fprintf(stderr, "Couldn't find group \"%s\" in groups file\n", conf->group); } } #endif #if HAVE_CHROOT if (conf->chroot) { if(getuid()) /* root check */ { fprintf(stderr, "WARNING: Cannot change server root unless running as root.\n"); return; } if(chroot(conf->base_dir)) { fprintf(stderr,"WARNING: Couldn't change server root: %s\n", strerror(errno)); return; } else fprintf(stdout, "Changed root successfully to \"%s\".\n", conf->base_dir); } #endif #if HAVE_SETUID if(conf->chuid) { if(getuid()) /* root check */ { fprintf(stderr, "WARNING: Can't change user id unless you are root.\n"); return; } if(uid != (uid_t)-1 && gid != (gid_t)-1) { if(!setgid(gid)) fprintf(stdout, "Changed groupid to %i.\n", (int)gid); else fprintf(stdout, "Error changing groupid: %s.\n", strerror(errno)); if(!initgroups(conf->user, gid)) fprintf(stdout, "Changed supplementary groups based on user: %s.\n", conf->user); else fprintf(stdout, "Error changing supplementary groups: %s.\n", strerror(errno)); if(!setuid(uid)) fprintf(stdout, "Changed userid to %i.\n", (int)uid); else fprintf(stdout, "Error changing userid: %s.\n", strerror(errno)); } } #endif } #endif #ifdef WIN32_SERVICE int mainService(int argc, char **argv) #else int main(int argc, char **argv) #endif { int res, ret; char filename[512]; char pbuf[1024]; /* parse the '-c icecast.xml' option ** only, so that we can read a configfile */ res = _parse_config_opts(argc, argv, filename, 512); if (res == 1) { #if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__) /* startup all the modules */ initialize_subsystems(); if (!_start_logging_stdout()) { _fatal_error("FATAL: Could not start logging on stderr."); shutdown_subsystems(); return 1; } #endif /* parse the config file */ config_get_config(); ret = config_initial_parse_file(filename); config_release_config(); if (ret < 0) { memset(pbuf, '\000', sizeof(pbuf)); snprintf(pbuf, sizeof(pbuf)-1, "FATAL: error parsing config file (%s)", filename); _fatal_error(pbuf); switch (ret) { case CONFIG_EINSANE: _fatal_error("filename was null or blank"); break; case CONFIG_ENOROOT: _fatal_error("no root element found"); break; case CONFIG_EBADROOT: _fatal_error("root element is not "); break; default: _fatal_error("XML config parsing error"); break; } #if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__) shutdown_subsystems(); #endif return 1; } } else if (res == -1) { _print_usage(); return 1; } /* override config file options with commandline options */ config_parse_cmdline(argc, argv); /* Bind socket, before we change userid */ if(!_server_proc_init()) { _fatal_error("Server startup failed. Exiting"); shutdown_subsystems(); return 1; } #if defined(HAVE_SETUID) || defined(HAVE_CHROOT) || defined(HAVE_SETUID) _ch_root_uid_setup(); /* Change user id and root if requested/possible */ #endif stats_initialize(); /* We have to do this later on because of threading */ fserve_initialize(); /* This too */ #ifdef HAVE_SETUID /* We'll only have getuid() if we also have setuid(), it's reasonable to * assume */ if(!getuid()) /* Running as root! Don't allow this */ { fprintf(stderr, "ERROR: You should not run icecast2 as root\n"); fprintf(stderr, "Use the changeowner directive in the config file\n"); shutdown_subsystems(); return 1; } #endif /* setup default signal handlers */ sighandler_initialize(); if (!_start_logging()) { _fatal_error("FATAL: Could not start logging"); shutdown_subsystems(); return 1; } ICECAST_LOG_INFO("%s server started", ICECAST_VERSION_STRING); /* REM 3D Graphics */ /* let her rip */ global.running = ICECAST_RUNNING; /* Startup yp thread */ yp_initialize(); /* Do this after logging init */ slave_initialize(); auth_initialise (); _server_proc(); ICECAST_LOG_INFO("Shutting down"); #if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__) shutdown_subsystems(); #endif if (pidfile) { remove (pidfile); free (pidfile); } return 0; } icecast-2.4.2/src/format_vorbis.h0000664000175000017500000000115512510726173013677 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_VORBIS_H #define __FORMAT_VORBIS_H #include "format_ogg.h" ogg_codec_t *initial_vorbis_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_VORBIS_H */ icecast-2.4.2/src/avl/0000775000175000017500000000000012511177344011513 500000000000000icecast-2.4.2/src/avl/avl.h0000664000175000017500000001247612511160565012375 00000000000000/* * Copyright (C) 1995 by Sam Rushing */ /* $Id: avl.h,v 1.7 2003/07/07 01:10:14 brendan Exp $ */ #ifndef __AVL_H #define __AVL_H #ifdef __cplusplus extern "C" { #endif #define AVL_KEY_PRINTER_BUFLEN (256) #ifndef NO_THREAD #include "thread/thread.h" #else #define thread_rwlock_create(x) do{}while(0) #define thread_rwlock_destroy(x) do{}while(0) #define thread_rwlock_rlock(x) do{}while(0) #define thread_rwlock_wlock(x) do{}while(0) #define thread_rwlock_unlock(x) do{}while(0) #endif typedef struct avl_node_tag { void * key; struct avl_node_tag * left; struct avl_node_tag * right; struct avl_node_tag * parent; /* * The lower 2 bits of specify the balance * factor: 00==-1, 01==0, 10==+1. * The rest of the bits are used for */ unsigned int rank_and_balance; #if !defined(NO_THREAD) && defined(HAVE_AVL_NODE_LOCK) rwlock_t rwlock; #endif } avl_node; #define AVL_GET_BALANCE(n) ((int)(((n)->rank_and_balance & 3) - 1)) #define AVL_GET_RANK(n) (((n)->rank_and_balance >> 2)) #define AVL_SET_BALANCE(n,b) \ ((n)->rank_and_balance) = \ (((n)->rank_and_balance & (~3)) | ((int)((b) + 1))) #define AVL_SET_RANK(n,r) \ ((n)->rank_and_balance) = \ (((n)->rank_and_balance & 3) | (r << 2)) struct _avl_tree; typedef int (*avl_key_compare_fun_type) (void * compare_arg, void * a, void * b); typedef int (*avl_iter_fun_type) (void * key, void * iter_arg); typedef int (*avl_iter_index_fun_type) (unsigned long index, void * key, void * iter_arg); typedef int (*avl_free_key_fun_type) (void * key); typedef int (*avl_key_printer_fun_type) (char *, void *); /* * and let us associate a particular compare * function with each tree, separately. */ #ifdef _mangle # define avl_tree_new _mangle(avl_tree_new) # define avl_node_new _mangle(avl_node_new) # define avl_tree_free _mangle(avl_tree_free) # define avl_insert _mangle(avl_insert) # define avl_delete _mangle(avl_delete) # define avl_get_by_index _mangle(avl_get_by_index) # define avl_get_by_key _mangle(avl_get_by_key) # define avl_iterate_inorder _mangle(avl_iterate_inorder) # define avl_iterate_index_range _mangle(avl_iterate_index_range) # define avl_tree_rlock _mangle(avl_tree_rlock) # define avl_tree_wlock _mangle(avl_tree_wlock) # define avl_tree_wlock _mangle(avl_tree_wlock) # define avl_tree_unlock _mangle(avl_tree_unlock) # define avl_node_rlock _mangle(avl_node_rlock) # define avl_node_wlock _mangle(avl_node_wlock) # define avl_node_unlock _mangle(avl_node_unlock) # define avl_get_span_by_key _mangle(avl_get_span_by_key) # define avl_get_span_by_two_keys _mangle(avl_get_span_by_two_keys) # define avl_verify _mangle(avl_verify) # define avl_print_tree _mangle(avl_print_tree) # define avl_get_first _mangle(avl_get_first) # define avl_get_prev _mangle(avl_get_prev) # define avl_get_next _mangle(avl_get_next) # define avl_get_item_by_key_most _mangle(avl_get_item_by_key_most) # define avl_get_item_by_key_least _mangle(avl_get_item_by_key_least) #endif typedef struct _avl_tree { avl_node * root; unsigned int height; unsigned int length; avl_key_compare_fun_type compare_fun; void * compare_arg; #ifndef NO_THREAD rwlock_t rwlock; #endif } avl_tree; avl_tree * avl_tree_new (avl_key_compare_fun_type compare_fun, void * compare_arg); avl_node * avl_node_new (void * key, avl_node * parent); void avl_tree_free ( avl_tree * tree, avl_free_key_fun_type free_key_fun ); int avl_insert ( avl_tree * ob, void * key ); int avl_delete ( avl_tree * tree, void * key, avl_free_key_fun_type free_key_fun ); int avl_get_by_index ( avl_tree * tree, unsigned long index, void ** value_address ); int avl_get_by_key ( avl_tree * tree, void * key, void ** value_address ); int avl_iterate_inorder ( avl_tree * tree, avl_iter_fun_type iter_fun, void * iter_arg ); int avl_iterate_index_range ( avl_tree * tree, avl_iter_index_fun_type iter_fun, unsigned long low, unsigned long high, void * iter_arg ); int avl_get_span_by_key ( avl_tree * tree, void * key, unsigned long * low, unsigned long * high ); int avl_get_span_by_two_keys ( avl_tree * tree, void * key_a, void * key_b, unsigned long * low, unsigned long * high ); int avl_verify (avl_tree * tree); void avl_print_tree ( avl_tree * tree, avl_key_printer_fun_type key_printer ); avl_node *avl_get_first(avl_tree *tree); avl_node *avl_get_prev(avl_node * node); avl_node *avl_get_next(avl_node * node); /* These two are from David Ascher */ int avl_get_item_by_key_most ( avl_tree * tree, void * key, void ** value_address ); int avl_get_item_by_key_least ( avl_tree * tree, void * key, void ** value_address ); /* optional locking stuff */ void avl_tree_rlock(avl_tree *tree); void avl_tree_wlock(avl_tree *tree); void avl_tree_unlock(avl_tree *tree); void avl_node_rlock(avl_node *node); void avl_node_wlock(avl_node *node); void avl_node_unlock(avl_node *node); #ifdef __cplusplus } #endif #endif /* __AVL_H */ icecast-2.4.2/src/avl/README0000664000175000017500000000017012511160565012306 00000000000000this is the avl tree library. lgpl by sam rushing modified by jack moffitt icecast-2.4.2/src/avl/test.c0000664000175000017500000000272312511160565012557 00000000000000#include #include "avl.h" #ifdef _WIN32 #define snprintf _snprintf #endif int _compare(void *compare_arg, void *a, void *b); int _free(void *key); int _printer(char *buff, void *key); int main(int argc, char **argv) { int i, max_nodes; avl_tree *tree; avl_node *node; max_nodes = 25; if (argc == 2) { max_nodes = atoi(argv[1]); if (max_nodes == 0) max_nodes = 10; } printf("avl test... max_nodes = %d...\n", max_nodes); tree = avl_tree_new(_compare, NULL); printf("Filling tree...\n"); for (i = 0; i < max_nodes; i++) { avl_insert(tree, (void *)rand()); } printf("Traversing tree...\n"); node = avl_get_first(tree); while (node) { i = (int)node->key; printf("...%5d\n", i); node = avl_get_next(node); } printf("Trying to go backwards...\n"); node = tree->root->right; while (node) { i = (int)node->key; printf("...%5d\n", i); node = avl_get_prev(node); } printf("Printing tree...\n"); avl_print_tree(tree, _printer); avl_tree_free(tree, _free); return 0; } int _compare(void *compare_arg, void *a, void *b) { int i, j; i = (int)a; j = (int)b; if (i > j) return 1; if (j > i) return -1; return 0; } int _free(void *key) { return 1; } int _printer(char *buff, void *key) { return snprintf(buff, 25, "%d", (int)key); } icecast-2.4.2/src/avl/Makefile.am0000664000175000017500000000056212511160565013467 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO avl.dsp test.c noinst_LTLIBRARIES = libiceavl.la noinst_HEADERS = avl.h libiceavl_la_SOURCES = avl.c libiceavl_la_CFLAGS = @XIPH_CFLAGS@ INCLUDES = -I$(srcdir)/.. debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" icecast-2.4.2/src/avl/TODO0000664000175000017500000000006212511160565012116 00000000000000- avl_get_last() - a little more cleanup probably icecast-2.4.2/src/avl/avl.c0000664000175000017500000006616612511160565012375 00000000000000/* * Copyright (C) 1995-1997 by Sam Rushing * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that copyright notice and this permission * notice appear in supporting documentation, and that the name of Sam * Rushing not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. * * SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* $Id: avl.c,v 1.11 2004/01/27 02:16:25 karl Exp $ */ /* * This is a fairly straightfoward translation of a prototype * written in python, 'avl_tree.py'. Read that file first. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "avl.h" avl_node * avl_node_new (void * key, avl_node * parent) { avl_node * node = (avl_node *) malloc (sizeof (avl_node)); if (!node) { return NULL; } else { node->parent = parent; node->key = key; node->left = NULL; node->right = NULL; node->rank_and_balance = 0; AVL_SET_BALANCE (node, 0); AVL_SET_RANK (node, 1); #ifdef HAVE_AVL_NODE_LOCK thread_rwlock_create(&node->rwlock); #endif return node; } } avl_tree * avl_tree_new (avl_key_compare_fun_type compare_fun, void * compare_arg) { avl_tree * t = (avl_tree *) malloc (sizeof (avl_tree)); if (!t) { return NULL; } else { avl_node * root = avl_node_new((void *)NULL, (avl_node *) NULL); if (!root) { free (t); return NULL; } else { t->root = root; t->height = 0; t->length = 0; t->compare_fun = compare_fun; t->compare_arg = compare_arg; thread_rwlock_create(&t->rwlock); return t; } } } static void avl_tree_free_helper (avl_node * node, avl_free_key_fun_type free_key_fun) { if (node->left) { avl_tree_free_helper (node->left, free_key_fun); } if (free_key_fun) free_key_fun (node->key); if (node->right) { avl_tree_free_helper (node->right, free_key_fun); } #ifdef HAVE_AVL_NODE_LOCK thread_rwlock_destroy (&node->rwlock); #endif free (node); } void avl_tree_free (avl_tree * tree, avl_free_key_fun_type free_key_fun) { if (tree->length) { avl_tree_free_helper (tree->root->right, free_key_fun); } if (tree->root) { #ifdef HAVE_AVL_NODE_LOCK thread_rwlock_destroy(&tree->root->rwlock); #endif free (tree->root); } thread_rwlock_destroy(&tree->rwlock); free (tree); } int avl_insert (avl_tree * ob, void * key) { if (!(ob->root->right)) { avl_node * node = avl_node_new (key, ob->root); if (!node) { return -1; } else { ob->root->right = node; ob->length = ob->length + 1; return 0; } } else { /* not self.right == None */ avl_node *t, *p, *s, *q, *r; int a; t = ob->root; s = p = t->right; while (1) { if (ob->compare_fun (ob->compare_arg, key, p->key) < 1) { /* move left */ AVL_SET_RANK (p, (AVL_GET_RANK (p) + 1)); q = p->left; if (!q) { /* insert */ avl_node * q_node = avl_node_new (key, p); if (!q_node) { return (-1); } else { q = q_node; p->left = q; break; } } else if (AVL_GET_BALANCE(q)) { t = p; s = q; } p = q; } else { /* move right */ q = p->right; if (!q) { /* insert */ avl_node * q_node = avl_node_new (key, p); if (!q_node) { return -1; } else { q = q_node; p->right = q; break; } } else if (AVL_GET_BALANCE(q)) { t = p; s = q; } p = q; } } ob->length = ob->length + 1; /* adjust balance factors */ if (ob->compare_fun (ob->compare_arg, key, s->key) < 1) { r = p = s->left; } else { r = p = s->right; } while (p != q) { if (ob->compare_fun (ob->compare_arg, key, p->key) < 1) { AVL_SET_BALANCE (p, -1); p = p->left; } else { AVL_SET_BALANCE (p, +1); p = p->right; } } /* balancing act */ if (ob->compare_fun (ob->compare_arg, key, s->key) < 1) { a = -1; } else { a = +1; } if (AVL_GET_BALANCE (s) == 0) { AVL_SET_BALANCE (s, a); ob->height = ob->height + 1; return 0; } else if (AVL_GET_BALANCE (s) == -a) { AVL_SET_BALANCE (s, 0); return 0; } else if (AVL_GET_BALANCE(s) == a) { if (AVL_GET_BALANCE (r) == a) { /* single rotation */ p = r; if (a == -1) { s->left = r->right; if (r->right) { r->right->parent = s; } r->right = s; s->parent = r; AVL_SET_RANK (s, (AVL_GET_RANK (s) - AVL_GET_RANK (r))); } else { s->right = r->left; if (r->left) { r->left->parent = s; } r->left = s; s->parent = r; AVL_SET_RANK (r, (AVL_GET_RANK (r) + AVL_GET_RANK (s))); } AVL_SET_BALANCE (s, 0); AVL_SET_BALANCE (r, 0); } else if (AVL_GET_BALANCE (r) == -a) { /* double rotation */ if (a == -1) { p = r->right; r->right = p->left; if (p->left) { p->left->parent = r; } p->left = r; r->parent = p; s->left = p->right; if (p->right) { p->right->parent = s; } p->right = s; s->parent = p; AVL_SET_RANK (p, (AVL_GET_RANK (p) + AVL_GET_RANK (r))); AVL_SET_RANK (s, (AVL_GET_RANK (s) - AVL_GET_RANK (p))); } else { p = r->left; r->left = p->right; if (p->right) { p->right->parent = r; } p->right = r; r->parent = p; s->right = p->left; if (p->left) { p->left->parent = s; } p->left = s; s->parent = p; AVL_SET_RANK (r, (AVL_GET_RANK (r) - AVL_GET_RANK (p))); AVL_SET_RANK (p, (AVL_GET_RANK (p) + AVL_GET_RANK (s))); } if (AVL_GET_BALANCE (p) == a) { AVL_SET_BALANCE (s, -a); AVL_SET_BALANCE (r, 0); } else if (AVL_GET_BALANCE (p) == -a) { AVL_SET_BALANCE (s, 0); AVL_SET_BALANCE (r, a); } else { AVL_SET_BALANCE (s, 0); AVL_SET_BALANCE (r, 0); } AVL_SET_BALANCE (p, 0); } /* finishing touch */ if (s == t->right) { t->right = p; } else { t->left = p; } p->parent = t; } } return 0; } int avl_get_by_index (avl_tree * tree, unsigned long index, void ** value_address) { avl_node * p = tree->root->right; unsigned long m = index + 1; while (1) { if (!p) { return -1; } if (m < AVL_GET_RANK(p)) { p = p->left; } else if (m > AVL_GET_RANK(p)) { m = m - AVL_GET_RANK(p); p = p->right; } else { *value_address = p->key; return 0; } } } int avl_get_by_key (avl_tree * tree, void * key, void **value_address) { avl_node * x = tree->root->right; if (!x) { return -1; } while (1) { int compare_result = tree->compare_fun (tree->compare_arg, key, x->key); if (compare_result < 0) { if (x->left) { x = x->left; } else { return -1; } } else if (compare_result > 0) { if (x->right) { x = x->right; } else { return -1; } } else { *value_address = x->key; return 0; } } } int avl_delete(avl_tree *tree, void *key, avl_free_key_fun_type free_key_fun) { avl_node *x, *y, *p, *q, *r, *top, *x_child; int shortened_side, shorter; x = tree->root->right; if (!x) { return -1; } while (1) { int compare_result = tree->compare_fun (tree->compare_arg, key, x->key); if (compare_result < 0) { /* move left * We will be deleting from the left, adjust this node's * rank accordingly */ AVL_SET_RANK (x, (AVL_GET_RANK(x) - 1)); if (x->left) { x = x->left; } else { /* Oops! now we have to undo the rank changes * all the way up the tree */ AVL_SET_RANK(x, (AVL_GET_RANK (x) + 1)); while (x != tree->root->right) { if (x->parent->left == x) { AVL_SET_RANK(x->parent, (AVL_GET_RANK (x->parent) + 1)); } x = x->parent; } return -1; /* key not in tree */ } } else if (compare_result > 0) { /* move right */ if (x->right) { x = x->right; } else { AVL_SET_RANK(x, (AVL_GET_RANK (x) + 1)); while (x != tree->root->right) { if (x->parent->left == x) { AVL_SET_RANK(x->parent, (AVL_GET_RANK (x->parent) + 1)); } x = x->parent; } return -1; /* key not in tree */ } } else { break; } } if (x->left && x->right) { void * temp_key; /* The complicated case. * reduce this to the simple case where we are deleting * a node with at most one child. */ /* find the immediate predecessor */ y = x->left; while (y->right) { y = y->right; } /* swap with */ temp_key = x->key; x->key = y->key; y->key = temp_key; /* we know 's left subtree lost a node because that's * where we took it from */ AVL_SET_RANK (x, (AVL_GET_RANK (x) - 1)); x = y; } /* now has at most one child * scoot this child into the place of */ if (x->left) { x_child = x->left; x_child->parent = x->parent; } else if (x->right) { x_child = x->right; x_child->parent = x->parent; } else { x_child = NULL; } /* now tell 's parent that a grandchild became a child */ if (x == x->parent->left) { x->parent->left = x_child; shortened_side = -1; } else { x->parent->right = x_child; shortened_side = +1; } /* * the height of the subtree * has now been shortened. climb back up * the tree, rotating when necessary to adjust * for the change. */ shorter = 1; p = x->parent; /* return the key and node to storage */ if (free_key_fun) free_key_fun (x->key); #ifdef HAVE_AVL_NODE_LOCK thread_rwlock_destroy (&x->rwlock); #endif free (x); while (shorter && p->parent) { /* case 1: height unchanged */ if (AVL_GET_BALANCE(p) == 0) { if (shortened_side == -1) { /* we removed a left child, the tree is now heavier * on the right */ AVL_SET_BALANCE (p, +1); } else { /* we removed a right child, the tree is now heavier * on the left */ AVL_SET_BALANCE (p, -1); } shorter = 0; } else if (AVL_GET_BALANCE (p) == shortened_side) { /* case 2: taller subtree shortened, height reduced */ AVL_SET_BALANCE (p, 0); } else { /* case 3: shorter subtree shortened */ top = p->parent; /* set to the taller of the two subtrees of

*/ if (shortened_side == 1) { q = p->left; } else { q = p->right; } if (AVL_GET_BALANCE (q) == 0) { /* case 3a: height unchanged */ if (shortened_side == -1) { /* single rotate left */ q->parent = p->parent; p->right = q->left; if (q->left) { q->left->parent = p; } q->left = p; p->parent = q; AVL_SET_RANK (q, (AVL_GET_RANK (q) + AVL_GET_RANK (p))); } else { /* single rotate right */ q->parent = p->parent; p->left = q->right; if (q->right) { q->right->parent = p; } q->right = p; p->parent = q; AVL_SET_RANK (p, (AVL_GET_RANK (p) - AVL_GET_RANK (q))); } shorter = 0; AVL_SET_BALANCE (q, shortened_side); AVL_SET_BALANCE (p, (- shortened_side)); } else if (AVL_GET_BALANCE (q) == AVL_GET_BALANCE (p)) { /* case 3b: height reduced */ if (shortened_side == -1) { /* single rotate left */ q->parent = p->parent; p->right = q->left; if (q->left) { q->left->parent = p; } q->left = p; p->parent = q; AVL_SET_RANK (q, (AVL_GET_RANK (q) + AVL_GET_RANK (p))); } else { /* single rotate right */ q->parent = p->parent; p->left = q->right; if (q->right) { q->right->parent = p; } q->right = p; p->parent = q; AVL_SET_RANK (p, (AVL_GET_RANK (p) - AVL_GET_RANK (q))); } shorter = 1; AVL_SET_BALANCE (q, 0); AVL_SET_BALANCE (p, 0); } else { /* case 3c: height reduced, balance factors opposite */ if (shortened_side == 1) { /* double rotate right */ /* first, a left rotation around q */ r = q->right; r->parent = p->parent; q->right = r->left; if (r->left) { r->left->parent = q; } r->left = q; q->parent = r; /* now, a right rotation around p */ p->left = r->right; if (r->right) { r->right->parent = p; } r->right = p; p->parent = r; AVL_SET_RANK (r, (AVL_GET_RANK (r) + AVL_GET_RANK (q))); AVL_SET_RANK (p, (AVL_GET_RANK (p) - AVL_GET_RANK (r))); } else { /* double rotate left */ /* first, a right rotation around q */ r = q->left; r->parent = p->parent; q->left = r->right; if (r->right) { r->right->parent = q; } r->right = q; q->parent = r; /* now a left rotation around p */ p->right = r->left; if (r->left) { r->left->parent = p; } r->left = p; p->parent = r; AVL_SET_RANK (q, (AVL_GET_RANK (q) - AVL_GET_RANK (r))); AVL_SET_RANK (r, (AVL_GET_RANK (r) + AVL_GET_RANK (p))); } if (AVL_GET_BALANCE (r) == shortened_side) { AVL_SET_BALANCE (q, (- shortened_side)); AVL_SET_BALANCE (p, 0); } else if (AVL_GET_BALANCE (r) == (- shortened_side)) { AVL_SET_BALANCE (q, 0); AVL_SET_BALANCE (p, shortened_side); } else { AVL_SET_BALANCE (q, 0); AVL_SET_BALANCE (p, 0); } AVL_SET_BALANCE (r, 0); q = r; } /* a rotation has caused (or in case 3c) to become * the root. let

's former parent know this. */ if (top->left == p) { top->left = q; } else { top->right = q; } /* end case 3 */ p = q; } x = p; p = x->parent; /* shortened_side tells us which side we came up from */ if (x == p->left) { shortened_side = -1; } else { shortened_side = +1; } } /* end while(shorter) */ /* when we're all done, we're one shorter */ tree->length = tree->length - 1; return (0); } static int avl_iterate_inorder_helper (avl_node * node, avl_iter_fun_type iter_fun, void * iter_arg) { int result; if (node->left) { result = avl_iterate_inorder_helper (node->left, iter_fun, iter_arg); if (result != 0) { return result; } } result = (iter_fun (node->key, iter_arg)); if (result != 0) { return result; } if (node->right) { result = avl_iterate_inorder_helper (node->right, iter_fun, iter_arg); if (result != 0) { return result; } } return 0; } int avl_iterate_inorder (avl_tree * tree, avl_iter_fun_type iter_fun, void * iter_arg) { int result; if (tree->length) { result = avl_iterate_inorder_helper (tree->root->right, iter_fun, iter_arg); return (result); } else { return 0; } } avl_node *avl_get_first(avl_tree *tree) { avl_node *node; node = tree->root->right; if (node == NULL || node->key == NULL) return NULL; while (node->left) node = node->left; return node; } avl_node *avl_get_prev(avl_node *node) { if (node->left) { node = node->left; while (node->right) { node = node->right; } return node; } else { avl_node *child = node; while (node->parent && node->parent->key) { node = node->parent; if (child == node->right) { return node; } child = node; } return NULL; } } avl_node *avl_get_next(avl_node *node) { if (node->right) { node = node->right; while (node->left) { node = node->left; } return node; } else { avl_node *child = node; while (node->parent && node->parent->key) { node = node->parent; if (child == node->left) { return node; } child = node; } return NULL; } } /* iterate a function over a range of indices, using get_predecessor */ int avl_iterate_index_range (avl_tree * tree, avl_iter_index_fun_type iter_fun, unsigned long low, unsigned long high, void * iter_arg) { unsigned long m; unsigned long num_left; avl_node * node; if (high > tree->length) { return -1; } num_left = (high - low); /* find the th node */ m = high; node = tree->root->right; while (1) { if (m < AVL_GET_RANK (node)) { node = node->left; } else if (m > AVL_GET_RANK (node)) { m = m - AVL_GET_RANK (node); node = node->right; } else { break; } } /* call on , , ... */ while (num_left) { num_left = num_left - 1; if (iter_fun (num_left, node->key, iter_arg) != 0) { return -1; } node = avl_get_prev (node); } return 0; } /* If is present in the tree, return that key's node, and set <*index> * appropriately. If not, return NULL, and set <*index> to the position * representing the closest preceding value. */ static avl_node * avl_get_index_by_key (avl_tree * tree, void * key, unsigned long * index) { avl_node * x = tree->root->right; unsigned long m; if (!x) { return NULL; } m = AVL_GET_RANK (x); while (1) { int compare_result = tree->compare_fun (tree->compare_arg, key, x->key); if (compare_result < 0) { if (x->left) { m = m - AVL_GET_RANK(x); x = x->left; m = m + AVL_GET_RANK(x); } else { *index = m - 2; return NULL; } } else if (compare_result > 0) { if (x->right) { x = x->right; m = m + AVL_GET_RANK(x); } else { *index = m - 1; return NULL; } } else { *index = m - 1; return x; } } } /* return the (low index, high index) pair that spans the given key */ int avl_get_span_by_key (avl_tree * tree, void * key, unsigned long * low, unsigned long * high) { unsigned long m, i, j; avl_node * node; node = avl_get_index_by_key (tree, key, &m); /* did we find an exact match? * if so, we have to search left and right * to find the span, since we know nothing about * the arrangement of like keys. */ if (node) { avl_node * left, * right; /* search left */ left = avl_get_prev (node); i = m; while (left && (i > 0) && (tree->compare_fun (tree->compare_arg, key, left->key) == 0)) { left = avl_get_prev (left); i = i - 1; } /* search right */ right = avl_get_next (node); j = m; while (right && (j <= tree->length) && (tree->compare_fun (tree->compare_arg, key, right->key) == 0)) { right = avl_get_next (right); j = j + 1; } *low = i; *high = j + 1; return 0; } else { *low = *high = m; } return 0; } /* return the (low index, high index) pair that spans the given key */ int avl_get_span_by_two_keys (avl_tree * tree, void * low_key, void * high_key, unsigned long * low, unsigned long * high) { unsigned long i, j; avl_node * low_node, * high_node; int order; /* we may need to swap them */ order = tree->compare_fun (tree->compare_arg, low_key, high_key); if (order > 0) { void * temp = low_key; low_key = high_key; high_key = temp; } low_node = avl_get_index_by_key (tree, low_key, &i); high_node = avl_get_index_by_key (tree, high_key, &j); if (low_node) { avl_node * left; /* search left */ left = avl_get_prev (low_node); while (left && (i > 0) && (tree->compare_fun (tree->compare_arg, low_key, left->key) == 0)) { left = avl_get_prev (left); i = i - 1; } } else { i = i + 1; } if (high_node) { avl_node * right; /* search right */ right = avl_get_next (high_node); while (right && (j <= tree->length) && (tree->compare_fun (tree->compare_arg, high_key, right->key) == 0)) { right = avl_get_next (right); j = j + 1; } } else { j = j + 1; } *low = i; *high = j; return 0; } int avl_get_item_by_key_most (avl_tree * tree, void * key, void **value_address) { avl_node * x = tree->root->right; *value_address = NULL; if (!x) { return -1; } while (1) { int compare_result = tree->compare_fun (tree->compare_arg, key, x->key); if (compare_result == 0) { *value_address = x->key; return 0; } else if (compare_result < 0) { /* the given key is less than the current key */ if (x->left) { x = x->left; } else { if (*value_address) return 0; else return -1; } } else { /* the given key is more than the current key */ /* save this value, it might end up being the right one! */ *value_address = x->key; if (x->right) { /* there is a bigger entry */ x = x->right; } else { if (*value_address) return 0; else return -1; } } } } int avl_get_item_by_key_least (avl_tree * tree, void * key, void **value_address) { avl_node * x = tree->root->right; *value_address = NULL; if (!x) { return -1; } while (1) { int compare_result = tree->compare_fun (tree->compare_arg, key, x->key); if (compare_result == 0) { *value_address = x->key; return 0; /* exact match */ } else if (compare_result < 0) { /* the given key is less than the current key */ /* save this value, it might end up being the right one! */ *value_address = x->key; if (x->left) { x = x->left; } else { if (*value_address) /* we have found a valid entry */ return 0; else return -1; } } else { if (x->right) { /* there is a bigger entry */ x = x->right; } else { if (*value_address) /* we have found a valid entry */ return 0; else return -1; } } } } #define AVL_MAX(X, Y) ((X) > (Y) ? (X) : (Y)) static long avl_verify_balance (avl_node * node) { if (!node) { return 0; } else { long lh = avl_verify_balance (node->left); long rh = avl_verify_balance (node->right); if ((rh - lh) != AVL_GET_BALANCE(node)) { return 0; } if (((lh - rh) > 1) || ((lh - rh) < -1)) { return 0; } return (1 + AVL_MAX (lh, rh)); } } static void avl_verify_parent (avl_node * node, avl_node * parent) { if (node->parent != parent) { return; } if (node->left) { avl_verify_parent (node->left, node); } if (node->right) { avl_verify_parent (node->right, node); } } static long avl_verify_rank (avl_node * node) { if (!node) { return 0; } else { unsigned long num_left=0, num_right=0; if (node->left) { num_left = avl_verify_rank (node->left); } if (node->right) { num_right = avl_verify_rank (node->right); } if (AVL_GET_RANK (node) != num_left + 1) { fprintf (stderr, "invalid rank at node %ld\n", (long) node->key); exit (1); } return (num_left + num_right + 1); } } /* sanity-check the tree */ int avl_verify (avl_tree * tree) { if (tree->length) { avl_verify_balance (tree->root->right); avl_verify_parent (tree->root->right, tree->root); avl_verify_rank (tree->root->right); } return (0); } /* * These structures are accumulated on the stack during print_tree * and are used to keep track of the width and direction of each * branch in the history of a particular line . */ typedef struct _link_node { struct _link_node * parent; char direction; int width; } link_node; static char balance_chars[3] = {'\\', '-', '/'}; static int default_key_printer (char * buffer, void * key) { return snprintf (buffer, AVL_KEY_PRINTER_BUFLEN, "%p", key); } /* * When traveling the family tree, a change in direction * indicates when to print a connector. This is kinda crazy, * we use the stack to build a linked list, and then travel * it backwards using recursion. */ static void print_connectors (link_node * link) { if (link->parent) { print_connectors (link->parent); } if (link->parent && (link->parent->direction != link->direction) && (link->parent->parent)) { int i; fprintf (stdout, "|"); for (i=0; i < (link->width - 1); i++) { fprintf (stdout, " "); } } else { int i; for (i=0; i < (link->width); i++) { fprintf (stdout, " "); } } } /* * The function writes a representation of the * key into (which is conveniently fixed in size to add * the spice of danger). It should return the size of the * representation. */ static void print_node (avl_key_printer_fun_type key_printer, avl_node * node, link_node * link) { char buffer[AVL_KEY_PRINTER_BUFLEN]; unsigned int width; width = key_printer (buffer, node->key); if (node->right) { link_node here; here.parent = link; here.direction = 1; here.width = width + 11; print_node (key_printer, node->right, &here); } print_connectors (link); fprintf (stdout, "+-[%c %s %03d]", balance_chars[AVL_GET_BALANCE(node)+1], buffer, (int)AVL_GET_RANK(node)); if (node->left || node->right) { fprintf (stdout, "-|\n"); } else { fprintf (stdout, "\n"); } if (node->left) { link_node here; here.parent = link; here.direction = -1; here.width = width + 11; print_node (key_printer, node->left, &here); } } void avl_print_tree (avl_tree * tree, avl_key_printer_fun_type key_printer) { link_node top = {NULL, 0, 0}; if (!key_printer) { key_printer = default_key_printer; } if (tree->length) { print_node (key_printer, tree->root->right, &top); } else { fprintf (stdout, "\n"); } } void avl_tree_rlock(avl_tree *tree) { thread_rwlock_rlock(&tree->rwlock); } void avl_tree_wlock(avl_tree *tree) { thread_rwlock_wlock(&tree->rwlock); } void avl_tree_unlock(avl_tree *tree) { thread_rwlock_unlock(&tree->rwlock); } #ifdef HAVE_AVL_NODE_LOCK void avl_node_rlock(avl_node *node) { thread_rwlock_rlock(&node->rwlock); } void avl_node_wlock(avl_node *node) { thread_rwlock_wlock(&node->rwlock); } void avl_node_unlock(avl_node *node) { thread_rwlock_unlock(&node->rwlock); } #endif icecast-2.4.2/src/avl/Makefile.in0000664000175000017500000004733112511177305013505 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/avl DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) COPYING README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libiceavl_la_LIBADD = am_libiceavl_la_OBJECTS = libiceavl_la-avl.lo libiceavl_la_OBJECTS = $(am_libiceavl_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libiceavl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libiceavl_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libiceavl_la_SOURCES) DIST_SOURCES = $(libiceavl_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO avl.dsp test.c noinst_LTLIBRARIES = libiceavl.la noinst_HEADERS = avl.h libiceavl_la_SOURCES = avl.c libiceavl_la_CFLAGS = @XIPH_CFLAGS@ INCLUDES = -I$(srcdir)/.. all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/avl/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/avl/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libiceavl.la: $(libiceavl_la_OBJECTS) $(libiceavl_la_DEPENDENCIES) $(EXTRA_libiceavl_la_DEPENDENCIES) $(AM_V_CCLD)$(libiceavl_la_LINK) $(libiceavl_la_OBJECTS) $(libiceavl_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiceavl_la-avl.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libiceavl_la-avl.lo: avl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiceavl_la_CFLAGS) $(CFLAGS) -MT libiceavl_la-avl.lo -MD -MP -MF $(DEPDIR)/libiceavl_la-avl.Tpo -c -o libiceavl_la-avl.lo `test -f 'avl.c' || echo '$(srcdir)/'`avl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libiceavl_la-avl.Tpo $(DEPDIR)/libiceavl_la-avl.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='avl.c' object='libiceavl_la-avl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiceavl_la_CFLAGS) $(CFLAGS) -c -o libiceavl_la-avl.lo `test -f 'avl.c' || echo '$(srcdir)/'`avl.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/avl/avl.dsp0000664000175000017500000000527612511160565012734 00000000000000# Microsoft Developer Studio Project File - Name="avl" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=avl - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "avl.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "avl.mak" CFG="avl - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "avl - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "avl - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "avl - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ELSEIF "$(CFG)" == "avl - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ENDIF # Begin Target # Name "avl - Win32 Release" # Name "avl - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\avl.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\avl.h # End Source File # End Group # End Target # End Project icecast-2.4.2/src/avl/BUILDING0000664000175000017500000000010212511160565012541 00000000000000defines that affect compilation none library dependencies none icecast-2.4.2/src/avl/COPYING0000664000175000017500000006127312511160565012474 00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! icecast-2.4.2/src/format_ebml.c0000664000175000017500000002531112511160565013303 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, * version 2. A copy of this license is included with this source. * At your option, this specific source file can also be distributed * under the GNU GPL version 3. * * Copyright 2012, David Richards, Mozilla Foundation, * and others (see AUTHORS for details). */ /* format_ebml.c * * format plugin for WebM/EBML * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "refbuf.h" #include "source.h" #include "client.h" #include "stats.h" #include "format.h" #include "format_ebml.h" #define CATMODULE "format-ebml" #include "logging.h" #define EBML_DEBUG 0 #define EBML_HEADER_MAX_SIZE 131072 #define EBML_SLICE_SIZE 4096 typedef struct ebml_client_data_st ebml_client_data_t; struct ebml_client_data_st { refbuf_t *header; int header_pos; }; struct ebml_st { char *cluster_id; int cluster_start; int position; unsigned char *input_buffer; unsigned char *buffer; int header_read; int header_size; int header_position; int header_read_position; unsigned char *header; }; static void ebml_free_plugin (format_plugin_t *plugin); static refbuf_t *ebml_get_buffer (source_t *source); static int ebml_write_buf_to_client (client_t *client); static void ebml_write_buf_to_file (source_t *source, refbuf_t *refbuf); static int ebml_create_client_data (source_t *source, client_t *client); static void ebml_free_client_data (client_t *client); static ebml_t *ebml_create(); static void ebml_destroy(ebml_t *ebml); static int ebml_read_space(ebml_t *ebml); static int ebml_read(ebml_t *ebml, char *buffer, int len); static int ebml_last_was_sync(ebml_t *ebml); static char *ebml_write_buffer(ebml_t *ebml, int len); static int ebml_wrote(ebml_t *ebml, int len); int format_ebml_get_plugin (source_t *source) { ebml_source_state_t *ebml_source_state = calloc(1, sizeof(ebml_source_state_t)); format_plugin_t *plugin = calloc(1, sizeof(format_plugin_t)); plugin->get_buffer = ebml_get_buffer; plugin->write_buf_to_client = ebml_write_buf_to_client; plugin->create_client_data = ebml_create_client_data; plugin->free_plugin = ebml_free_plugin; plugin->write_buf_to_file = ebml_write_buf_to_file; plugin->set_tag = NULL; plugin->apply_settings = NULL; plugin->contenttype = httpp_getvar (source->parser, "content-type"); plugin->_state = ebml_source_state; source->format = plugin; ebml_source_state->ebml = ebml_create(); return 0; } static void ebml_free_plugin (format_plugin_t *plugin) { ebml_source_state_t *ebml_source_state = plugin->_state; refbuf_release (ebml_source_state->header); ebml_destroy(ebml_source_state->ebml); free (ebml_source_state); free (plugin); } static int send_ebml_header (client_t *client) { ebml_client_data_t *ebml_client_data = client->format_data; int len = EBML_SLICE_SIZE; int ret; if (ebml_client_data->header->len - ebml_client_data->header_pos < len) { len = ebml_client_data->header->len - ebml_client_data->header_pos; } ret = client_send_bytes (client, ebml_client_data->header->data + ebml_client_data->header_pos, len); if (ret > 0) { ebml_client_data->header_pos += ret; } return ret; } static int ebml_write_buf_to_client (client_t *client) { ebml_client_data_t *ebml_client_data = client->format_data; if (ebml_client_data->header_pos != ebml_client_data->header->len) { return send_ebml_header (client); } else { client->write_to_client = format_generic_write_to_client; return client->write_to_client(client); } } static refbuf_t *ebml_get_buffer (source_t *source) { ebml_source_state_t *ebml_source_state = source->format->_state; format_plugin_t *format = source->format; char *data = NULL; int bytes = 0; refbuf_t *refbuf; int ret; while (1) { if ((bytes = ebml_read_space(ebml_source_state->ebml)) > 0) { refbuf = refbuf_new(bytes); ebml_read(ebml_source_state->ebml, refbuf->data, bytes); if (ebml_source_state->header == NULL) { ebml_source_state->header = refbuf; continue; } if (ebml_last_was_sync(ebml_source_state->ebml)) { refbuf->sync_point = 1; } return refbuf; } else { data = ebml_write_buffer(ebml_source_state->ebml, EBML_SLICE_SIZE); bytes = client_read_bytes (source->client, data, EBML_SLICE_SIZE); if (bytes <= 0) { ebml_wrote (ebml_source_state->ebml, 0); return NULL; } format->read_bytes += bytes; ret = ebml_wrote (ebml_source_state->ebml, bytes); if (ret != bytes) { ICECAST_LOG_ERROR("Problem processing stream"); source->running = 0; return NULL; } } } } static int ebml_create_client_data (source_t *source, client_t *client) { ebml_client_data_t *ebml_client_data = calloc(1, sizeof(ebml_client_data_t)); ebml_source_state_t *ebml_source_state = source->format->_state; int ret = -1; if ((ebml_client_data) && (ebml_source_state->header)) { ebml_client_data->header = ebml_source_state->header; refbuf_addref (ebml_client_data->header); client->format_data = ebml_client_data; client->free_client_data = ebml_free_client_data; ret = 0; } return ret; } static void ebml_free_client_data (client_t *client) { ebml_client_data_t *ebml_client_data = client->format_data; refbuf_release (ebml_client_data->header); free (client->format_data); client->format_data = NULL; } static void ebml_write_buf_to_file_fail (source_t *source) { ICECAST_LOG_WARN("Write to dump file failed, disabling"); fclose (source->dumpfile); source->dumpfile = NULL; } static void ebml_write_buf_to_file (source_t *source, refbuf_t *refbuf) { ebml_source_state_t *ebml_source_state = source->format->_state; if (ebml_source_state->file_headers_written == 0) { if (fwrite (ebml_source_state->header->data, 1, ebml_source_state->header->len, source->dumpfile) != ebml_source_state->header->len) ebml_write_buf_to_file_fail(source); else ebml_source_state->file_headers_written = 1; } if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) != refbuf->len) { ebml_write_buf_to_file_fail(source); } } /* internal ebml parsing */ static void ebml_destroy(ebml_t *ebml) { free(ebml->header); free(ebml->input_buffer); free(ebml->buffer); free(ebml); } static ebml_t *ebml_create() { ebml_t *ebml = calloc(1, sizeof(ebml_t)); ebml->header = calloc(1, EBML_HEADER_MAX_SIZE); ebml->buffer = calloc(1, EBML_SLICE_SIZE * 4); ebml->input_buffer = calloc(1, EBML_SLICE_SIZE); ebml->cluster_id = "\x1F\x43\xB6\x75"; ebml->cluster_start = -2; return ebml; } static int ebml_read_space(ebml_t *ebml) { int read_space; if (ebml->header_read == 1) { if (ebml->cluster_start > 0) read_space = ebml->cluster_start; else read_space = ebml->position - 4; return read_space; } else { if (ebml->header_size != 0) return ebml->header_size; else return 0; } } static int ebml_read(ebml_t *ebml, char *buffer, int len) { int read_space; int to_read; if (len < 1) return 0; if (ebml->header_read == 1) { if (ebml->cluster_start > 0) read_space = ebml->cluster_start; else read_space = ebml->position - 4; if (read_space < 1) return 0; if (read_space >= len ) to_read = len; else to_read = read_space; memcpy(buffer, ebml->buffer, to_read); memmove(ebml->buffer, ebml->buffer + to_read, ebml->position - to_read); ebml->position -= to_read; if (ebml->cluster_start > 0) ebml->cluster_start -= to_read; } else { if (ebml->header_size != 0) { read_space = ebml->header_size - ebml->header_read_position; if (read_space >= len) to_read = len; else to_read = read_space; memcpy(buffer, ebml->header, to_read); ebml->header_read_position += to_read; if (ebml->header_read_position == ebml->header_size) ebml->header_read = 1; } else { return 0; } } return to_read; } static int ebml_last_was_sync(ebml_t *ebml) { if (ebml->cluster_start == 0) { ebml->cluster_start -= 1; return 0; } if (ebml->cluster_start == -1) { ebml->cluster_start -= 1; return 1; } return 0; } static char *ebml_write_buffer(ebml_t *ebml, int len) { return (char *)ebml->input_buffer; } static int ebml_wrote(ebml_t *ebml, int len) { int b; if (ebml->header_size == 0) { if ((ebml->header_position + len) > EBML_HEADER_MAX_SIZE) { ICECAST_LOG_ERROR("EBML Header too large, failing"); return -1; } if (EBML_DEBUG) { printf("EBML: Adding to header, ofset is %d size is %d adding %d\n", ebml->header_size, ebml->header_position, len); } memcpy(ebml->header + ebml->header_position, ebml->input_buffer, len); ebml->header_position += len; } else { memcpy(ebml->buffer + ebml->position, ebml->input_buffer, len); } for (b = 0; b < len - 4; b++) { if (!memcmp(ebml->input_buffer + b, ebml->cluster_id, 4)) { if (EBML_DEBUG) { printf("EBML: found cluster\n"); } if (ebml->header_size == 0) { ebml->header_size = ebml->header_position - len + b; memcpy(ebml->buffer, ebml->input_buffer + b, len - b); ebml->position = len - b; ebml->cluster_start = -1; return len; } else { ebml->cluster_start = ebml->position + b; } } } ebml->position += len; return len; } icecast-2.4.2/src/logging.c0000664000175000017500000001541112511160565012442 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "thread/thread.h" #include "httpp/httpp.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "compat.h" #include "cfgfile.h" #include "logging.h" #include "util.h" #ifdef _WIN32 #define snprintf _snprintf #define vsnprintf _vsnprintf #endif /* the global log descriptors */ int errorlog = 0; int accesslog = 0; int playlistlog = 0; #ifdef _WIN32 /* Since strftime's %z option on win32 is different, we need to go through a few loops to get the same info as %z */ int get_clf_time (char *buffer, unsigned len, struct tm *t) { char sign; char *timezone_string; struct tm gmt; time_t time1 = time(NULL); int time_days, time_hours, time_tz; int tempnum1, tempnum2; struct tm *thetime; time_t now; #if !defined(_WIN32) thetime = gmtime_r(&time1, &gmt) #else /* gmtime() on W32 breaks POSIX and IS thread-safe (uses TLS) */ thetime = gmtime (&time1); if (thetime) memcpy (&gmt, thetime, sizeof (gmt)); #endif /* FIXME: bail out if gmtime* returns NULL */ time_days = t->tm_yday - gmt.tm_yday; if (time_days < -1) { tempnum1 = 24; } else { tempnum1 = 1; } if (tempnum1 < time_days) { tempnum2 = -24; } else { tempnum2 = time_days*24; } time_hours = (tempnum2 + t->tm_hour - gmt.tm_hour); time_tz = time_hours * 60 + t->tm_min - gmt.tm_min; if (time_tz < 0) { sign = '-'; time_tz = -time_tz; } else { sign = '+'; } timezone_string = calloc(1, 7); snprintf(timezone_string, 7, " %c%.2d%.2d", sign, time_tz / 60, time_tz % 60); now = time(NULL); thetime = localtime(&now); strftime (buffer, len-7, "%d/%b/%Y:%H:%M:%S", thetime); strcat(buffer, timezone_string); free(timezone_string); return 1; } #endif /* ** ADDR IDENT USER DATE REQUEST CODE BYTES REFERER AGENT [TIME] ** ** ADDR = client->con->ip ** IDENT = always - , we don't support it because it's useless ** USER = client->username ** DATE = _make_date(client->con->con_time) ** REQUEST = build from client->parser ** CODE = client->respcode ** BYTES = client->con->sent_bytes ** REFERER = get from client->parser ** AGENT = get from client->parser ** TIME = timing_get_time() - client->con->con_time */ void logging_access(client_t *client) { char datebuf[128]; struct tm thetime; time_t now; time_t stayed; const char *referrer, *user_agent, *username; now = time(NULL); localtime_r (&now, &thetime); /* build the data */ #ifdef _WIN32 memset(datebuf, '\000', sizeof(datebuf)); get_clf_time(datebuf, sizeof(datebuf)-1, &thetime); #else strftime (datebuf, sizeof(datebuf), LOGGING_FORMAT_CLF, &thetime); #endif stayed = now - client->con->con_time; if (client->username == NULL) username = "-"; else username = client->username; referrer = httpp_getvar (client->parser, "referer"); if (referrer == NULL) referrer = "-"; user_agent = httpp_getvar (client->parser, "user-agent"); if (user_agent == NULL) user_agent = "-"; log_write_direct (accesslog, "%s - %H [%s] \"%H %H %H/%H\" %d %llu \"% H\" \"% H\" %llu", client->con->ip, username, datebuf, httpp_getvar (client->parser, HTTPP_VAR_REQ_TYPE), httpp_getvar (client->parser, HTTPP_VAR_URI), httpp_getvar (client->parser, HTTPP_VAR_PROTOCOL), httpp_getvar (client->parser, HTTPP_VAR_VERSION), client->respcode, (long long unsigned int)client->con->sent_bytes, referrer, user_agent, (long long unsigned int)stayed); } /* This function will provide a log of metadata for each mountpoint. The metadata *must* be in UTF-8, and thus you can assume that the log itself is UTF-8 encoded */ void logging_playlist(const char *mount, const char *metadata, long listeners) { char datebuf[128]; struct tm thetime; time_t now; if (playlistlog == -1) { return; } now = time(NULL); localtime_r (&now, &thetime); /* build the data */ #ifdef _WIN32 memset(datebuf, '\000', sizeof(datebuf)); get_clf_time(datebuf, sizeof(datebuf)-1, &thetime); #else strftime (datebuf, sizeof(datebuf), LOGGING_FORMAT_CLF, &thetime); #endif /* This format MAY CHANGE OVER TIME. We are looking into finding a good standard format for this, if you have any ideas, please let us know */ log_write_direct (playlistlog, "%s|%s|%ld|%s", datebuf, mount, listeners, metadata); } void log_parse_failure (void *ctx, const char *fmt, ...) { char line [200]; va_list ap; char *eol; va_start (ap, fmt); vsnprintf (line, sizeof (line), fmt, ap); eol = strrchr (line, '\n'); if (eol) *eol='\0'; va_end (ap); log_write (errorlog, 2, (char*)ctx, "", "%s", line); } void restart_logging (ice_config_t *config) { if (strcmp (config->error_log, "-")) { char fn_error[FILENAME_MAX]; snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log); log_set_filename (errorlog, fn_error); log_set_level (errorlog, config->loglevel); log_set_trigger (errorlog, config->logsize); log_set_archive_timestamp(errorlog, config->logarchive); log_reopen (errorlog); } if (strcmp (config->access_log, "-")) { char fn_error[FILENAME_MAX]; snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->access_log); log_set_filename (accesslog, fn_error); log_set_trigger (accesslog, config->logsize); log_set_archive_timestamp (accesslog, config->logarchive); log_reopen (accesslog); } if (config->playlist_log) { char fn_error[FILENAME_MAX]; snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log); log_set_filename (playlistlog, fn_error); log_set_trigger (playlistlog, config->logsize); log_set_archive_timestamp (playlistlog, config->logarchive); log_reopen (playlistlog); } } icecast-2.4.2/src/format_skeleton.h0000664000175000017500000000116512510726173014220 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_SKELETON_H #define __FORMAT_SKELETON_H #include "format_ogg.h" ogg_codec_t *initial_skeleton_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_SKELETON_H */ icecast-2.4.2/src/md5.h0000664000175000017500000000151612510726173011511 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __MD5_H__ #define __MD5_H__ #include "compat.h" #define HASH_LEN 16 struct MD5Context { uint32_t buf[4]; uint32_t bits[2]; unsigned char in[64]; }; void MD5Init(struct MD5Context *context); void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len); void MD5Final(unsigned char digest[HASH_LEN], struct MD5Context *context); #endif icecast-2.4.2/src/slave.h0000664000175000017500000000204512511160565012132 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __SLAVE_H__ #define __SLAVE_H__ #include "thread/thread.h" typedef struct _relay_server { char *server; int port; char *mount; char *username; char *password; char *localmount; char *bind; struct source_tag *source; int mp3metadata; int on_demand; int running; int cleanup; time_t start; thread_type *thread; struct _relay_server *next; } relay_server; void slave_initialize(void); void slave_shutdown(void); void slave_update_all_mounts (void); void slave_rebuild_mounts (void); relay_server *relay_free (relay_server *relay); #endif /* __SLAVE_H__ */ icecast-2.4.2/src/format_mp3.c0000664000175000017500000005314112511160565013065 00000000000000/* -*- c-basic-offset: 4; -*- */ /* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft , */ /* format_mp3.c ** ** format plugin for mp3 ** */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifdef HAVE_STRINGS_H # include #endif #include "refbuf.h" #include "source.h" #include "client.h" #include "stats.h" #include "format.h" #include "httpp/httpp.h" #include "logging.h" #include "format_mp3.h" #ifdef WIN32 #define strcasecmp stricmp #define strncasecmp strnicmp #define snprintf _snprintf #endif #define CATMODULE "format-mp3" /* Note that this seems to be 8192 in shoutcast - perhaps we want to be the * same for compability with crappy clients? */ #define ICY_METADATA_INTERVAL 16000 static void format_mp3_free_plugin(format_plugin_t *self); static refbuf_t *mp3_get_filter_meta (source_t *source); static refbuf_t *mp3_get_no_meta (source_t *source); static int format_mp3_create_client_data (source_t *source, client_t *client); static void free_mp3_client_data (client_t *client); static int format_mp3_write_buf_to_client(client_t *client); static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf); static void mp3_set_tag (format_plugin_t *plugin, const char *tag, const char *in_value, const char *charset); static void format_mp3_apply_settings(client_t *client, format_plugin_t *format, mount_proxy *mount); typedef struct { unsigned int interval; int metadata_offset; unsigned int since_meta_block; int in_metadata; refbuf_t *associated; } mp3_client_data; int format_mp3_get_plugin (source_t *source) { const char *metadata; format_plugin_t *plugin; mp3_state *state = calloc(1, sizeof(mp3_state)); refbuf_t *meta; plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t)); plugin->type = FORMAT_TYPE_GENERIC; plugin->get_buffer = mp3_get_no_meta; plugin->write_buf_to_client = format_mp3_write_buf_to_client; plugin->write_buf_to_file = write_mp3_to_file; plugin->create_client_data = format_mp3_create_client_data; plugin->free_plugin = format_mp3_free_plugin; plugin->set_tag = mp3_set_tag; plugin->apply_settings = format_mp3_apply_settings; plugin->contenttype = httpp_getvar (source->parser, "content-type"); if (plugin->contenttype == NULL) { /* We default to MP3 audio for old clients without content types */ plugin->contenttype = "audio/mpeg"; } plugin->_state = state; /* initial metadata needs to be blank for sending to clients and for comparing with new metadata */ meta = refbuf_new (17); memcpy (meta->data, "\001StreamTitle='';", 17); state->metadata = meta; state->interval = -1; metadata = httpp_getvar (source->parser, "icy-metaint"); if (metadata) { state->inline_metadata_interval = atoi (metadata); if (state->inline_metadata_interval > 0) { state->offset = 0; plugin->get_buffer = mp3_get_filter_meta; state->interval = state->inline_metadata_interval; } } source->format = plugin; thread_mutex_create (&state->url_lock); return 0; } static void mp3_set_tag (format_plugin_t *plugin, const char *tag, const char *in_value, const char *charset) { mp3_state *source_mp3 = plugin->_state; char *value = NULL; /* protect against multiple updaters */ thread_mutex_lock (&source_mp3->url_lock); if (tag==NULL) { source_mp3->update_metadata = 1; thread_mutex_unlock (&source_mp3->url_lock); return; } if (in_value) { value = util_conv_string (in_value, charset, plugin->charset); if (value == NULL) value = strdup (in_value); } if (strcmp (tag, "title") == 0 || strcmp (tag, "song") == 0) { free (source_mp3->url_title); source_mp3->url_title = value; } else if (strcmp (tag, "artist") == 0) { free (source_mp3->url_artist); source_mp3->url_artist = value; } else if (strcmp (tag, "url") == 0) { free (source_mp3->url); source_mp3->url = value; } else free (value); thread_mutex_unlock (&source_mp3->url_lock); } static void filter_shoutcast_metadata (source_t *source, char *metadata, unsigned int meta_len) { if (metadata) { char *end, *p; int len; do { metadata++; if (strncmp (metadata, "StreamTitle='", 13)) break; if ((end = strstr (metadata+13, "\';")) == NULL) break; len = (end - metadata) - 13; p = calloc (1, len+1); if (p) { memcpy (p, metadata+13, len); logging_playlist (source->mount, p, source->listeners); stats_event_conv (source->mount, "title", p, source->format->charset); yp_touch (source->mount); free (p); } } while (0); } } static void format_mp3_apply_settings (client_t *client, format_plugin_t *format, mount_proxy *mount) { mp3_state *source_mp3 = format->_state; source_mp3->interval = -1; free (format->charset); format->charset = NULL; if (mount) { if (mount->mp3_meta_interval >= 0) source_mp3->interval = mount->mp3_meta_interval; if (mount->charset) format->charset = strdup (mount->charset); } if (source_mp3->interval < 0) { const char *metadata = httpp_getvar (client->parser, "icy-metaint"); source_mp3->interval = ICY_METADATA_INTERVAL; if (metadata) { int interval = atoi (metadata); if (interval > 0) source_mp3->interval = interval; } } if (format->charset == NULL) format->charset = strdup ("ISO8859-1"); ICECAST_LOG_DEBUG("sending metadata interval %d", source_mp3->interval); ICECAST_LOG_DEBUG("charset %s", format->charset); } /* called from the source thread when the metadata has been updated. * The artist title are checked and made ready for clients to send */ static void mp3_set_title (source_t *source) { const char streamtitle[] = "StreamTitle='"; const char streamurl[] = "StreamUrl='"; size_t size; unsigned char len_byte; refbuf_t *p; unsigned int len = sizeof(streamtitle) + 2; /* the StreamTitle, quotes, ; and null */ mp3_state *source_mp3 = source->format->_state; /* make sure the url data does not disappear from under us */ thread_mutex_lock (&source_mp3->url_lock); /* work out message length */ if (source_mp3->url_artist) len += strlen (source_mp3->url_artist); if (source_mp3->url_title) len += strlen (source_mp3->url_title); if (source_mp3->url_artist && source_mp3->url_title) len += 3; if (source_mp3->inline_url) { char *end = strstr (source_mp3->inline_url, "';"); if (end) len += end - source_mp3->inline_url+2; } else if (source_mp3->url) len += strlen (source_mp3->url) + strlen (streamurl) + 2; #define MAX_META_LEN 255*16 if (len > MAX_META_LEN) { thread_mutex_unlock (&source_mp3->url_lock); ICECAST_LOG_WARN("Metadata too long at %d chars", len); return; } /* work out the metadata len byte */ len_byte = (len-1) / 16 + 1; /* now we know how much space to allocate, +1 for the len byte */ size = len_byte * 16 + 1; p = refbuf_new (size); if (p) { mp3_state *source_mp3 = source->format->_state; int r; memset (p->data, '\0', size); if (source_mp3->url_artist && source_mp3->url_title) r = snprintf (p->data, size, "%c%s%s - %s';", len_byte, streamtitle, source_mp3->url_artist, source_mp3->url_title); else r = snprintf (p->data, size, "%c%s%s';", len_byte, streamtitle, source_mp3->url_title); if (r > 0) { if (source_mp3->inline_url) { char *end = strstr (source_mp3->inline_url, "';"); ssize_t urllen = size; if (end) urllen = end - source_mp3->inline_url + 2; if ((ssize_t)(size-r) > urllen) snprintf (p->data+r, size-r, "StreamUrl='%s';", source_mp3->inline_url+11); } else if (source_mp3->url) snprintf (p->data+r, size-r, "StreamUrl='%s';", source_mp3->url); } ICECAST_LOG_DEBUG("shoutcast metadata block setup with %s", p->data+1); filter_shoutcast_metadata (source, p->data, size); refbuf_release (source_mp3->metadata); source_mp3->metadata = p; } thread_mutex_unlock (&source_mp3->url_lock); } /* send the appropriate metadata, and return the number of bytes written * which is 0 or greater. Check the client in_metadata value afterwards * to see if all metadata has been sent */ static int send_stream_metadata (client_t *client, refbuf_t *associated) { int ret = 0; char *metadata; int meta_len; mp3_client_data *client_mp3 = client->format_data; /* If there is a change in metadata then send it else * send a single zero value byte in its place */ if (associated && associated != client_mp3->associated) { metadata = associated->data + client_mp3->metadata_offset; meta_len = associated->len - client_mp3->metadata_offset; } else { if (associated) { metadata = "\0"; meta_len = 1; } else { char *meta = "\001StreamTitle='';"; metadata = meta + client_mp3->metadata_offset; meta_len = 17 - client_mp3->metadata_offset; } } ret = client_send_bytes (client, metadata, meta_len); if (ret == meta_len) { client_mp3->associated = associated; client_mp3->metadata_offset = 0; client_mp3->in_metadata = 0; client_mp3->since_meta_block = 0; return ret; } if (ret > 0) client_mp3->metadata_offset += ret; else ret = 0; client_mp3->in_metadata = 1; return ret; } /* Handler for writing mp3 data to a client, taking into account whether * client has requested shoutcast style metadata updates */ static int format_mp3_write_buf_to_client(client_t *client) { int ret, written = 0; mp3_client_data *client_mp3 = client->format_data; refbuf_t *refbuf = client->refbuf; char *buf = refbuf->data + client->pos; unsigned int len = refbuf->len - client->pos; do { /* send any unwritten metadata to the client */ if (client_mp3->in_metadata) { refbuf_t *associated = refbuf->associated; ret = send_stream_metadata (client, associated); if (client_mp3->in_metadata) break; written += ret; } /* see if we need to send the current metadata to the client */ if (client_mp3->interval) { unsigned int remaining = client_mp3->interval - client_mp3->since_meta_block; /* leading up to sending the metadata block */ if (remaining <= len) { /* send any mp3 before the metadata block */ if (remaining) { ret = client_send_bytes (client, buf, remaining); if (ret > 0) { client_mp3->since_meta_block += ret; client->pos += ret; } if (ret < (int)remaining) break; written += ret; } ret = send_stream_metadata (client, refbuf->associated); if (client_mp3->in_metadata) break; written += ret; buf += remaining; len -= remaining; /* limit how much mp3 we send if using small intervals */ if (len > client_mp3->interval) len = client_mp3->interval; } } /* write any mp3, maybe after the metadata block */ if (len) { ret = client_send_bytes (client, buf, len); if (ret > 0) { client_mp3->since_meta_block += ret; client->pos += ret; } if (ret < (int)len) break; written += ret; } ret = 0; } while (0); if (ret > 0) written += ret; return written; } static void format_mp3_free_plugin(format_plugin_t *self) { /* free the plugin instance */ mp3_state *state = self->_state; thread_mutex_destroy (&state->url_lock); free (state->url_artist); free (state->url_title); free (self->charset); refbuf_release (state->metadata); refbuf_release (state->read_data); free(state); free(self); } /* This does the actual reading, making sure the read data is packaged in * blocks of 1400 bytes (near the common MTU size). This is because many * incoming streams come in small packets which could waste a lot of * bandwidth with many listeners due to headers and such like. */ static int complete_read (source_t *source) { int bytes; format_plugin_t *format = source->format; mp3_state *source_mp3 = format->_state; char *buf; refbuf_t *refbuf; #define REFBUF_SIZE 1400 if (source_mp3->read_data == NULL) { source_mp3->read_data = refbuf_new (REFBUF_SIZE); source_mp3->read_count = 0; } buf = source_mp3->read_data->data + source_mp3->read_count; bytes = client_read_bytes (source->client, buf, REFBUF_SIZE-source_mp3->read_count); if (bytes < 0) { if (source->client->con->error) { refbuf_release (source_mp3->read_data); source_mp3->read_data = NULL; } return 0; } source_mp3->read_count += bytes; refbuf = source_mp3->read_data; refbuf->len = source_mp3->read_count; format->read_bytes += bytes; if (source_mp3->read_count < REFBUF_SIZE) { if (source_mp3->read_count == 0) { refbuf_release (source_mp3->read_data); source_mp3->read_data = NULL; } return 0; } return 1; } /* read an mp3 stream which does not have shoutcast style metadata */ static refbuf_t *mp3_get_no_meta (source_t *source) { refbuf_t *refbuf; mp3_state *source_mp3 = source->format->_state; if (complete_read (source) == 0) return NULL; refbuf = source_mp3->read_data; source_mp3->read_data = NULL; if (source_mp3->update_metadata) { mp3_set_title (source); source_mp3->update_metadata = 0; } refbuf->associated = source_mp3->metadata; refbuf_addref (source_mp3->metadata); refbuf->sync_point = 1; return refbuf; } /* read mp3 data with inlined metadata from the source. Filter out the * metadata so that the mp3 data itself is store on the queue and the * metadata is is associated with it */ static refbuf_t *mp3_get_filter_meta (source_t *source) { refbuf_t *refbuf; format_plugin_t *plugin = source->format; mp3_state *source_mp3 = plugin->_state; unsigned char *src; unsigned int bytes, mp3_block; if (complete_read (source) == 0) return NULL; refbuf = source_mp3->read_data; source_mp3->read_data = NULL; src = (unsigned char *)refbuf->data; if (source_mp3->update_metadata) { mp3_set_title (source); source_mp3->update_metadata = 0; } /* fill the buffer with the read data */ bytes = source_mp3->read_count; refbuf->len = 0; while (bytes > 0) { unsigned int metadata_remaining; mp3_block = source_mp3->inline_metadata_interval - source_mp3->offset; /* is there only enough to account for mp3 data */ if (bytes <= mp3_block) { refbuf->len += bytes; source_mp3->offset += bytes; break; } /* we have enough data to get to the metadata * block, but only transfer upto it */ if (mp3_block) { src += mp3_block; bytes -= mp3_block; refbuf->len += mp3_block; source_mp3->offset += mp3_block; continue; } /* process the inline metadata, len == 0 indicates not seen any yet */ if (source_mp3->build_metadata_len == 0) { memset (source_mp3->build_metadata, 0, sizeof (source_mp3->build_metadata)); source_mp3->build_metadata_offset = 0; source_mp3->build_metadata_len = 1 + (*src * 16); } /* do we have all of the metatdata block */ metadata_remaining = source_mp3->build_metadata_len - source_mp3->build_metadata_offset; if (bytes < metadata_remaining) { memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset, src, bytes); source_mp3->build_metadata_offset += bytes; break; } /* copy all bytes except the last one, that way we * know a null byte terminates the message */ memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset, src, metadata_remaining-1); /* overwrite metadata in the buffer */ bytes -= metadata_remaining; memmove (src, src+metadata_remaining, bytes); /* assign metadata if it's greater than 1 byte, and the text has changed */ if (source_mp3->build_metadata_len > 1 && strcmp (source_mp3->build_metadata+1, source_mp3->metadata->data+1) != 0) { refbuf_t *meta = refbuf_new (source_mp3->build_metadata_len); memcpy (meta->data, source_mp3->build_metadata, source_mp3->build_metadata_len); ICECAST_LOG_DEBUG("shoutcast metadata %.*s", 4080, meta->data+1); if (strncmp (meta->data+1, "StreamTitle=", 12) == 0) { filter_shoutcast_metadata (source, source_mp3->build_metadata, source_mp3->build_metadata_len); refbuf_release (source_mp3->metadata); source_mp3->metadata = meta; source_mp3->inline_url = strstr (meta->data+1, "StreamUrl='"); } else { ICECAST_LOG_ERROR("Incorrect metadata format, ending stream"); source->running = 0; refbuf_release (refbuf); refbuf_release (meta); return NULL; } } source_mp3->offset = 0; source_mp3->build_metadata_len = 0; } /* the data we have just read may of just been metadata */ if (refbuf->len == 0) { refbuf_release (refbuf); return NULL; } refbuf->associated = source_mp3->metadata; refbuf_addref (source_mp3->metadata); refbuf->sync_point = 1; return refbuf; } static int format_mp3_create_client_data(source_t *source, client_t *client) { mp3_client_data *client_mp3 = calloc(1,sizeof(mp3_client_data)); mp3_state *source_mp3 = source->format->_state; const char *metadata; /* the +-2 is for overwriting the last set of \r\n */ unsigned remaining = 4096 - client->refbuf->len + 2; char *ptr = client->refbuf->data + client->refbuf->len - 2; int bytes; const char *useragent; if (client_mp3 == NULL) return -1; /* hack for flash player, it wants a length. It has also been reported that the useragent * appears as MSIE if run in internet explorer */ useragent = httpp_getvar (client->parser, "user-agent"); if (httpp_getvar(client->parser, "x-flash-version") || (useragent && strstr(useragent, "MSIE"))) { bytes = snprintf (ptr, remaining, "Content-Length: 221183499\r\n"); remaining -= bytes; ptr += bytes; } client->format_data = client_mp3; client->free_client_data = free_mp3_client_data; metadata = httpp_getvar(client->parser, "icy-metadata"); if (metadata && atoi(metadata)) { if (source_mp3->interval >= 0) client_mp3->interval = source_mp3->interval; else client_mp3->interval = ICY_METADATA_INTERVAL; if (client_mp3->interval) { bytes = snprintf (ptr, remaining, "icy-metaint:%u\r\n", client_mp3->interval); if (bytes > 0) { remaining -= bytes; ptr += bytes; } } } bytes = snprintf (ptr, remaining, "\r\n"); remaining -= bytes; ptr += bytes; client->refbuf->len = 4096 - remaining; return 0; } static void free_mp3_client_data (client_t *client) { free (client->format_data); client->format_data = NULL; } static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf) { if (refbuf->len == 0) return; if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) < (size_t)refbuf->len) { ICECAST_LOG_WARN("Write to dump file failed, disabling"); fclose (source->dumpfile); source->dumpfile = NULL; } } icecast-2.4.2/src/global.c0000664000175000017500000000253712511160565012261 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #ifdef HAVE_CONFIG_H #include #endif #include #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "source.h" #include "format.h" #include "global.h" ice_global_t global; static mutex_t _global_mutex; void global_initialize(void) { global.server_sockets = 0; global.relays = NULL; global.master_relays = NULL; global.running = 0; global.clients = 0; global.sources = 0; global.source_tree = avl_tree_new(source_compare_sources, NULL); thread_mutex_create(&_global_mutex); } void global_shutdown(void) { thread_mutex_destroy(&_global_mutex); avl_tree_free(global.source_tree, NULL); } void global_lock(void) { thread_mutex_lock(&_global_mutex); } void global_unlock(void) { thread_mutex_unlock(&_global_mutex); } icecast-2.4.2/src/log/0000775000175000017500000000000012511177344011512 500000000000000icecast-2.4.2/src/log/test.c0000664000175000017500000000046712511160565012561 00000000000000#include "log.h" #define CATMODULE "test" #define LOG_ERR(x, y, z...) log_write(x, 1, CATMODULE "/" __FUNCTION__, y, ##z) int main(void) { int lid; log_initialize(); lid = log_open("test.log"); LOG_ERR(lid, "The log id is %d, damnit...", lid); log_close(lid); log_shutdown(); } icecast-2.4.2/src/log/Makefile.am0000664000175000017500000000045112511160565013463 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign EXTRA_DIST = test.c noinst_LTLIBRARIES = libicelog.la noinst_HEADERS = log.h libicelog_la_SOURCES = log.c AM_CFLAGS = $(XIPH_CFLAGS) debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" icecast-2.4.2/src/log/log.h0000664000175000017500000000230712511160565012363 00000000000000/* ** Logging framework. ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. */ #ifndef __LOG_H__ #define __LOG_H__ #include #define LOG_EINSANE -1 #define LOG_ENOMORELOGS -2 #define LOG_ECANTOPEN -3 #define LOG_ENOTOPEN -4 #define LOG_ENOTIMPL -5 #ifdef _WIN32 #define IO_BUFFER_TYPE _IONBF #else #define IO_BUFFER_TYPE _IOLBF #endif void log_initialize(void); int log_open_file(FILE *file); int log_open(const char *filename); int log_open_with_buffer(const char *filename, int size); void log_set_level(int log_id, unsigned level); void log_set_trigger(int id, unsigned trigger); int log_set_filename(int id, const char *filename); void log_set_lines_kept (int log_id, unsigned int count); void log_contents (int log_id, char **_contents, unsigned int *_len); int log_set_archive_timestamp(int id, int value); void log_flush(int log_id); void log_reopen(int log_id); void log_close(int log_id); void log_shutdown(void); void log_write(int log_id, unsigned priority, const char *cat, const char *func, const char *fmt, ...); void log_write_direct(int log_id, const char *fmt, ...); #endif /* __LOG_H__ */ icecast-2.4.2/src/log/log.c0000664000175000017500000004076512511160565012370 00000000000000/* ** Logging framework. ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifndef _WIN32 #include #else #include #endif #include "log.h" #define LOG_MAXLOGS 25 #define LOG_MAXLINELEN 1024 #ifdef _WIN32 #define mutex_t CRITICAL_SECTION #define snprintf _snprintf #define vsnprintf _vsnprintf #else #define mutex_t pthread_mutex_t #endif static mutex_t _logger_mutex; static int _initialized = 0; typedef struct _log_entry_t { char *line; unsigned int len; struct _log_entry_t *next; } log_entry_t; typedef struct log_tag { int in_use; unsigned level; char *filename; FILE *logfile; off_t size; off_t trigger_level; int archive_timestamp; unsigned long total; unsigned int entries; unsigned int keep_entries; log_entry_t *log_head; log_entry_t **log_tail; char *buffer; } log_t; static log_t loglist[LOG_MAXLOGS]; static int _get_log_id(void); static void _release_log_id(int log_id); static void _lock_logger(void); static void _unlock_logger(void); static int _log_open (int id) { if (loglist [id] . in_use == 0) return 0; /* check for cases where an open of the logfile is wanted */ if (loglist [id] . logfile == NULL || (loglist [id] . trigger_level && loglist [id] . size > loglist [id] . trigger_level)) { if (loglist [id] . filename) /* only re-open files where we have a name */ { struct stat st; if (loglist [id] . logfile) { char new_name [4096]; fclose (loglist [id] . logfile); loglist [id] . logfile = NULL; /* simple rename, but could use time providing locking were used */ if (loglist[id].archive_timestamp) { char timestamp [128]; time_t now = time(NULL); strftime (timestamp, sizeof (timestamp), "%Y%m%d_%H%M%S", localtime (&now)); snprintf (new_name, sizeof(new_name), "%s.%s", loglist[id].filename, timestamp); } else { snprintf (new_name, sizeof(new_name), "%s.old", loglist [id] . filename); } #ifdef _WIN32 if (stat (new_name, &st) == 0) remove (new_name); #endif rename (loglist [id] . filename, new_name); } loglist [id] . logfile = fopen (loglist [id] . filename, "a"); if (loglist [id] . logfile == NULL) return 0; setvbuf (loglist [id] . logfile, NULL, IO_BUFFER_TYPE, 0); if (stat (loglist [id] . filename, &st) < 0) loglist [id] . size = 0; else loglist [id] . size = st.st_size; } else loglist [id] . size = 0; } return 1; } void log_initialize(void) { int i; if (_initialized) return; for (i = 0; i < LOG_MAXLOGS; i++) { loglist[i].in_use = 0; loglist[i].level = 2; loglist[i].size = 0; loglist[i].trigger_level = 1000000000; loglist[i].filename = NULL; loglist[i].logfile = NULL; loglist[i].buffer = NULL; loglist[i].total = 0; loglist[i].entries = 0; loglist[i].keep_entries = 0; loglist[i].log_head = NULL; loglist[i].log_tail = &loglist[i].log_head; } /* initialize mutexes */ #ifndef _WIN32 pthread_mutex_init(&_logger_mutex, NULL); #else InitializeCriticalSection(&_logger_mutex); #endif _initialized = 1; } int log_open_file(FILE *file) { int log_id; if(file == NULL) return LOG_EINSANE; log_id = _get_log_id(); if (log_id < 0) return LOG_ENOMORELOGS; loglist[log_id].logfile = file; loglist[log_id].filename = NULL; loglist[log_id].size = 0; return log_id; } int log_open(const char *filename) { int id; FILE *file; if (filename == NULL) return LOG_EINSANE; if (strcmp(filename, "") == 0) return LOG_EINSANE; file = fopen(filename, "a"); id = log_open_file(file); if (id >= 0) { struct stat st; setvbuf (loglist [id] . logfile, NULL, IO_BUFFER_TYPE, 0); loglist [id] . filename = strdup (filename); if (stat (loglist [id] . filename, &st) == 0) loglist [id] . size = st.st_size; loglist [id] . entries = 0; loglist [id] . log_head = NULL; loglist [id] . log_tail = &loglist [id] . log_head; } return id; } /* set the trigger level to trigger, represented in kilobytes */ void log_set_trigger(int id, unsigned trigger) { if (id >= 0 && id < LOG_MAXLOGS && loglist [id] . in_use) { loglist [id] . trigger_level = trigger*1024; } } int log_set_filename(int id, const char *filename) { if (id < 0 || id >= LOG_MAXLOGS) return LOG_EINSANE; /* NULL filename is ok, empty filename is not. */ if ((filename && !strcmp(filename, "")) || loglist [id] . in_use == 0) return LOG_EINSANE; _lock_logger(); if (loglist [id] . filename) free (loglist [id] . filename); if (filename) loglist [id] . filename = strdup (filename); else loglist [id] . filename = NULL; _unlock_logger(); return id; } int log_set_archive_timestamp(int id, int value) { if (id < 0 || id >= LOG_MAXLOGS) return LOG_EINSANE; _lock_logger(); loglist[id].archive_timestamp = value; _unlock_logger(); return id; } int log_open_with_buffer(const char *filename, int size) { /* not implemented */ return LOG_ENOTIMPL; } void log_set_lines_kept (int log_id, unsigned int count) { if (log_id < 0 || log_id >= LOG_MAXLOGS) return; if (loglist[log_id].in_use == 0) return; _lock_logger (); loglist[log_id].keep_entries = count; while (loglist[log_id].entries > count) { log_entry_t *to_go = loglist [log_id].log_head; loglist [log_id].log_head = to_go->next; loglist [log_id].total -= to_go->len; free (to_go->line); free (to_go); loglist [log_id].entries--; } _unlock_logger (); } void log_set_level(int log_id, unsigned level) { if (log_id < 0 || log_id >= LOG_MAXLOGS) return; if (loglist[log_id].in_use == 0) return; loglist[log_id].level = level; } void log_flush(int log_id) { if (log_id < 0 || log_id >= LOG_MAXLOGS) return; if (loglist[log_id].in_use == 0) return; _lock_logger(); if (loglist[log_id].logfile) fflush(loglist[log_id].logfile); _unlock_logger(); } void log_reopen(int log_id) { if (log_id < 0 || log_id >= LOG_MAXLOGS) return; if (loglist [log_id] . filename && loglist [log_id] . logfile) { _lock_logger(); fclose (loglist [log_id] . logfile); loglist [log_id] . logfile = NULL; _unlock_logger(); } } void log_close(int log_id) { if (log_id < 0 || log_id >= LOG_MAXLOGS) return; _lock_logger(); if (loglist[log_id].in_use == 0) { _unlock_logger(); return; } loglist[log_id].in_use = 0; loglist[log_id].level = 2; if (loglist[log_id].filename) free(loglist[log_id].filename); if (loglist[log_id].buffer) free(loglist[log_id].buffer); if (loglist [log_id] . logfile) { fclose (loglist [log_id] . logfile); loglist [log_id] . logfile = NULL; } while (loglist[log_id].entries) { log_entry_t *to_go = loglist [log_id].log_head; loglist [log_id].log_head = to_go->next; loglist [log_id].total -= to_go->len; free (to_go->line); free (to_go); loglist [log_id].entries--; } _unlock_logger(); } void log_shutdown(void) { /* destroy mutexes */ #ifndef _WIN32 pthread_mutex_destroy(&_logger_mutex); #else DeleteCriticalSection(&_logger_mutex); #endif _initialized = 0; } static int create_log_entry (int log_id, const char *pre, const char *line) { log_entry_t *entry; if (loglist[log_id].keep_entries == 0) return fprintf (loglist[log_id].logfile, "%s%s\n", pre, line); entry = calloc (1, sizeof (log_entry_t)); entry->len = strlen (pre) + strlen (line) + 2; entry->line = malloc (entry->len); snprintf (entry->line, entry->len, "%s%s\n", pre, line); loglist [log_id].total += entry->len; fprintf (loglist[log_id].logfile, "%s", entry->line); *loglist [log_id].log_tail = entry; loglist [log_id].log_tail = &entry->next; if (loglist [log_id].entries >= loglist [log_id].keep_entries) { log_entry_t *to_go = loglist [log_id].log_head; loglist [log_id].log_head = to_go->next; loglist [log_id].total -= to_go->len; free (to_go->line); free (to_go); } else loglist [log_id].entries++; return entry->len; } void log_contents (int log_id, char **_contents, unsigned int *_len) { int remain; log_entry_t *entry; char *ptr; if (log_id < 0) return; if (log_id >= LOG_MAXLOGS) return; /* Bad log number */ _lock_logger (); remain = loglist [log_id].total + 1; *_contents = malloc (remain); **_contents= '\0'; *_len = loglist [log_id].total; entry = loglist [log_id].log_head; ptr = *_contents; while (entry) { int len = snprintf (ptr, remain, "%s", entry->line); if (len > 0) { ptr += len; remain -= len; } entry = entry->next; } _unlock_logger (); } static void __vsnprintf(char *str, size_t size, const char *format, va_list ap) { int in_block = 0; int block_size = 0; int block_len; int block_space = 0; const char * arg; char buf[80]; for (; *format && size; format++) { if ( !in_block ) { if ( *format == '%' ) { in_block = 1; block_size = 0; block_len = 0; block_space = 0; } else { *(str++) = *format; size--; } } else { // TODO: %l*[sdupi] as well as %.4080s and "%.*s arg = NULL; switch (*format) { case 'l': block_size++; break; case '.': // just ignore '.'. If somebody cares: fix it. break; case '*': block_len = va_arg(ap, int); break; case ' ': block_space = 1; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': block_len = atoi(format); for (; *format >= '0' && *format <= '9'; format++); format--; break; case 'p': snprintf(buf, sizeof(buf), "%p", (void*)va_arg(ap, void *)); arg = buf; case 'd': case 'i': case 'u': if (!arg) { switch (block_size) { case 0: if (*format == 'u') snprintf(buf, sizeof(buf), "%u", (unsigned int)va_arg(ap, unsigned int)); else snprintf(buf, sizeof(buf), "%i", (int)va_arg(ap, int)); break; case 1: if (*format == 'u') snprintf(buf, sizeof(buf), "%lu", (unsigned long int)va_arg(ap, unsigned long int)); else snprintf(buf, sizeof(buf), "%li", (long int)va_arg(ap, long int)); break; case 2: if (*format == 'u') snprintf(buf, sizeof(buf), "%llu", (unsigned long long int)va_arg(ap, unsigned long long int)); else snprintf(buf, sizeof(buf), "%lli", (long long int)va_arg(ap, long long int)); break; default: snprintf(buf, sizeof(buf), "<<>>"); break; } arg = buf; } case 's': case 'H': // TODO. if (!arg) arg = va_arg(ap, const char *); if (!arg) arg = "(null)"; if (!block_len) block_len = strlen(arg); // the if() is the outer structure so the inner for() // is branch optimized. if (*format == 'H' ) { for (; *arg && block_len && size; arg++, size--, block_len--) { if ((*arg <= '"' || *arg == '`' || *arg == '\\') && !(block_space && *arg == ' ')) *(str++) = '.'; else *(str++) = *arg; } } else { for (; *arg && block_len && size; arg++, size--, block_len--) *(str++) = *arg; } in_block = 0; break; } } } if ( !size ) str--; *str = 0; } void log_write(int log_id, unsigned priority, const char *cat, const char *func, const char *fmt, ...) { static const char *prior[] = { "EROR", "WARN", "INFO", "DBUG" }; int datelen; time_t now; char pre[256]; char line[LOG_MAXLINELEN]; va_list ap; if (log_id < 0 || log_id >= LOG_MAXLOGS) return; /* Bad log number */ if (loglist[log_id].level < priority) return; if (!priority || priority > sizeof(prior)/sizeof(prior[0])) return; /* Bad priority */ va_start(ap, fmt); __vsnprintf(line, sizeof(line), fmt, ap); va_end(ap); now = time(NULL); datelen = strftime (pre, sizeof (pre), "[%Y-%m-%d %H:%M:%S]", localtime(&now)); snprintf (pre+datelen, sizeof (pre)-datelen, " %s %s%s ", prior [priority-1], cat, func); _lock_logger(); if (_log_open (log_id)) { int len = create_log_entry (log_id, pre, line); if (len > 0) loglist[log_id].size += len; } _unlock_logger(); } void log_write_direct(int log_id, const char *fmt, ...) { va_list ap; time_t now; char line[LOG_MAXLINELEN]; if (log_id < 0 || log_id >= LOG_MAXLOGS) return; va_start(ap, fmt); now = time(NULL); _lock_logger(); __vsnprintf(line, LOG_MAXLINELEN, fmt, ap); if (_log_open (log_id)) { int len = create_log_entry (log_id, "", line); if (len > 0) loglist[log_id].size += len; } _unlock_logger(); va_end(ap); fflush(loglist[log_id].logfile); } static int _get_log_id(void) { int i; int id = -1; /* lock mutex */ _lock_logger(); for (i = 0; i < LOG_MAXLOGS; i++) if (loglist[i].in_use == 0) { loglist[i].in_use = 1; id = i; break; } /* unlock mutex */ _unlock_logger(); return id; } static void _release_log_id(int log_id) { /* lock mutex */ _lock_logger(); loglist[log_id].in_use = 0; /* unlock mutex */ _unlock_logger(); } static void _lock_logger(void) { #ifndef _WIN32 pthread_mutex_lock(&_logger_mutex); #else EnterCriticalSection(&_logger_mutex); #endif } static void _unlock_logger(void) { #ifndef _WIN32 pthread_mutex_unlock(&_logger_mutex); #else LeaveCriticalSection(&_logger_mutex); #endif } icecast-2.4.2/src/log/Makefile.in0000664000175000017500000004470312511177306013505 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/log DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libicelog_la_LIBADD = am_libicelog_la_OBJECTS = log.lo libicelog_la_OBJECTS = $(am_libicelog_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libicelog_la_SOURCES) DIST_SOURCES = $(libicelog_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = test.c noinst_LTLIBRARIES = libicelog.la noinst_HEADERS = log.h libicelog_la_SOURCES = log.c AM_CFLAGS = $(XIPH_CFLAGS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/log/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/log/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libicelog.la: $(libicelog_la_OBJECTS) $(libicelog_la_DEPENDENCIES) $(EXTRA_libicelog_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libicelog_la_OBJECTS) $(libicelog_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/format_kate.h0000664000175000017500000000114512511160565013314 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_KATE_H #define __FORMAT_KATE_H #include "format_ogg.h" ogg_codec_t *initial_kate_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_KATE_H */ icecast-2.4.2/src/sighandler.c0000664000175000017500000000323412511160565013134 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H #include #endif #include #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "global.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "logging.h" #include "event.h" #define CATMODULE "sighandler" #ifndef _WIN32 void _sig_hup(int signo); void _sig_die(int signo); void _sig_ignore(int signo); #endif void sighandler_initialize(void) { #ifndef _WIN32 signal(SIGHUP, _sig_hup); signal(SIGINT, _sig_die); signal(SIGTERM, _sig_die); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, _sig_ignore); #endif } #ifndef _WIN32 void _sig_ignore(int signo) { signal(signo, _sig_ignore); } void _sig_hup(int signo) { ICECAST_LOG_INFO("Caught signal %d, scheduling config re-read...", signo); global_lock(); global . schedule_config_reread = 1; global_unlock(); /* some OSes require us to reattach the signal handler */ signal(SIGHUP, _sig_hup); } void _sig_die(int signo) { ICECAST_LOG_INFO("Caught signal %d, shutting down...", signo); /* inform the server to start shutting down */ global.running = ICECAST_HALTING; } #endif icecast-2.4.2/src/timing/0000775000175000017500000000000012511177344012220 500000000000000icecast-2.4.2/src/timing/README0000664000175000017500000000010612511160565013012 00000000000000this is the timing library. lgpl by jack moffitt icecast-2.4.2/src/timing/Makefile.am0000664000175000017500000000052712511160565014175 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO noinst_LTLIBRARIES = libicetiming.la noinst_HEADERS = timing.h libicetiming_la_SOURCES = timing.c libicetiming_la_CFLAGS = @XIPH_CFLAGS@ debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" icecast-2.4.2/src/timing/TODO0000664000175000017500000000001112511160565012615 00000000000000 nothing icecast-2.4.2/src/timing/timing.h0000664000175000017500000000132712511160565013600 00000000000000/* ** Timing functions. ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. */ #ifndef __TIMING_H__ #define __TIMING_H__ #include #ifdef HAVE_INTTYPES_H #include #elif defined(HAVE_STDINT_H) #include #endif #if defined(_WIN32) && !defined(int64_t) typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #endif /* config.h should be included before we are to define _mangle */ #ifdef _mangle # define timing_get_time _mangle(timing_get_time) # define timing_sleep _mangle(timing_sleep) #endif uint64_t timing_get_time(void); void timing_sleep(uint64_t sleeptime); #endif /* __TIMING_H__ */ icecast-2.4.2/src/timing/Makefile.in0000664000175000017500000004751412511177306014216 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/timing DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) COPYING README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libicetiming_la_LIBADD = am_libicetiming_la_OBJECTS = libicetiming_la-timing.lo libicetiming_la_OBJECTS = $(am_libicetiming_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libicetiming_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libicetiming_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libicetiming_la_SOURCES) DIST_SOURCES = $(libicetiming_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO noinst_LTLIBRARIES = libicetiming.la noinst_HEADERS = timing.h libicetiming_la_SOURCES = timing.c libicetiming_la_CFLAGS = @XIPH_CFLAGS@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/timing/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/timing/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libicetiming.la: $(libicetiming_la_OBJECTS) $(libicetiming_la_DEPENDENCIES) $(EXTRA_libicetiming_la_DEPENDENCIES) $(AM_V_CCLD)$(libicetiming_la_LINK) $(libicetiming_la_OBJECTS) $(libicetiming_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libicetiming_la-timing.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libicetiming_la-timing.lo: timing.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicetiming_la_CFLAGS) $(CFLAGS) -MT libicetiming_la-timing.lo -MD -MP -MF $(DEPDIR)/libicetiming_la-timing.Tpo -c -o libicetiming_la-timing.lo `test -f 'timing.c' || echo '$(srcdir)/'`timing.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libicetiming_la-timing.Tpo $(DEPDIR)/libicetiming_la-timing.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timing.c' object='libicetiming_la-timing.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicetiming_la_CFLAGS) $(CFLAGS) -c -o libicetiming_la-timing.lo `test -f 'timing.c' || echo '$(srcdir)/'`timing.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/timing/BUILDING0000664000175000017500000000010212511160565013246 00000000000000defines that affect compilation none library dependencies none icecast-2.4.2/src/timing/timing.c0000664000175000017500000000303612511160565013572 00000000000000/* timing.c ** - Timing functions ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #ifdef _WIN32 #include #include #else #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_TIMEB_H #include #endif #include "timing.h" /* see timing.h for an explanation of _mangle() */ /* * Returns milliseconds no matter what. */ uint64_t timing_get_time(void) { #ifdef HAVE_GETTIMEOFDAY struct timeval mtv; gettimeofday(&mtv, NULL); return (uint64_t)(mtv.tv_sec) * 1000 + (uint64_t)(mtv.tv_usec) / 1000; #elif HAVE_FTIME struct timeb t; ftime(&t); return t.time * 1000 + t.millitm; #else #error need time query handler #endif } void timing_sleep(uint64_t sleeptime) { struct timeval sleeper; sleeper.tv_sec = sleeptime / 1000; sleeper.tv_usec = (sleeptime % 1000) * 1000; /* NOTE: * This should be 0 for the first argument. The linux manpage * says so. The solaris manpage also says this is a legal * value. If you think differerntly, please provide references. */ #ifdef WIN32 Sleep(sleeptime); #else select(1, NULL, NULL, NULL, &sleeper); #endif } icecast-2.4.2/src/timing/COPYING0000664000175000017500000006127312511160565013201 00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! icecast-2.4.2/src/cfgfile.h0000664000175000017500000001501212511160565012415 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * Michael Smith , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011, Dave 'justdave' Miller . * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , */ #ifndef __CFGFILE_H__ #define __CFGFILE_H__ #define CONFIG_EINSANE -1 #define CONFIG_ENOROOT -2 #define CONFIG_EBADROOT -3 #define CONFIG_EPARSE -4 #define MAX_YP_DIRECTORIES 25 struct _mount_proxy; #include "thread/thread.h" #include "avl/avl.h" #include "auth.h" #include "global.h" #include "connection.h" #define XMLSTR(str) ((xmlChar *)(str)) typedef enum _http_header_type { /* static: headers are passed as is to the client. */ HTTP_HEADER_TYPE_STATIC } http_header_type; typedef struct ice_config_http_header_tag { /* type of this header. See http_header_type */ http_header_type type; /* name and value of the header */ char *name; char *value; /* filters */ int status; /* link to the next list element */ struct ice_config_http_header_tag *next; } ice_config_http_header_t; typedef struct ice_config_dir_tag { char *host; int touch_interval; struct ice_config_dir_tag *next; } ice_config_dir_t; typedef struct _config_options { char *name; char *value; struct _config_options *next; } config_options_t; typedef enum _mount_type { MOUNT_TYPE_NORMAL, MOUNT_TYPE_DEFAULT } mount_type; typedef struct _mount_proxy { char *mountname; /* The mountpoint this proxy is used for */ mount_type mounttype; /* The type of the mount point */ char *username; /* Username and password for this mountpoint. If unset, */ char *password; /* falls back to global source password */ char *dumpfile; /* Filename to dump this stream to (will be appended). NULL to not dump. */ char *intro_filename; /* Send contents of file to client before the stream */ int fallback_when_full; /* switch new listener to fallback source when max listeners reached */ int max_listeners; /* Max listeners for this mountpoint only. -1 to not limit here (i.e. only use the global limit) */ char *fallback_mount; /* Fallback mountname */ int fallback_override; /* When this source arrives, do we steal back clients from the fallback? */ int no_mount; /* Do we permit direct requests of this mountpoint? (or only indirect, through fallbacks) */ int burst_size; /* amount to send to a new client if possible, -1 take * from global setting */ unsigned int queue_size_limit; int hidden; /* Do we list this on the xsl pages */ unsigned int source_timeout; /* source timeout in seconds */ char *charset; /* character set if not utf8 */ int mp3_meta_interval; /* outgoing per-stream metadata interval */ ice_config_http_header_t *http_headers; /* additional HTTP headers */ char *auth_type; /* Authentication type */ struct auth_tag *auth; char *cluster_password; config_options_t *auth_options; /* Options for this type */ char *on_connect; char *on_disconnect; unsigned int max_listener_duration; char *stream_name; char *stream_description; char *stream_url; char *stream_genre; char *bitrate; char *type; char *subtype; int yp_public; struct _mount_proxy *next; } mount_proxy; typedef struct _aliases { char *source; char *destination; int port; char *bind_address; struct _aliases *next; } aliases; typedef struct _listener_t { struct _listener_t *next; int port; int so_sndbuf; char *bind_address; int shoutcast_compat; char *shoutcast_mount; int ssl; } listener_t; typedef struct ice_config_tag { char *config_filename; char *location; char *admin; int client_limit; int source_limit; unsigned int queue_size_limit; int threadpool_size; unsigned int burst_size; int client_timeout; int header_timeout; int source_timeout; int ice_login; int fileserve; int on_demand; /* global setting for all relays */ char *shoutcast_mount; char *source_password; char *admin_username; char *admin_password; char *relay_username; char *relay_password; int touch_interval; ice_config_dir_t *dir_list; char *hostname; int port; char *mimetypes_fn; listener_t *listen_sock; unsigned int listen_sock_count; char *master_server; int master_server_port; int master_update_interval; char *master_username; char *master_password; ice_config_http_header_t *http_headers; relay_server *relay; mount_proxy *mounts; char *server_id; char *base_dir; char *log_dir; char *pidfile; char *banfile; char *allowfile; char *cert_file; char *cipher_list; char *webroot_dir; char *adminroot_dir; aliases *aliases; char *access_log; char *error_log; char *playlist_log; int loglevel; int logsize; int logarchive; int chroot; int chuid; char *user; char *group; char *yp_url[MAX_YP_DIRECTORIES]; int yp_url_timeout[MAX_YP_DIRECTORIES]; int yp_touch_interval[MAX_YP_DIRECTORIES]; int num_yp_directories; } ice_config_t; typedef struct { rwlock_t config_lock; mutex_t relay_lock; } ice_config_locks; void config_initialize(void); void config_shutdown(void); int config_parse_file(const char *filename, ice_config_t *configuration); int config_initial_parse_file(const char *filename); int config_parse_cmdline(int arg, char **argv); void config_set_config(ice_config_t *config); listener_t *config_clear_listener (listener_t *listener); void config_clear(ice_config_t *config); mount_proxy *config_find_mount (ice_config_t *config, const char *mount, mount_type type); listener_t *config_get_listen_sock (ice_config_t *config, connection_t *con); int config_rehash(void); ice_config_locks *config_locks(void); ice_config_t *config_get_config(void); ice_config_t *config_grab_config(void); void config_release_config(void); /* To be used ONLY in one-time startup code */ ice_config_t *config_get_config_unlocked(void); #endif /* __CFGFILE_H__ */ icecast-2.4.2/src/client.c0000664000175000017500000001701612511160565012275 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft , */ /* client.c ** ** client interface implementation ** */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "cfgfile.h" #include "connection.h" #include "refbuf.h" #include "format.h" #include "stats.h" #include "fserve.h" #include "client.h" #include "logging.h" #include "util.h" #ifdef _WIN32 #define snprintf _snprintf #endif #undef CATMODULE #define CATMODULE "client" /* create a client_t with the provided connection and parser details. Return * 0 on success, -1 if server limit has been reached. In either case a * client_t is returned just in case a message needs to be returned. Should * be called with global lock held. */ int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser) { ice_config_t *config; client_t *client = (client_t *)calloc(1, sizeof(client_t)); int ret = -1; if (client == NULL) abort(); config = config_get_config (); global.clients++; if (config->client_limit < global.clients) ICECAST_LOG_WARN("server client limit reached (%d/%d)", config->client_limit, global.clients); else ret = 0; config_release_config (); stats_event_args (NULL, "clients", "%d", global.clients); client->con = con; client->parser = parser; client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); client->refbuf->len = 0; /* force reader code to ignore buffer contents */ client->pos = 0; client->write_to_client = format_generic_write_to_client; *c_ptr = client; return ret; } void client_destroy(client_t *client) { if (client == NULL) return; /* release the buffer now, as the buffer could be on the source queue * and may of disappeared after auth completes */ if (client->refbuf) { refbuf_release (client->refbuf); client->refbuf = NULL; } if (auth_release_listener (client)) return; /* write log entry if ip is set (some things don't set it, like outgoing * slave requests */ if (client->respcode && client->parser) logging_access(client); if (client->con) connection_close(client->con); if (client->parser) httpp_destroy(client->parser); global_lock (); global.clients--; stats_event_args (NULL, "clients", "%d", global.clients); global_unlock (); /* we need to free client specific format data (if any) */ if (client->free_client_data) client->free_client_data (client); free(client->username); free(client->password); free(client); } /* return -1 for failed, 0 for authenticated, 1 for pending */ int client_check_source_auth (client_t *client, const char *mount) { ice_config_t *config = config_get_config(); char *pass = config->source_password; char *user = "source"; int ret = -1; mount_proxy *mountinfo = config_find_mount (config, mount, MOUNT_TYPE_NORMAL); do { if (mountinfo) { ret = 1; if (auth_stream_authenticate (client, mount, mountinfo) > 0) break; ret = -1; if (mountinfo->password) pass = mountinfo->password; if (mountinfo->username) user = mountinfo->username; } if (connection_check_pass (client->parser, user, pass) > 0) ret = 0; } while (0); config_release_config(); return ret; } /* helper function for reading data from a client */ int client_read_bytes (client_t *client, void *buf, unsigned len) { int bytes; if (client->refbuf && client->refbuf->len) { /* we have data to read from a refbuf first */ if (client->refbuf->len < len) len = client->refbuf->len; memcpy (buf, client->refbuf->data, len); if (len < client->refbuf->len) { char *ptr = client->refbuf->data; memmove (ptr, ptr+len, client->refbuf->len - len); } client->refbuf->len -= len; return len; } bytes = client->con->read (client->con, buf, len); if (bytes == -1 && client->con->error) ICECAST_LOG_DEBUG("reading from connection has failed"); return bytes; } static void client_send_error(client_t *client, int status, int plain, const char *message) { ssize_t ret; ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, status, NULL, plain ? "text/plain" : "text/html", "utf-8", plain ? message : "", NULL); if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); return; } if (!plain) snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Error %i%i - %s\r\n", status, status, message); client->respcode = status; client->refbuf->len = strlen (client->refbuf->data); fserve_add_client (client, NULL); } void client_send_100(client_t *client) { /* On demand inject a HTTP/1.1 100 Continue to make sure clients are happy */ sock_write (client->con->sock, "HTTP/1.1 100 Continue\r\n\r\n"); } void client_send_400(client_t *client, const char *message) { client_send_error(client, 400, 0, message); } void client_send_404(client_t *client, const char *message) { client_send_error(client, 404, 0, message); } void client_send_401(client_t *client) { client_send_error(client, 401, 1, "You need to authenticate\r\n"); } void client_send_403(client_t *client, const char *message) { client_send_error(client, 403, 1, message); } /* this function is designed to work even if client is in bad state */ void client_send_500(client_t *client, const char *message) { const char header[] = "HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n" "500 - Internal Server Error\n---------------------------\n"; const size_t header_len = sizeof(header) - 1; int ret; ret = client_send_bytes(client, header, header_len); /* only send message if we have one AND if header could have transmitted completly */ if (message && ret == header_len) client_send_bytes(client, message, strlen(message)); client_destroy(client); } /* helper function for sending the data to a client */ int client_send_bytes (client_t *client, const void *buf, unsigned len) { int ret = client->con->send (client->con, buf, len); if (client->con->error) ICECAST_LOG_DEBUG("Client connection died"); return ret; } void client_set_queue (client_t *client, refbuf_t *refbuf) { refbuf_t *to_release = client->refbuf; client->refbuf = refbuf; if (refbuf) refbuf_addref (client->refbuf); client->pos = 0; if (to_release) refbuf_release (to_release); } icecast-2.4.2/src/auth_url.h0000664000175000017500000000114612511160565012644 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __AUTH_URL_H__ #define __AUTH_URL_H__ #ifdef HAVE_CONFIG_H #include #endif int auth_get_url_auth (auth_t *authenticator, config_options_t *options); #endif icecast-2.4.2/src/Makefile.am0000664000175000017500000000260112511160565012701 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign SUBDIRS = avl thread httpp net log timing bin_PROGRAMS = icecast noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \ global.h util.h slave.h source.h stats.h refbuf.h client.h \ compat.h fserve.h xslt.h yp.h event.h md5.h \ auth.h auth_htpasswd.h auth_url.h \ format.h format_ogg.h format_mp3.h format_ebml.h \ format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \ format_kate.h format_skeleton.h format_opus.h icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \ util.c slave.c source.c stats.c refbuf.c client.c \ xslt.c fserve.c event.c admin.c md5.c \ format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \ auth.c auth_htpasswd.c format_kate.c format_skeleton.c format_opus.c EXTRA_icecast_SOURCES = yp.c \ auth_url.c \ format_vorbis.c format_theora.c format_speex.c icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \ httpp/libicehttpp.la log/libicelog.la avl/libiceavl.la timing/libicetiming.la icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@ @KATE_LIBS@ AM_CFLAGS = @XIPH_CFLAGS@ AM_CPPFLAGS = @XIPH_CPPFLAGS@ AM_LDFLAGS = @XIPH_LDFLAGS@ @KATE_LIBS@ debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" icecast-2.4.2/src/httpp/0000775000175000017500000000000012511177344012070 500000000000000icecast-2.4.2/src/httpp/httpp.h0000664000175000017500000000504712511160565013323 00000000000000/* httpp.h ** ** http parsing library ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. */ #ifndef __HTTPP_H #define __HTTPP_H #include #define HTTPP_VAR_PROTOCOL "__protocol" #define HTTPP_VAR_VERSION "__version" #define HTTPP_VAR_URI "__uri" #define HTTPP_VAR_RAWURI "__rawuri" #define HTTPP_VAR_QUERYARGS " __queryargs" #define HTTPP_VAR_REQ_TYPE "__req_type" #define HTTPP_VAR_ERROR_MESSAGE "__errormessage" #define HTTPP_VAR_ERROR_CODE "__errorcode" #define HTTPP_VAR_ICYPASSWORD "__icy_password" typedef enum httpp_request_type_tag { httpp_req_none, httpp_req_get, httpp_req_post, httpp_req_put, httpp_req_head, httpp_req_source, httpp_req_play, httpp_req_stats, httpp_req_unknown } httpp_request_type_e; typedef struct http_var_tag { char *name; char *value; } http_var_t; typedef struct http_varlist_tag { http_var_t var; struct http_varlist_tag *next; } http_varlist_t; typedef struct http_parser_tag { httpp_request_type_e req_type; char *uri; avl_tree *vars; avl_tree *queryvars; } http_parser_t; #ifdef _mangle # define httpp_create_parser _mangle(httpp_create_parser) # define httpp_initialize _mangle(httpp_initialize) # define httpp_parse _mangle(httpp_parse) # define httpp_parse_icy _mangle(httpp_parse_icy) # define httpp_parse_response _mangle(httpp_parse_response) # define httpp_setvar _mangle(httpp_setvar) # define httpp_getvar _mangle(httpp_getvar) # define httpp_set_query_param _mangle(httpp_set_query_param) # define httpp_get_query_param _mangle(httpp_get_query_param) # define httpp_destroy _mangle(httpp_destroy) # define httpp_clear _mangle(httpp_clear) #endif http_parser_t *httpp_create_parser(void); void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults); int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len); int httpp_parse_icy(http_parser_t *parser, const char *http_data, unsigned long len); int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned long len, const char *uri); void httpp_setvar(http_parser_t *parser, const char *name, const char *value); void httpp_deletevar(http_parser_t *parser, const char *name); const char *httpp_getvar(http_parser_t *parser, const char *name); void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value); const char *httpp_get_query_param(http_parser_t *parser, const char *name); void httpp_destroy(http_parser_t *parser); void httpp_clear(http_parser_t *parser); #endif icecast-2.4.2/src/httpp/README0000664000175000017500000000014312511160565012663 00000000000000httpp is a simple http parser licensed under the lgpl created by jack moffitt icecast-2.4.2/src/httpp/Makefile.am0000664000175000017500000000061112511160565014037 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign noinst_LTLIBRARIES = libicehttpp.la noinst_HEADERS = httpp.h libicehttpp_la_SOURCES = httpp.c libicehttpp_la_CFLAGS = @XIPH_CFLAGS@ AM_CPPFLAGS = @XIPH_CPPFLAGS@ INCLUDES = -I$(srcdir)/.. # SCCS stuff (for BitKeeper) GET = true debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" icecast-2.4.2/src/httpp/TODO0000664000175000017500000000003112511160565012467 00000000000000- nothing i can think of icecast-2.4.2/src/httpp/Makefile.in0000664000175000017500000004752012511177306014063 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/httpp DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) COPYING README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libicehttpp_la_LIBADD = am_libicehttpp_la_OBJECTS = libicehttpp_la-httpp.lo libicehttpp_la_OBJECTS = $(am_libicehttpp_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libicehttpp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libicehttpp_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o \ $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libicehttpp_la_SOURCES) DIST_SOURCES = $(libicehttpp_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign noinst_LTLIBRARIES = libicehttpp.la noinst_HEADERS = httpp.h libicehttpp_la_SOURCES = httpp.c libicehttpp_la_CFLAGS = @XIPH_CFLAGS@ AM_CPPFLAGS = @XIPH_CPPFLAGS@ INCLUDES = -I$(srcdir)/.. # SCCS stuff (for BitKeeper) GET = true all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/httpp/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/httpp/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libicehttpp.la: $(libicehttpp_la_OBJECTS) $(libicehttpp_la_DEPENDENCIES) $(EXTRA_libicehttpp_la_DEPENDENCIES) $(AM_V_CCLD)$(libicehttpp_la_LINK) $(libicehttpp_la_OBJECTS) $(libicehttpp_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libicehttpp_la-httpp.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libicehttpp_la-httpp.lo: httpp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicehttpp_la_CFLAGS) $(CFLAGS) -MT libicehttpp_la-httpp.lo -MD -MP -MF $(DEPDIR)/libicehttpp_la-httpp.Tpo -c -o libicehttpp_la-httpp.lo `test -f 'httpp.c' || echo '$(srcdir)/'`httpp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libicehttpp_la-httpp.Tpo $(DEPDIR)/libicehttpp_la-httpp.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpp.c' object='libicehttpp_la-httpp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicehttpp_la_CFLAGS) $(CFLAGS) -c -o libicehttpp_la-httpp.lo `test -f 'httpp.c' || echo '$(srcdir)/'`httpp.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/httpp/httpp.c0000664000175000017500000003250712511160565013317 00000000000000/* Httpp.c ** ** http parsing engine ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include #include "httpp.h" #if defined(_WIN32) && !defined(HAVE_STRCASECMP) #define strcasecmp stricmp #endif #define MAX_HEADERS 32 /* internal functions */ /* misc */ static char *_lowercase(char *str); /* for avl trees */ static int _compare_vars(void *compare_arg, void *a, void *b); static int _free_vars(void *key); http_parser_t *httpp_create_parser(void) { return (http_parser_t *)malloc(sizeof(http_parser_t)); } void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults) { http_varlist_t *list; parser->req_type = httpp_req_none; parser->uri = NULL; parser->vars = avl_tree_new(_compare_vars, NULL); parser->queryvars = avl_tree_new(_compare_vars, NULL); /* now insert the default variables */ list = defaults; while (list != NULL) { httpp_setvar(parser, list->var.name, list->var.value); list = list->next; } } static int split_headers(char *data, unsigned long len, char **line) { /* first we count how many lines there are ** and set up the line[] array */ int lines = 0; unsigned long i; line[lines] = data; for (i = 0; i < len && lines < MAX_HEADERS; i++) { if (data[i] == '\r') data[i] = '\0'; if (data[i] == '\n') { lines++; data[i] = '\0'; if (lines >= MAX_HEADERS) return MAX_HEADERS; if (i + 1 < len) { if (data[i + 1] == '\n' || data[i + 1] == '\r') break; line[lines] = &data[i + 1]; } } } i++; while (i < len && data[i] == '\n') i++; return lines; } static void parse_headers(http_parser_t *parser, char **line, int lines) { int i, l; int whitespace, slen; char *name = NULL; char *value = NULL; /* parse the name: value lines. */ for (l = 1; l < lines; l++) { whitespace = 0; name = line[l]; value = NULL; slen = strlen(line[l]); for (i = 0; i < slen; i++) { if (line[l][i] == ':') { whitespace = 1; line[l][i] = '\0'; } else { if (whitespace) { whitespace = 0; while (i < slen && line[l][i] == ' ') i++; if (i < slen) value = &line[l][i]; break; } } } if (name != NULL && value != NULL) { httpp_setvar(parser, _lowercase(name), value); name = NULL; value = NULL; } } } int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned long len, const char *uri) { char *data; char *line[MAX_HEADERS]; int lines, slen,i, whitespace=0, where=0,code; char *version=NULL, *resp_code=NULL, *message=NULL; if(http_data == NULL) return 0; /* make a local copy of the data, including 0 terminator */ data = (char *)malloc(len+1); if (data == NULL) return 0; memcpy(data, http_data, len); data[len] = 0; lines = split_headers(data, len, line); /* In this case, the first line contains: * VERSION RESPONSE_CODE MESSAGE, such as HTTP/1.0 200 OK */ slen = strlen(line[0]); version = line[0]; for(i=0; i < slen; i++) { if(line[0][i] == ' ') { line[0][i] = 0; whitespace = 1; } else if(whitespace) { whitespace = 0; where++; if(where == 1) resp_code = &line[0][i]; else { message = &line[0][i]; break; } } } if(version == NULL || resp_code == NULL || message == NULL) { free(data); return 0; } httpp_setvar(parser, HTTPP_VAR_ERROR_CODE, resp_code); code = atoi(resp_code); if(code < 200 || code >= 300) { httpp_setvar(parser, HTTPP_VAR_ERROR_MESSAGE, message); } httpp_setvar(parser, HTTPP_VAR_URI, uri); httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "NONE"); parse_headers(parser, line, lines); free(data); return 1; } static int hex(char c) { if(c >= '0' && c <= '9') return c - '0'; else if(c >= 'A' && c <= 'F') return c - 'A' + 10; else if(c >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; } static char *url_escape(const char *src) { int len = strlen(src); unsigned char *decoded; int i; char *dst; int done = 0; decoded = calloc(1, len + 1); dst = (char *)decoded; for(i=0; i < len; i++) { switch(src[i]) { case '%': if(i+2 >= len) { free(decoded); return NULL; } if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) { free(decoded); return NULL; } *dst++ = hex(src[i+1]) * 16 + hex(src[i+2]); i+= 2; break; case '+': *dst++ = ' '; break; case '#': done = 1; break; case 0: free(decoded); return NULL; break; default: *dst++ = src[i]; break; } if(done) break; } *dst = 0; /* null terminator */ return (char *)decoded; } /** TODO: This is almost certainly buggy in some cases */ static void parse_query(http_parser_t *parser, char *query) { int len; int i=0; char *key = query; char *val=NULL; if(!query || !*query) return; len = strlen(query); while(ireq_type = httpp_req_get; } else if (strcasecmp("POST", req_type) == 0) { parser->req_type = httpp_req_post; } else if (strcasecmp("PUT", req_type) == 0) { parser->req_type = httpp_req_put; } else if (strcasecmp("HEAD", req_type) == 0) { parser->req_type = httpp_req_head; } else if (strcasecmp("SOURCE", req_type) == 0) { parser->req_type = httpp_req_source; } else if (strcasecmp("PLAY", req_type) == 0) { parser->req_type = httpp_req_play; } else if (strcasecmp("STATS", req_type) == 0) { parser->req_type = httpp_req_stats; } else { parser->req_type = httpp_req_unknown; } if (uri != NULL && strlen(uri) > 0) { char *query; if((query = strchr(uri, '?')) != NULL) { httpp_setvar(parser, HTTPP_VAR_RAWURI, uri); httpp_setvar(parser, HTTPP_VAR_QUERYARGS, query); *query = 0; query++; parse_query(parser, query); } parser->uri = strdup(uri); } else { free(data); return 0; } if ((version != NULL) && ((tmp = strchr(version, '/')) != NULL)) { tmp[0] = '\0'; if ((strlen(version) > 0) && (strlen(&tmp[1]) > 0)) { httpp_setvar(parser, HTTPP_VAR_PROTOCOL, version); httpp_setvar(parser, HTTPP_VAR_VERSION, &tmp[1]); } else { free(data); return 0; } } else { free(data); return 0; } if (parser->req_type != httpp_req_none && parser->req_type != httpp_req_unknown) { switch (parser->req_type) { case httpp_req_get: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "GET"); break; case httpp_req_post: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "POST"); break; case httpp_req_put: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PUT"); break; case httpp_req_head: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "HEAD"); break; case httpp_req_source: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "SOURCE"); break; case httpp_req_play: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "PLAY"); break; case httpp_req_stats: httpp_setvar(parser, HTTPP_VAR_REQ_TYPE, "STATS"); break; default: break; } } else { free(data); return 0; } if (parser->uri != NULL) { httpp_setvar(parser, HTTPP_VAR_URI, parser->uri); } else { free(data); return 0; } parse_headers(parser, line, lines); free(data); return 1; } void httpp_deletevar(http_parser_t *parser, const char *name) { http_var_t var; if (parser == NULL || name == NULL) return; var.name = (char*)name; var.value = NULL; avl_delete(parser->vars, (void *)&var, _free_vars); } void httpp_setvar(http_parser_t *parser, const char *name, const char *value) { http_var_t *var; if (name == NULL || value == NULL) return; var = (http_var_t *)malloc(sizeof(http_var_t)); if (var == NULL) return; var->name = strdup(name); var->value = strdup(value); if (httpp_getvar(parser, name) == NULL) { avl_insert(parser->vars, (void *)var); } else { avl_delete(parser->vars, (void *)var, _free_vars); avl_insert(parser->vars, (void *)var); } } const char *httpp_getvar(http_parser_t *parser, const char *name) { http_var_t var; http_var_t *found; void *fp; if (parser == NULL || name == NULL) return NULL; fp = &found; var.name = (char*)name; var.value = NULL; if (avl_get_by_key(parser->vars, &var, fp) == 0) return found->value; else return NULL; } void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value) { http_var_t *var; if (name == NULL || value == NULL) return; var = (http_var_t *)malloc(sizeof(http_var_t)); if (var == NULL) return; var->name = strdup(name); var->value = url_escape(value); if (httpp_get_query_param(parser, name) == NULL) { avl_insert(parser->queryvars, (void *)var); } else { avl_delete(parser->queryvars, (void *)var, _free_vars); avl_insert(parser->queryvars, (void *)var); } } const char *httpp_get_query_param(http_parser_t *parser, const char *name) { http_var_t var; http_var_t *found; void *fp; fp = &found; var.name = (char *)name; var.value = NULL; if (avl_get_by_key(parser->queryvars, (void *)&var, fp) == 0) return found->value; else return NULL; } void httpp_clear(http_parser_t *parser) { parser->req_type = httpp_req_none; if (parser->uri) free(parser->uri); parser->uri = NULL; avl_tree_free(parser->vars, _free_vars); avl_tree_free(parser->queryvars, _free_vars); parser->vars = NULL; } void httpp_destroy(http_parser_t *parser) { httpp_clear(parser); free(parser); } static char *_lowercase(char *str) { char *p = str; for (; *p != '\0'; p++) *p = tolower(*p); return str; } static int _compare_vars(void *compare_arg, void *a, void *b) { http_var_t *vara, *varb; vara = (http_var_t *)a; varb = (http_var_t *)b; return strcmp(vara->name, varb->name); } static int _free_vars(void *key) { http_var_t *var; var = (http_var_t *)key; if (var->name) free(var->name); if (var->value) free(var->value); free(var); return 1; } icecast-2.4.2/src/httpp/COPYING0000664000175000017500000006127312511160565013051 00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! icecast-2.4.2/src/TODO0000664000175000017500000000014612510726173011341 00000000000000need a shutdown function in case anything else in the code needs to have icecast gracefully shutdown. icecast-2.4.2/src/format_theora.c0000664000175000017500000001301712511160565013646 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for theora logical streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct source_tag source_t; #include "refbuf.h" #include "format_ogg.h" #include "format_theora.h" #include "client.h" #include "stats.h" #define CATMODULE "format-theora" #include "logging.h" typedef struct _theora_codec_tag { theora_info ti; theora_comment tc; int granule_shift; ogg_int64_t last_iframe; ogg_int64_t prev_granulepos; } theora_codec_t; static void theora_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { theora_codec_t *theora = codec->specific; ICECAST_LOG_DEBUG("freeing theora codec"); stats_event (ogg_info->mount, "video_bitrate", NULL); stats_event (ogg_info->mount, "video_quality", NULL); stats_event (ogg_info->mount, "frame_rate", NULL); stats_event (ogg_info->mount, "frame_size", NULL); theora_info_clear (&theora->ti); theora_comment_clear (&theora->tc); ogg_stream_clear (&codec->os); free (theora); free (codec); } /* theora pages are not rebuilt, so here we just for headers and then * pass them straight through to the the queue */ static refbuf_t *process_theora_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { theora_codec_t *theora = codec->specific; ogg_packet packet; int header_page = 0; int has_keyframe = 0; refbuf_t *refbuf = NULL; ogg_int64_t granulepos; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } granulepos = ogg_page_granulepos (page); while (ogg_stream_packetout (&codec->os, &packet) > 0) { if (theora_packet_isheader (&packet)) { if (theora_decode_header (&theora->ti, &theora->tc, &packet) < 0) { ogg_info->error = 1; ICECAST_LOG_WARN("problem with theora header"); return NULL; } header_page = 1; codec->headers++; if (codec->headers == 3) { ogg_info->bitrate += theora->ti.target_bitrate; stats_event_args (ogg_info->mount, "video_bitrate", "%ld", (long)theora->ti.target_bitrate); stats_event_args (ogg_info->mount, "video_quality", "%ld", (long)theora->ti.quality); stats_event_args (ogg_info->mount, "frame_size", "%ld x %ld", (long)theora->ti.frame_width, (long)theora->ti.frame_height); stats_event_args (ogg_info->mount, "frame_rate", "%.2f", (float)theora->ti.fps_numerator/theora->ti.fps_denominator); } continue; } if (codec->headers < 3) { ogg_info->error = 1; ICECAST_LOG_ERROR("Not enough header packets"); return NULL; } if (theora_packet_iskeyframe (&packet)) has_keyframe = 1; } if (header_page) { format_ogg_attach_header (ogg_info, page); return NULL; } refbuf = make_refbuf_with_page (page); /* ICECAST_LOG_DEBUG("refbuf %p has pageno %ld, %llu", refbuf, ogg_page_pageno (page), (uint64_t)granulepos); */ if (granulepos != theora->prev_granulepos || granulepos == 0) { if (codec->possible_start) refbuf_release (codec->possible_start); refbuf_addref (refbuf); codec->possible_start = refbuf; } theora->prev_granulepos = granulepos; if (has_keyframe && codec->possible_start) { codec->possible_start->sync_point = 1; refbuf_release (codec->possible_start); codec->possible_start = NULL; } return refbuf; } /* Check if specified BOS page is the start of a theora stream and * if so, create a codec structure for handling it */ ogg_codec_t *initial_theora_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; theora_codec_t *theora_codec = calloc (1, sizeof (theora_codec_t)); ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); theora_info_init (&theora_codec->ti); theora_comment_init (&theora_codec->tc); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for theora codec"); if (theora_decode_header (&theora_codec->ti, &theora_codec->tc, &packet) < 0) { theora_info_clear (&theora_codec->ti); theora_comment_clear (&theora_codec->tc); ogg_stream_clear (&codec->os); free (theora_codec); free (codec); return NULL; } ICECAST_LOG_INFO("seen initial theora header"); codec->specific = theora_codec; codec->process_page = process_theora_page; codec->codec_free = theora_codec_free; codec->headers = 1; codec->name = "Theora"; format_ogg_attach_header (ogg_info, page); ogg_info->codec_sync = codec; return codec; } icecast-2.4.2/src/connection.c0000664000175000017500000012522212511160565013155 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011, Philipp "ph3-der-loewe" Schafft , * Dave 'justdave' Miller . */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_POLL #include #endif #include #include #ifndef _WIN32 #include #include #else #include #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp #endif #include "compat.h" #include "thread/thread.h" #include "avl/avl.h" #include "net/sock.h" #include "httpp/httpp.h" #include "cfgfile.h" #include "global.h" #include "util.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "stats.h" #include "logging.h" #include "xslt.h" #include "fserve.h" #include "sighandler.h" #include "yp.h" #include "source.h" #include "format.h" #include "format_mp3.h" #include "event.h" #include "admin.h" #include "auth.h" #define CATMODULE "connection" /* Two different major types of source authentication. Shoutcast style is used only by the Shoutcast DSP and is a crazy version of HTTP. It looks like : Source Client -> Connects to port + 1 Source Client -> sends encoder password (plaintext)\r\n Icecast -> reads encoder password, if ok, sends OK2\r\n, else disconnects Source Client -> reads OK2\r\n, then sends http-type request headers that contain the stream details (icy-name, etc..) Icecast -> reads headers, stores them Source Client -> starts sending MP3 data Source Client -> periodically updates metadata via admin.cgi call Icecast auth style uses HTTP and Basic Authorization. */ #define SHOUTCAST_SOURCE_AUTH 1 #define ICECAST_SOURCE_AUTH 0 typedef struct client_queue_tag { client_t *client; int offset; int stream_offset; int shoutcast; char *shoutcast_mount; struct client_queue_tag *next; } client_queue_t; typedef struct _thread_queue_tag { thread_type *thread_id; struct _thread_queue_tag *next; } thread_queue_t; typedef struct { char *filename; time_t file_recheck; time_t file_mtime; avl_tree *contents; } cache_file_contents; static spin_t _connection_lock; // protects _current_id, _con_queue, _con_queue_tail static volatile unsigned long _current_id = 0; static int _initialized = 0; static volatile client_queue_t *_req_queue = NULL, **_req_queue_tail = &_req_queue; static volatile client_queue_t *_con_queue = NULL, **_con_queue_tail = &_con_queue; static int ssl_ok; #ifdef HAVE_OPENSSL static SSL_CTX *ssl_ctx; #endif /* filtering client connection based on IP */ static cache_file_contents banned_ip, allowed_ip; rwlock_t _source_shutdown_rwlock; static void _handle_connection(void); static int compare_ip (void *arg, void *a, void *b) { const char *ip = (const char *)a; const char *pattern = (const char *)b; return strcmp (pattern, ip); } static int free_filtered_ip (void*x) { free (x); return 1; } void connection_initialize(void) { if (_initialized) return; thread_spin_create (&_connection_lock); thread_mutex_create(&move_clients_mutex); thread_rwlock_create(&_source_shutdown_rwlock); thread_cond_create(&global.shutdown_cond); _req_queue = NULL; _req_queue_tail = &_req_queue; _con_queue = NULL; _con_queue_tail = &_con_queue; banned_ip.contents = NULL; banned_ip.file_mtime = 0; allowed_ip.contents = NULL; allowed_ip.file_mtime = 0; _initialized = 1; } void connection_shutdown(void) { if (!_initialized) return; #ifdef HAVE_OPENSSL SSL_CTX_free (ssl_ctx); #endif if (banned_ip.contents) avl_tree_free (banned_ip.contents, free_filtered_ip); if (allowed_ip.contents) avl_tree_free (allowed_ip.contents, free_filtered_ip); thread_cond_destroy(&global.shutdown_cond); thread_rwlock_destroy(&_source_shutdown_rwlock); thread_spin_destroy (&_connection_lock); thread_mutex_destroy(&move_clients_mutex); _initialized = 0; } static unsigned long _next_connection_id(void) { unsigned long id; thread_spin_lock (&_connection_lock); id = _current_id++; thread_spin_unlock (&_connection_lock); return id; } #ifdef HAVE_OPENSSL static void get_ssl_certificate (ice_config_t *config) { SSL_METHOD *method; long ssl_opts; ssl_ok = 0; SSL_load_error_strings(); /* readable error messages */ SSL_library_init(); /* initialize library */ method = SSLv23_server_method(); ssl_ctx = SSL_CTX_new (method); ssl_opts = SSL_CTX_get_options (ssl_ctx); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION); #else SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3); #endif do { if (config->cert_file == NULL) break; if (SSL_CTX_use_certificate_chain_file (ssl_ctx, config->cert_file) <= 0) { ICECAST_LOG_WARN("Invalid cert file %s", config->cert_file); break; } if (SSL_CTX_use_PrivateKey_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0) { ICECAST_LOG_WARN("Invalid private key file %s", config->cert_file); break; } if (!SSL_CTX_check_private_key (ssl_ctx)) { ICECAST_LOG_ERROR("Invalid %s - Private key does not match cert public key", config->cert_file); break; } if (SSL_CTX_set_cipher_list(ssl_ctx, config->cipher_list) <= 0) { ICECAST_LOG_WARN("Invalid cipher list: %s", config->cipher_list); } ssl_ok = 1; ICECAST_LOG_INFO("SSL certificate found at %s", config->cert_file); ICECAST_LOG_INFO("SSL using ciphers %s", config->cipher_list); return; } while (0); ICECAST_LOG_INFO("No SSL capability on any configured ports"); } /* handlers for reading and writing a connection_t when there is ssl * configured on the listening port */ static int connection_read_ssl (connection_t *con, void *buf, size_t len) { int bytes = SSL_read (con->ssl, buf, len); if (bytes < 0) { switch (SSL_get_error (con->ssl, bytes)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return -1; } con->error = 1; } return bytes; } static int connection_send_ssl (connection_t *con, const void *buf, size_t len) { int bytes = SSL_write (con->ssl, buf, len); if (bytes < 0) { switch (SSL_get_error (con->ssl, bytes)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return -1; } con->error = 1; } else con->sent_bytes += bytes; return bytes; } #else /* SSL not compiled in, so at least log it */ static void get_ssl_certificate (ice_config_t *config) { ssl_ok = 0; ICECAST_LOG_INFO("No SSL capability"); } #endif /* HAVE_OPENSSL */ /* handlers (default) for reading and writing a connection_t, no encrpytion * used just straight access to the socket */ static int connection_read (connection_t *con, void *buf, size_t len) { int bytes = sock_read_bytes (con->sock, buf, len); if (bytes == 0) con->error = 1; if (bytes == -1 && !sock_recoverable (sock_error())) con->error = 1; return bytes; } static int connection_send (connection_t *con, const void *buf, size_t len) { int bytes = sock_write_bytes (con->sock, buf, len); if (bytes < 0) { if (!sock_recoverable (sock_error())) con->error = 1; } else con->sent_bytes += bytes; return bytes; } /* function to handle the re-populating of the avl tree containing IP addresses * for deciding whether a connection of an incoming request is to be dropped. */ static void recheck_ip_file (cache_file_contents *cache) { time_t now = time(NULL); if (now >= cache->file_recheck) { struct stat file_stat; FILE *file = NULL; int count = 0; avl_tree *new_ips; char line [MAX_LINE_LEN]; cache->file_recheck = now + 10; if (cache->filename == NULL) { if (cache->contents) { avl_tree_free (cache->contents, free_filtered_ip); cache->contents = NULL; } return; } if (stat (cache->filename, &file_stat) < 0) { ICECAST_LOG_WARN("failed to check status of \"%s\": %s", cache->filename, strerror(errno)); return; } if (file_stat.st_mtime == cache->file_mtime) return; /* common case, no update to file */ cache->file_mtime = file_stat.st_mtime; file = fopen (cache->filename, "r"); if (file == NULL) { ICECAST_LOG_WARN("Failed to open file \"%s\": %s", cache->filename, strerror (errno)); return; } new_ips = avl_tree_new (compare_ip, NULL); while (get_line (file, line, MAX_LINE_LEN)) { char *str; if(!line[0] || line[0] == '#') continue; count++; str = strdup (line); if (str) avl_insert (new_ips, str); } fclose (file); ICECAST_LOG_INFO("%d entries read from file \"%s\"", count, cache->filename); if (cache->contents) avl_tree_free (cache->contents, free_filtered_ip); cache->contents = new_ips; } } /* return 0 if the passed ip address is not to be handled by icecast, non-zero otherwise */ static int accept_ip_address (char *ip) { void *result; recheck_ip_file (&banned_ip); recheck_ip_file (&allowed_ip); if (banned_ip.contents) { if (avl_get_by_key (banned_ip.contents, ip, &result) == 0) { ICECAST_LOG_DEBUG("%s is banned", ip); return 0; } } if (allowed_ip.contents) { if (avl_get_by_key (allowed_ip.contents, ip, &result) == 0) { ICECAST_LOG_DEBUG("%s is allowed", ip); return 1; } else { ICECAST_LOG_DEBUG("%s is not allowed", ip); return 0; } } return 1; } connection_t *connection_create (sock_t sock, sock_t serversock, char *ip) { connection_t *con; con = (connection_t *)calloc(1, sizeof(connection_t)); if (con) { con->sock = sock; con->serversock = serversock; con->con_time = time(NULL); con->id = _next_connection_id(); con->ip = ip; con->read = connection_read; con->send = connection_send; } return con; } /* prepare connection for interacting over a SSL connection */ void connection_uses_ssl (connection_t *con) { #ifdef HAVE_OPENSSL con->read = connection_read_ssl; con->send = connection_send_ssl; con->ssl = SSL_new (ssl_ctx); SSL_set_accept_state (con->ssl); SSL_set_fd (con->ssl, con->sock); #endif } static sock_t wait_for_serversock(int timeout) { #ifdef HAVE_POLL struct pollfd ufds [global.server_sockets]; int i, ret; for(i=0; i < global.server_sockets; i++) { ufds[i].fd = global.serversock[i]; ufds[i].events = POLLIN; ufds[i].revents = 0; } ret = poll(ufds, global.server_sockets, timeout); if(ret < 0) { return SOCK_ERROR; } else if(ret == 0) { return SOCK_ERROR; } else { int dst; for(i=0; i < global.server_sockets; i++) { if(ufds[i].revents & POLLIN) return ufds[i].fd; if(ufds[i].revents & (POLLHUP|POLLERR|POLLNVAL)) { if (ufds[i].revents & (POLLHUP|POLLERR)) { sock_close (global.serversock[i]); ICECAST_LOG_WARN("Had to close a listening socket"); } global.serversock[i] = SOCK_ERROR; } } /* remove any closed sockets */ for(i=0, dst=0; i < global.server_sockets; i++) { if (global.serversock[i] == SOCK_ERROR) continue; if (i!=dst) global.serversock[dst] = global.serversock[i]; dst++; } global.server_sockets = dst; return SOCK_ERROR; } #else fd_set rfds; struct timeval tv, *p=NULL; int i, ret; sock_t max = SOCK_ERROR; FD_ZERO(&rfds); for(i=0; i < global.server_sockets; i++) { FD_SET(global.serversock[i], &rfds); if (max == SOCK_ERROR || global.serversock[i] > max) max = global.serversock[i]; } if(timeout >= 0) { tv.tv_sec = timeout/1000; tv.tv_usec = (timeout % 1000) * 1000; p = &tv; } ret = select(max+1, &rfds, NULL, NULL, p); if(ret < 0) { return SOCK_ERROR; } else if(ret == 0) { return SOCK_ERROR; } else { for(i=0; i < global.server_sockets; i++) { if(FD_ISSET(global.serversock[i], &rfds)) return global.serversock[i]; } return SOCK_ERROR; /* Should be impossible, stop compiler warnings */ } #endif } static connection_t *_accept_connection(int duration) { sock_t sock, serversock; char *ip; serversock = wait_for_serversock (duration); if (serversock == SOCK_ERROR) return NULL; /* malloc enough room for a full IP address (including ipv6) */ ip = (char *)malloc(MAX_ADDR_LEN); sock = sock_accept(serversock, ip, MAX_ADDR_LEN); if (sock != SOCK_ERROR) { connection_t *con = NULL; /* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */ if (strncmp (ip, "::ffff:", 7) == 0) memmove (ip, ip+7, strlen (ip+7)+1); if (accept_ip_address (ip)) con = connection_create (sock, serversock, ip); if (con) return con; sock_close (sock); } else { if (!sock_recoverable(sock_error())) { ICECAST_LOG_WARN("accept() failed with error %d: %s", sock_error(), strerror(sock_error())); thread_sleep (500000); } } free(ip); return NULL; } /* add client to connection queue. At this point some header information * has been collected, so we now pass it onto the connection thread for * further processing */ static void _add_connection (client_queue_t *node) { thread_spin_lock (&_connection_lock); *_con_queue_tail = node; _con_queue_tail = (volatile client_queue_t **)&node->next; thread_spin_unlock (&_connection_lock); } /* this returns queued clients for the connection thread. headers are * already provided, but need to be parsed. */ static client_queue_t *_get_connection(void) { client_queue_t *node = NULL; thread_spin_lock (&_connection_lock); if (_con_queue) { node = (client_queue_t *)_con_queue; _con_queue = node->next; if (_con_queue == NULL) _con_queue_tail = &_con_queue; node->next = NULL; } thread_spin_unlock (&_connection_lock); return node; } /* run along queue checking for any data that has come in or a timeout */ static void process_request_queue (void) { client_queue_t **node_ref = (client_queue_t **)&_req_queue; ice_config_t *config = config_get_config (); int timeout = config->header_timeout; config_release_config(); while (*node_ref) { client_queue_t *node = *node_ref; client_t *client = node->client; int len = PER_CLIENT_REFBUF_SIZE - 1 - node->offset; char *buf = client->refbuf->data + node->offset; if (len > 0) { if (client->con->con_time + timeout <= time(NULL)) len = 0; else len = client_read_bytes (client, buf, len); } if (len > 0) { int pass_it = 1; char *ptr; /* handle \n, \r\n and nsvcap which for some strange reason has * EOL as \r\r\n */ node->offset += len; client->refbuf->data [node->offset] = '\000'; do { if (node->shoutcast == 1) { /* password line */ if (strstr (client->refbuf->data, "\r\r\n") != NULL) break; if (strstr (client->refbuf->data, "\r\n") != NULL) break; if (strstr (client->refbuf->data, "\n") != NULL) break; } /* stream_offset refers to the start of any data sent after the * http style headers, we don't want to lose those */ ptr = strstr (client->refbuf->data, "\r\r\n\r\r\n"); if (ptr) { node->stream_offset = (ptr+6) - client->refbuf->data; break; } ptr = strstr (client->refbuf->data, "\r\n\r\n"); if (ptr) { node->stream_offset = (ptr+4) - client->refbuf->data; break; } ptr = strstr (client->refbuf->data, "\n\n"); if (ptr) { node->stream_offset = (ptr+2) - client->refbuf->data; break; } pass_it = 0; } while (0); if (pass_it) { if ((client_queue_t **)_req_queue_tail == &(node->next)) _req_queue_tail = (volatile client_queue_t **)node_ref; *node_ref = node->next; node->next = NULL; _add_connection (node); continue; } } else { if (len == 0 || client->con->error) { if ((client_queue_t **)_req_queue_tail == &node->next) _req_queue_tail = (volatile client_queue_t **)node_ref; *node_ref = node->next; client_destroy (client); free (node); continue; } } node_ref = &node->next; } _handle_connection(); } /* add node to the queue of requests. This is where the clients are when * initial http details are read. */ static void _add_request_queue (client_queue_t *node) { *_req_queue_tail = node; _req_queue_tail = (volatile client_queue_t **)&node->next; } 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 == ICECAST_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(); ICECAST_LOG_WARN("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); } /* Called when activating a source. Verifies that the source count is not * exceeded and applies any initial parameters. */ int connection_complete_source (source_t *source, int response) { ice_config_t *config; global_lock (); ICECAST_LOG_DEBUG("sources count is %d", global.sources); config = config_get_config(); if (global.sources < config->source_limit) { const char *contenttype; const char *expectcontinue; mount_proxy *mountinfo; format_type_t format_type; /* setup format handler */ contenttype = httpp_getvar (source->parser, "content-type"); if (contenttype != NULL) { format_type = format_get_type (contenttype); if (format_type == FORMAT_ERROR) { config_release_config(); global_unlock(); if (response) { client_send_403 (source->client, "Content-type not supported"); source->client = NULL; } ICECAST_LOG_WARN("Content-type \"%s\" not supported, dropping source", contenttype); return -1; } } else if (source->parser->req_type == httpp_req_put) { config_release_config(); global_unlock(); if (response) { client_send_403 (source->client, "No Content-type given"); source->client = NULL; } ICECAST_LOG_ERROR("Content-type not given in PUT request, dropping source"); return -1; } else { ICECAST_LOG_ERROR("No content-type header, falling back to backwards compatibility mode " "for icecast 1.x relays. Assuming content is mp3. This behaviour is deprecated " "and the source client will NOT work with future Icecast versions!"); format_type = FORMAT_TYPE_GENERIC; } if (format_get_plugin (format_type, source) < 0) { global_unlock(); config_release_config(); if (response) { client_send_403 (source->client, "internal format allocation problem"); source->client = NULL; } ICECAST_LOG_WARN("plugin format failed for \"%s\"", source->mount); return -1; } /* For PUT support we check for 100-continue and send back a 100 to stay in spec */ expectcontinue = httpp_getvar (source->parser, "expect"); if (expectcontinue != NULL) { #ifdef HAVE_STRCASESTR if (strcasestr (expectcontinue, "100-continue") != NULL) #else ICECAST_LOG_WARN("OS doesn't support case insenestive substring checks..."); if (strstr (expectcontinue, "100-continue") != NULL) #endif { client_send_100 (source->client); } } global.sources++; stats_event_args (NULL, "sources", "%d", global.sources); global_unlock(); source->running = 1; mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL); source_update_settings (config, source, mountinfo); config_release_config(); slave_rebuild_mounts(); source->shutdown_rwlock = &_source_shutdown_rwlock; ICECAST_LOG_DEBUG("source is ready to start"); return 0; } ICECAST_LOG_WARN("Request to add source when maximum source limit " "reached %d", global.sources); global_unlock(); config_release_config(); if (response) { client_send_403 (source->client, "too many sources connected"); source->client = NULL; } return -1; } static int _check_pass_http(http_parser_t *parser, const char *correctuser, const char *correctpass) { /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */ const char *header = httpp_getvar(parser, "authorization"); char *userpass, *tmp; char *username, *password; if(header == NULL) return 0; if(strncmp(header, "Basic ", 6)) return 0; userpass = util_base64_decode(header+6); if(userpass == NULL) { ICECAST_LOG_WARN("Base64 decode of Authorization header \"%s\" failed", header+6); return 0; } tmp = strchr(userpass, ':'); if(!tmp) { free(userpass); return 0; } *tmp = 0; username = userpass; password = tmp+1; if(strcmp(username, correctuser) || strcmp(password, correctpass)) { free(userpass); return 0; } free(userpass); return 1; } static int _check_pass_icy(http_parser_t *parser, const char *correctpass) { const char *password; password = httpp_getvar(parser, HTTPP_VAR_ICYPASSWORD); if(!password) return 0; if (strcmp(password, correctpass)) return 0; else return 1; } static int _check_pass_ice(http_parser_t *parser, const char *correctpass) { const char *password; password = httpp_getvar(parser, "ice-password"); if(!password) password = ""; if (strcmp(password, correctpass)) return 0; else return 1; } int connection_check_admin_pass(http_parser_t *parser) { int ret; ice_config_t *config = config_get_config(); char *pass = config->admin_password; char *user = config->admin_username; const char *protocol; if(!pass || !user) { config_release_config(); return 0; } protocol = httpp_getvar (parser, HTTPP_VAR_PROTOCOL); if (protocol && strcmp (protocol, "ICY") == 0) ret = _check_pass_icy (parser, pass); else ret = _check_pass_http (parser, user, pass); config_release_config(); return ret; } int connection_check_relay_pass(http_parser_t *parser) { int ret; ice_config_t *config = config_get_config(); char *pass = config->relay_password; char *user = config->relay_username; if(!pass || !user) { config_release_config(); return 0; } ret = _check_pass_http(parser, user, pass); config_release_config(); return ret; } /* return 0 for failed, 1 for ok */ int connection_check_pass (http_parser_t *parser, const char *user, const char *pass) { int ret; const char *protocol; if(!pass) { ICECAST_LOG_WARN("No source password set, rejecting source"); return -1; } protocol = httpp_getvar(parser, HTTPP_VAR_PROTOCOL); if(protocol != NULL && !strcmp(protocol, "ICY")) { ret = _check_pass_icy(parser, pass); } else { ret = _check_pass_http(parser, user, pass); if (!ret) { ice_config_t *config = config_get_config_unlocked(); if (config->ice_login) { ret = _check_pass_ice(parser, pass); if(ret) ICECAST_LOG_WARN("Source is using deprecated icecast login"); } } } return ret; } /* only called for native icecast source clients */ static void _handle_source_request (client_t *client, const char *uri) { ICECAST_LOG_INFO("Source logging in at mountpoint \"%s\" from %s", uri, client->con->ip); if (uri[0] != '/') { ICECAST_LOG_WARN("source mountpoint not starting with /"); client_send_401 (client); return; } switch (client_check_source_auth (client, uri)) { case 0: /* authenticated from config file */ source_startup (client, uri, ICECAST_SOURCE_AUTH); break; case 1: /* auth pending */ break; default: /* failed */ ICECAST_LOG_INFO("Source (%s) attempted to login with invalid or missing password", uri); client_send_401(client); break; } } void source_startup (client_t *client, const char *uri, int auth_style) { source_t *source; source = source_reserve (uri); if (source) { source->client = client; source->parser = client->parser; source->con = client->con; if (connection_complete_source (source, 1) < 0) { source_clear_source (source); source_free_source (source); return; } client->respcode = 200; if (auth_style == SHOUTCAST_SOURCE_AUTH) { source->shoutcast_compat = 1; source_client_callback (client, source); } else { refbuf_t *ok = refbuf_new (PER_CLIENT_REFBUF_SIZE); client->respcode = 200; snprintf (ok->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\n\r\n"); ok->len = strlen (ok->data); /* we may have unprocessed data read in, so don't overwrite it */ ok->associated = client->refbuf; client->refbuf = ok; fserve_add_client_callback (client, source_client_callback, source); } } else { client_send_403 (client, "Mountpoint in use"); ICECAST_LOG_WARN("Mountpoint %s in use", uri); } } static void _handle_stats_request (client_t *client, char *uri) { stats_event_inc(NULL, "stats_connections"); if (connection_check_admin_pass (client->parser) == 0) { client_send_401 (client); ICECAST_LOG_ERROR("Bad password for stats connection"); return; } client->respcode = 200; snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 200 OK\r\n\r\n"); client->refbuf->len = strlen (client->refbuf->data); fserve_add_client_callback (client, stats_callback, NULL); } static void _handle_get_request (client_t *client, char *passed_uri) { char *serverhost = NULL; int serverport = 0; aliases *alias; ice_config_t *config; char *uri = passed_uri; listener_t *listen_sock; config = config_get_config(); listen_sock = config_get_listen_sock (config, client->con); if (listen_sock) { serverhost = listen_sock->bind_address; serverport = listen_sock->port; } alias = config->aliases; /* there are several types of HTTP GET clients ** media clients, which are looking for a source (eg, URI = /stream.ogg) ** stats clients, which are looking for /admin/stats.xml ** and directory server authorizers, which are looking for /GUID-xxxxxxxx ** (where xxxxxx is the GUID in question) - this isn't implemented yet. ** we need to handle the latter two before the former, as the latter two ** aren't subject to the limits. */ /* TODO: add GUID-xxxxxx */ /* Handle aliases */ while(alias) { if(strcmp(uri, alias->source) == 0 && (alias->port == -1 || alias->port == serverport) && (alias->bind_address == NULL || (serverhost != NULL && strcmp(alias->bind_address, serverhost) == 0))) { uri = strdup (alias->destination); ICECAST_LOG_DEBUG("alias has made %s into %s", passed_uri, uri); break; } alias = alias->next; } config_release_config(); stats_event_inc(NULL, "client_connections"); /* Dispatch all admin requests */ if ((strcmp(uri, "/admin.cgi") == 0) || (strncmp(uri, "/admin/", 7) == 0)) { admin_handle_request(client, uri); if (uri != passed_uri) free (uri); return; } auth_add_listener (uri, client); if (uri != passed_uri) free (uri); } 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 ICECAST_LOG_INFO("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; } /* Connection thread. Here we take clients off the connection queue and check * the contents provided. We set up the parser then hand off to the specific * request handler. */ static void _handle_connection(void) { http_parser_t *parser; const char *rawuri; client_queue_t *node; while (1) { node = _get_connection(); if (node) { client_t *client = node->client; /* Check for special shoutcast compatability processing */ if (node->shoutcast) { _handle_shoutcast_compatible (node); continue; } /* process normal HTTP headers */ parser = httpp_create_parser(); httpp_initialize(parser, NULL); client->parser = parser; if (httpp_parse (parser, client->refbuf->data, node->offset)) { char *uri; /* 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); } rawuri = httpp_getvar(parser, HTTPP_VAR_URI); /* assign a port-based shoutcast mountpoint if required */ if (node->shoutcast_mount && strcmp (rawuri, "/admin.cgi") == 0) httpp_set_query_param (client->parser, "mount", node->shoutcast_mount); free (node->shoutcast_mount); free (node); if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) { ICECAST_LOG_ERROR("Bad HTTP protocol detected"); client_destroy (client); continue; } uri = util_normalise_uri(rawuri); if (uri == NULL) { client_destroy (client); continue; } if (parser->req_type == httpp_req_source || parser->req_type == httpp_req_put) { _handle_source_request (client, uri); } else if (parser->req_type == httpp_req_stats) { _handle_stats_request (client, uri); } else if (parser->req_type == httpp_req_get) { _handle_get_request (client, uri); } else { ICECAST_LOG_ERROR("Wrong request type from client"); client_send_400 (client, "unknown request"); } free(uri); } else { free (node); ICECAST_LOG_ERROR("HTTP request parsing failed"); client_destroy (client); } continue; } break; } } /* called when listening thread is not checking for incoming connections */ int connection_setup_sockets (ice_config_t *config) { int count = 0; listener_t *listener, **prev; free (banned_ip.filename); banned_ip.filename = NULL; free (allowed_ip.filename); allowed_ip.filename = NULL; global_lock(); if (global.serversock) { for (; count < global.server_sockets; count++) sock_close (global.serversock [count]); free (global.serversock); global.serversock = NULL; } if (config == NULL) { global_unlock(); return 0; } /* setup the banned/allowed IP filenames from the xml */ if (config->banfile) banned_ip.filename = strdup (config->banfile); if (config->allowfile) allowed_ip.filename = strdup (config->allowfile); count = 0; global.serversock = calloc (config->listen_sock_count, sizeof (sock_t)); listener = config->listen_sock; prev = &config->listen_sock; while (listener) { int successful = 0; do { sock_t sock = sock_get_server_socket (listener->port, listener->bind_address); if (sock == SOCK_ERROR) break; if (sock_listen (sock, ICECAST_LISTEN_QUEUE) == SOCK_ERROR) { sock_close (sock); break; } /* some win32 setups do not do TCP win scaling well, so allow an override */ if (listener->so_sndbuf) sock_set_send_buffer (sock, listener->so_sndbuf); sock_set_blocking (sock, 0); successful = 1; global.serversock [count] = sock; count++; } while(0); if (successful == 0) { if (listener->bind_address) ICECAST_LOG_ERROR("Could not create listener socket on port %d bind %s", listener->port, listener->bind_address); else ICECAST_LOG_ERROR("Could not create listener socket on port %d", listener->port); /* remove failed connection */ *prev = config_clear_listener (listener); listener = *prev; continue; } if (listener->bind_address) ICECAST_LOG_INFO("listener socket on port %d address %s", listener->port, listener->bind_address); else ICECAST_LOG_INFO("listener socket on port %d", listener->port); prev = &listener->next; listener = listener->next; } global.server_sockets = count; global_unlock(); if (count == 0) ICECAST_LOG_ERROR("No listening sockets established"); return count; } void connection_close(connection_t *con) { sock_close(con->sock); if (con->ip) free(con->ip); if (con->host) free(con->host); #ifdef HAVE_OPENSSL if (con->ssl) { SSL_shutdown (con->ssl); SSL_free (con->ssl); } #endif free(con); } icecast-2.4.2/src/format_kate.c0000664000175000017500000001542512511160565013315 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for kate logical streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifdef HAVE_KATE #include #endif typedef struct source_tag source_t; #include "refbuf.h" #include "format_ogg.h" #include "format_kate.h" #include "client.h" #include "stats.h" #define CATMODULE "format-kate" #include "logging.h" typedef struct _kate_codec_tag { int headers_done; #ifdef HAVE_KATE kate_info ki; kate_comment kc; #endif int num_headers; int granule_shift; ogg_int64_t last_iframe; ogg_int64_t prev_granulepos; } kate_codec_t; static void kate_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { kate_codec_t *kate = codec->specific; ICECAST_LOG_DEBUG("freeing kate codec"); /* TODO: should i replace with something or just remove stats_event (ogg_info->mount, "video_bitrate", NULL); stats_event (ogg_info->mount, "video_quality", NULL); stats_event (ogg_info->mount, "frame_rate", NULL); stats_event (ogg_info->mount, "frame_size", NULL); */ #ifdef HAVE_KATE kate_info_clear (&kate->ki); kate_comment_clear (&kate->kc); #endif ogg_stream_clear (&codec->os); free (kate); free (codec); } /* kate pages are not rebuilt, so here we just for headers and then * pass them straight through to the the queue */ static refbuf_t *process_kate_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { kate_codec_t *kate = codec->specific; ogg_packet packet; int header_page = 0; refbuf_t *refbuf = NULL; ogg_int64_t granulepos; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } granulepos = ogg_page_granulepos (page); while (ogg_stream_packetout (&codec->os, &packet) > 0) { if (!kate->headers_done) { #ifdef HAVE_KATE int ret = kate_ogg_decode_headerin (&kate->ki, &kate->kc, &packet); if (ret < 0) { ogg_info->error = 1; ICECAST_LOG_WARN("problem with kate header"); return NULL; } header_page = 1; kate->num_headers = kate->ki.num_headers; codec->headers++; if (ret > 0) { kate->headers_done = 1; /* TODO: what to replace this with ? ogg_info->bitrate += theora->ti.target_bitrate; stats_event_args (ogg_info->mount, "video_bitrate", "%ld", (long)theora->ti.target_bitrate); stats_event_args (ogg_info->mount, "video_quality", "%ld", (long)theora->ti.quality); stats_event_args (ogg_info->mount, "frame_size", "%ld x %ld", (long)theora->ti.frame_width, (long)theora->ti.frame_height); stats_event_args (ogg_info->mount, "frame_rate", "%.2f", (float)theora->ti.fps_numerator/theora->ti.fps_denominator); */ } continue; #else header_page = (packet.bytes>0 && (packet.packet[0]&0x80)); if (!header_page) break; codec->headers++; if (packet.packet[0]==0x80) { if (packet.bytes<64) return NULL; /* we peek for the number of headers to expect */ kate->num_headers = packet.packet[11]; } continue; #endif } if (codec->headers < kate->num_headers) { ogg_info->error = 1; ICECAST_LOG_ERROR("Not enough header packets"); return NULL; } } if (header_page) { format_ogg_attach_header (ogg_info, page); return NULL; } refbuf = make_refbuf_with_page (page); /* ICECAST_LOG_DEBUG("refbuf %p has pageno %ld, %llu", refbuf, ogg_page_pageno (page), (uint64_t)granulepos); */ if (codec->possible_start) { /* we don't bother trying to know where we can start, we'll just start whenever we have to, video's more important and in the majority of the cases it's ok if we lose an event we're seeking in the middle of, as we won't have display artifacts as we'd have with video */ codec->possible_start->sync_point = 1; refbuf_release (codec->possible_start); codec->possible_start = NULL; } if (granulepos != kate->prev_granulepos || granulepos == 0) { if (codec->possible_start) refbuf_release (codec->possible_start); refbuf_addref (refbuf); codec->possible_start = refbuf; } kate->prev_granulepos = granulepos; return refbuf; } /* Check if specified BOS page is the start of a kate stream and * if so, create a codec structure for handling it */ ogg_codec_t *initial_kate_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; kate_codec_t *kate_codec = calloc (1, sizeof (kate_codec_t)); ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); #ifdef HAVE_KATE kate_info_init (&kate_codec->ki); kate_comment_init (&kate_codec->kc); #endif ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for kate codec"); #ifdef HAVE_KATE if (kate_ogg_decode_headerin (&kate_codec->ki, &kate_codec->kc, &packet) < 0) { kate_info_clear (&kate_codec->ki); kate_comment_clear (&kate_codec->kc); ogg_stream_clear (&codec->os); free (kate_codec); free (codec); return NULL; } #else /* we don't have libkate, so we examine the packet magic by hand */ if ((packet.bytes<9) || memcmp(packet.packet, "\x80kate\0\0\0\0", 9)) { ogg_stream_clear (&codec->os); free (kate_codec); free (codec); return NULL; } #endif ICECAST_LOG_INFO("seen initial kate header"); codec->specific = kate_codec; codec->process_page = process_kate_page; codec->codec_free = kate_codec_free; codec->headers = 1; codec->name = "Kate"; format_ogg_attach_header (ogg_info, page); ogg_info->codec_sync = codec; return codec; } icecast-2.4.2/src/format_opus.h0000664000175000017500000000106012511160565013352 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, * version 2. A copy of this license is included with this source. * At your option, this specific source file can also be distributed * under the GNU GPL version 3. * * Copyright 2012, David Richards, Mozilla Foundation, * and others (see AUTHORS for details). */ #ifndef __FORMAT_OPUS_H #define __FORMAT_OPUS_H #include "format_ogg.h" ogg_codec_t *initial_opus_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_OPUS_H */ icecast-2.4.2/src/format.c0000664000175000017500000003024612511160565012307 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* -*- c-basic-offset: 4; -*- */ /* format.c ** ** format plugin implementation ** */ #ifdef HAVE_CONFIG_H #include #endif #include #include #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include "connection.h" #include "refbuf.h" #include "source.h" #include "format.h" #include "global.h" #include "httpp/httpp.h" #include "format_ogg.h" #include "format_mp3.h" #include "format_ebml.h" #include "logging.h" #include "stats.h" #define CATMODULE "format" #ifdef WIN32 #define strcasecmp stricmp #define strncasecmp strnicmp #define snprintf _snprintf #endif static int format_prepare_headers (source_t *source, client_t *client); format_type_t format_get_type (const char *contenttype) { if(strcmp(contenttype, "application/x-ogg") == 0) return FORMAT_TYPE_OGG; /* Backwards compatibility */ else if(strcmp(contenttype, "application/ogg") == 0) return FORMAT_TYPE_OGG; /* Now blessed by IANA */ else if(strcmp(contenttype, "audio/ogg") == 0) return FORMAT_TYPE_OGG; else if(strcmp(contenttype, "video/ogg") == 0) return FORMAT_TYPE_OGG; else if(strcmp(contenttype, "audio/webm") == 0) return FORMAT_TYPE_EBML; else if(strcmp(contenttype, "video/webm") == 0) return FORMAT_TYPE_EBML; else if(strcmp(contenttype, "audio/x-matroska") == 0) return FORMAT_TYPE_EBML; else if(strcmp(contenttype, "video/x-matroska") == 0) return FORMAT_TYPE_EBML; else if(strcmp(contenttype, "video/x-matroska-3d") == 0) return FORMAT_TYPE_EBML; else /* We default to the Generic format handler, which can handle many more formats than just mp3. Let's warn that this is not well supported */ ICECAST_LOG_WARN("Unsupported or legacy stream type: \"%s\". Falling back to generic minimal handler for best effort.", contenttype); return FORMAT_TYPE_GENERIC; } int format_get_plugin(format_type_t type, source_t *source) { int ret = -1; switch (type) { case FORMAT_TYPE_OGG: ret = format_ogg_get_plugin (source); break; case FORMAT_TYPE_EBML: ret = format_ebml_get_plugin (source); break; case FORMAT_TYPE_GENERIC: ret = format_mp3_get_plugin (source); break; default: break; } if (ret < 0) stats_event (source->mount, "content-type", source->format->contenttype); return ret; } /* clients need to be start from somewhere in the queue so we will look for * a refbuf which has been previously marked as a sync point. */ static void find_client_start (source_t *source, client_t *client) { refbuf_t *refbuf = source->burst_point; /* we only want to attempt a burst at connection time, not midstream * however streams like theora may not have the most recent page marked as * a starting point, so look for one from the burst point */ if (client->intro_offset == -1 && source->stream_data_tail && source->stream_data_tail->sync_point) refbuf = source->stream_data_tail; else { size_t size = client->intro_offset; refbuf = source->burst_point; while (size > 0 && refbuf && refbuf->next) { size -= refbuf->len; refbuf = refbuf->next; } } while (refbuf) { if (refbuf->sync_point) { client_set_queue (client, refbuf); client->check_buffer = format_advance_queue; client->write_to_client = source->format->write_buf_to_client; client->intro_offset = -1; break; } refbuf = refbuf->next; } } static int get_file_data (FILE *intro, client_t *client) { refbuf_t *refbuf = client->refbuf; size_t bytes; if (intro == NULL || fseek (intro, client->intro_offset, SEEK_SET) < 0) return 0; bytes = fread (refbuf->data, 1, 4096, intro); if (bytes == 0) return 0; refbuf->len = (unsigned int)bytes; return 1; } /* call to check the buffer contents for file reading. move the client * to right place in the queue at end of file else repeat file if queue * is not ready yet. */ int format_check_file_buffer (source_t *source, client_t *client) { refbuf_t *refbuf = client->refbuf; if (refbuf == NULL) { /* client refers to no data, must be from a move */ if (source->client) { find_client_start (source, client); return -1; } /* source -> file fallback, need a refbuf for data */ refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE); client->refbuf = refbuf; client->pos = refbuf->len; client->intro_offset = 0; } if (client->pos == refbuf->len) { if (get_file_data (source->intro_file, client)) { client->pos = 0; client->intro_offset += refbuf->len; } else { if (source->stream_data_tail) { /* better find the right place in queue for this client */ client_set_queue (client, NULL); find_client_start (source, client); } else client->intro_offset = 0; /* replay intro file */ return -1; } } return 0; } /* call this to verify that the HTTP data has been sent and if so setup * callbacks to the appropriate format functions */ int format_check_http_buffer (source_t *source, client_t *client) { refbuf_t *refbuf = client->refbuf; if (refbuf == NULL) return -1; if (client->respcode == 0) { ICECAST_LOG_DEBUG("processing pending client headers"); if (format_prepare_headers (source, client) < 0) { ICECAST_LOG_ERROR("internal problem, dropping client"); client->con->error = 1; return -1; } client->respcode = 200; stats_event_inc (NULL, "listeners"); stats_event_inc (NULL, "listener_connections"); stats_event_inc (source->mount, "listener_connections"); } if (client->pos == refbuf->len) { client->write_to_client = source->format->write_buf_to_client; client->check_buffer = format_check_file_buffer; client->intro_offset = 0; client->pos = refbuf->len = 4096; return -1; } return 0; } int format_generic_write_to_client (client_t *client) { refbuf_t *refbuf = client->refbuf; int ret; const char *buf = refbuf->data + client->pos; unsigned int len = refbuf->len - client->pos; ret = client_send_bytes (client, buf, len); if (ret > 0) client->pos += ret; return ret; } /* This is the commonly used for source streams, here we just progress to * the next buffer in the queue if there is no more left to be written from * the existing buffer. */ int format_advance_queue (source_t *source, client_t *client) { refbuf_t *refbuf = client->refbuf; if (refbuf == NULL) return -1; if (refbuf->next == NULL && client->pos == refbuf->len) return -1; /* move to the next buffer if we have finished with the current one */ if (refbuf->next && client->pos == refbuf->len) { client_set_queue (client, refbuf->next); refbuf = client->refbuf; } return 0; } 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); if (bytes == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "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); if (bytes == -1 ) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); return -1; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); client_send_500(client, "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; } icecast-2.4.2/src/xslt.h0000664000175000017500000000176212511160565012017 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #include #include #include #include #include #include #include #include #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "net/sock.h" #include "connection.h" #include "global.h" #include "refbuf.h" #include "client.h" #include "stats.h" void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client); void xslt_initialize(void); void xslt_shutdown(void); icecast-2.4.2/src/net/0000775000175000017500000000000012511177344011517 500000000000000icecast-2.4.2/src/net/resolver.c0000664000175000017500000001165212511160565013446 00000000000000/* * resolver.c - name resolver library * * Copyright (C) 1999 the icecast team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifndef _WIN32 #include #include #include #include #else #include #endif #ifndef NO_THREAD #include #else #define thread_mutex_create(x) do{}while(0) #define thread_mutex_destroy(x) do{}while(0) #define thread_mutex_lock(x) do{}while(0) #define thread_mutex_unlock(x) do{}while(0) #endif #include "resolver.h" #include "sock.h" /* internal function */ static int _isip(const char *what); /* internal data */ #ifndef NO_THREAD static mutex_t _resolver_mutex; #endif static int _initialized = 0; #ifdef HAVE_INET_PTON static int _isip(const char *what) { union { struct in_addr v4addr; struct in6_addr v6addr; } addr_u; if (inet_pton(AF_INET, what, &addr_u.v4addr) <= 0) return inet_pton(AF_INET6, what, &addr_u.v6addr) > 0 ? 1 : 0; return 1; } #else static int _isip(const char *what) { struct in_addr inp; return inet_aton(what, &inp); } #endif #if defined (HAVE_GETNAMEINFO) && defined (HAVE_GETADDRINFO) char *resolver_getname(const char *ip, char *buff, int len) { struct addrinfo *head = NULL, hints; char *ret = NULL; if (!_isip(ip)) { strncpy(buff, ip, len); buff [len-1] = '\0'; return buff; } memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; if (getaddrinfo (ip, NULL, &hints, &head)) return NULL; if (head) { if (getnameinfo(head->ai_addr, head->ai_addrlen, buff, len, NULL, 0, NI_NAMEREQD) == 0) ret = buff; freeaddrinfo (head); } return ret; } char *resolver_getip(const char *name, char *buff, int len) { struct addrinfo *head, hints; char *ret = NULL; if (_isip(name)) { strncpy(buff, name, len); buff [len-1] = '\0'; return buff; } memset (&hints, 0, sizeof (hints)); hints . ai_family = AF_UNSPEC; hints . ai_socktype = SOCK_STREAM; if (getaddrinfo (name, NULL, &hints, &head)) return NULL; if (head) { if (getnameinfo(head->ai_addr, head->ai_addrlen, buff, len, NULL, 0, NI_NUMERICHOST) == 0) ret = buff; freeaddrinfo (head); } return ret; } #else char *resolver_getname(const char *ip, char *buff, int len) { struct hostent *host; char *ret = NULL; struct in_addr addr; if (! _isip(ip)) { strncpy(buff, ip, len); buff [len-1] = '\0'; return buff; } thread_mutex_lock(&_resolver_mutex); if (inet_aton (ip, &addr)) { /* casting &addr to const char* as it is recommended on win* */ if ((host=gethostbyaddr ((const char *)&addr, sizeof (struct in_addr), AF_INET))) { ret = strncpy (buff, host->h_name, len); buff [len-1] = '\0'; } } thread_mutex_unlock(&_resolver_mutex); return ret; } char *resolver_getip(const char *name, char *buff, int len) { struct hostent *host; char *ret = NULL; if (_isip(name)) { strncpy(buff, name, len); buff [len-1] = '\0'; return buff; } thread_mutex_lock(&_resolver_mutex); host = gethostbyname(name); if (host) { char * temp = inet_ntoa(*(struct in_addr *)host->h_addr); ret = strncpy(buff, temp, len); buff [len-1] = '\0'; } thread_mutex_unlock(&_resolver_mutex); return ret; } #endif void resolver_initialize() { /* initialize the lib if we havne't done so already */ if (!_initialized) { _initialized = 1; thread_mutex_create (&_resolver_mutex); /* keep dns connects (TCP) open */ #ifdef HAVE_SETHOSTENT sethostent(1); #endif } } void resolver_shutdown(void) { if (_initialized) { thread_mutex_destroy(&_resolver_mutex); _initialized = 0; #ifdef HAVE_ENDHOSTENT endhostent(); #endif } } icecast-2.4.2/src/net/resolver.h0000664000175000017500000000132712511160565013451 00000000000000/* ** resolver.h ** ** name resolver library header ** */ #ifndef __RESOLVER_H #define __RESOLVER_H /* ** resolver_lookup ** ** resolves a hosts name from it's ip address ** or ** resolves an ip address from it's host name ** ** returns a pointer to buff, or NULL if an error occured ** */ #ifdef _mangle # define resolver_initialize _mangle(resolver_initialize) # define resolver_shutdown _mangle(resolver_shutdown) # define resolver_getname _mangle(resolver_getname) # define resolver_getip _mangle(resolver_getip) #endif void resolver_initialize(void); void resolver_shutdown(void); char *resolver_getname(const char *ip, char *buff, int len); char *resolver_getip(const char *name, char *buff, int len); #endif icecast-2.4.2/src/net/README0000664000175000017500000000054312511160565012316 00000000000000This is a name resolving library that's threadsafe. Right now it only implements this with mutexes, but we should extend it to use gethostbyXXXX_r() if it's available. It shoudl work on win32, but i'm probably forgetting a headerfile. API is basically not going to change. Please consult with the rest of the team before changing the interface. jack.icecast-2.4.2/src/net/Makefile.am0000664000175000017500000000061212511160565013467 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO test_resolver.c noinst_LTLIBRARIES = libicenet.la noinst_HEADERS = resolver.h sock.h libicenet_la_SOURCES = sock.c resolver.c libicenet_la_CFLAGS = @XIPH_CFLAGS@ INCLUDES = -I$(srcdir)/.. debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@ icecast-2.4.2/src/net/TODO0000664000175000017500000000004112511160565012117 00000000000000- add getXbyY_r function support icecast-2.4.2/src/net/sock.c0000664000175000017500000005226712511160565012553 00000000000000/* -*- c-basic-offset: 4; -*- */ /* sock.c: General Socket Functions * * Copyright (c) 1999 the icecast team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_POLL #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifndef _WIN32 #include #include #include #include #include #include #include #else #include #define vsnprintf _vsnprintf #define EINPROGRESS WSAEINPROGRESS #define ENOTSOCK WSAENOTSOCK #define EWOULDBLOCK WSAEWOULDBLOCK #define EALREADY WSAEALREADY #define socklen_t int #ifndef __MINGW32__ #define va_copy(ap1, ap2) memcpy(&ap1, &ap2, sizeof(va_list)) #endif #endif #include "sock.h" #include "resolver.h" /* for older C libraries */ #ifndef AI_NUMERICSERV # define AI_NUMERICSERV 0 #endif #ifndef AI_ADDRCONFIG # define AI_ADDRCONFIG 0 #endif /* sock_initialize ** ** initializes the socket library. you must call this ** before using the library! */ void sock_initialize(void) { #ifdef _WIN32 WSADATA wsad; WSAStartup(0x0101, &wsad); #endif resolver_initialize(); } /* sock_shutdown ** ** shutdown the socket library. remember to call this when you're ** through using the lib */ void sock_shutdown(void) { #ifdef _WIN32 WSACleanup(); #endif resolver_shutdown(); } /* sock_get_localip ** ** gets the local ip address for the machine ** the ip it returns *should* be on the internet. ** in any case, it's as close as we can hope to get ** unless someone has better ideas on how to do this */ char *sock_get_localip(char *buff, int len) { char temp[1024]; if (gethostname(temp, sizeof(temp)) != 0) return NULL; if (resolver_getip(temp, buff, len)) return buff; return NULL; } /* sock_error ** ** returns the last socket error */ int sock_error(void) { #ifdef _WIN32 return WSAGetLastError(); #else return errno; #endif } void sock_set_error(int val) { #ifdef _WIN32 WSASetLastError (val); #else errno = val; #endif } /* sock_recoverable ** ** determines if the socket error is recoverable ** in terms of non blocking sockets */ int sock_recoverable(int error) { switch (error) { case 0: case EAGAIN: case EINTR: case EINPROGRESS: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif #ifdef ERESTART case ERESTART: #endif return 1; default: return 0; } } int sock_stalled (int error) { switch (error) { case EAGAIN: case EINPROGRESS: case EALREADY: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif #ifdef ERESTART case ERESTART: #endif return 1; default: return 0; } } static int sock_connect_pending (int error) { return error == EINPROGRESS || error == EALREADY; } /* sock_valid_socket ** ** determines if a sock_t represents a valid socket */ int sock_valid_socket(sock_t sock) { int ret; int optval; socklen_t optlen; optlen = sizeof(int); /* apparently on windows getsockopt.optval is a char * */ ret = getsockopt(sock, SOL_SOCKET, SO_TYPE, (void*) &optval, &optlen); return (ret == 0); } /* determines if the passed socket is still connected */ int sock_active (sock_t sock) { char c; int l; l = recv (sock, &c, 1, MSG_PEEK); if (l == 0) return 0; if (l == SOCK_ERROR && sock_recoverable (sock_error())) return 1; return 0; } /* inet_aton ** ** turns an ascii ip address into a binary representation */ #ifdef _WIN32 int inet_aton(const char *s, struct in_addr *a) { int lsb, b2, b3, msb; if (sscanf(s, "%d.%d.%d.%d", &lsb, &b2, &b3, &msb) < 4) { return 0; } a->s_addr = inet_addr(s); return (a->s_addr != INADDR_NONE); } #endif /* _WIN32 */ /* sock_set_blocking * * set the sock blocking or nonblocking * 1 for blocking * 0 for nonblocking */ int sock_set_blocking(sock_t sock, int block) { #ifdef _WIN32 #ifdef __MINGW32__ u_long varblock = 1; #else int varblock = 1; #endif #endif if ((!sock_valid_socket(sock)) || (block < 0) || (block > 1)) return SOCK_ERROR; #ifdef _WIN32 if (block) varblock = 0; return ioctlsocket(sock, FIONBIO, &varblock); #else return fcntl(sock, F_SETFL, (block) ? 0 : O_NONBLOCK); #endif } int sock_set_nolinger(sock_t sock) { struct linger lin = { 0, 0 }; return setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&lin, sizeof(struct linger)); } int sock_set_nodelay(sock_t sock) { int nodelay = 1; return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&nodelay, sizeof(int)); } int sock_set_keepalive(sock_t sock) { int keepalive = 1; return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(int)); } /* sock_close ** ** close the socket */ int sock_close(sock_t sock) { #ifdef _WIN32 return closesocket(sock); #else return close(sock); #endif } /* sock_writev * * write multiple buffers at once, return bytes actually written */ #ifdef HAVE_WRITEV ssize_t sock_writev (sock_t sock, const struct iovec *iov, size_t count) { return writev (sock, iov, count); } #else ssize_t sock_writev (sock_t sock, const struct iovec *iov, size_t count) { int i = count, accum = 0, ret; const struct iovec *v = iov; while (i) { if (v->iov_base && v->iov_len) { ret = sock_write_bytes (sock, v->iov_base, v->iov_len); if (ret == -1 && accum==0) return -1; if (ret == -1) ret = 0; accum += ret; if (ret < (int)v->iov_len) break; } v++; i--; } return accum; } #endif /* sock_write_bytes ** ** write bytes to the socket ** this function will _NOT_ block */ int sock_write_bytes(sock_t sock, const void *buff, size_t len) { /* sanity check */ if (!buff) { return SOCK_ERROR; } else if (len <= 0) { return SOCK_ERROR; } /*else if (!sock_valid_socket(sock)) { return SOCK_ERROR; } */ return send(sock, buff, len, 0); } /* sock_write_string ** ** writes a string to a socket ** This function must only be called with a blocking socket. */ int sock_write_string(sock_t sock, const char *buff) { return (sock_write_bytes(sock, buff, strlen(buff)) > 0); } /* sock_write ** ** write a formatted string to the socket ** this function must only be called with a blocking socket. ** will truncate the string if it's greater than 1024 chars. */ int sock_write(sock_t sock, const char *fmt, ...) { int rc; va_list ap; va_start (ap, fmt); rc = sock_write_fmt (sock, fmt, ap); va_end (ap); return rc; } #ifdef HAVE_OLD_VSNPRINTF int sock_write_fmt(sock_t sock, const char *fmt, va_list ap) { va_list ap_local; unsigned int len = 1024; char *buff = NULL; int ret; /* don't go infinite, but stop at some huge limit */ while (len < 2*1024*1024) { char *tmp = realloc (buff, len); ret = -1; if (tmp == NULL) break; buff = tmp; va_copy (ap_local, ap); ret = vsnprintf (buff, len, fmt, ap_local); if (ret > 0) { ret = sock_write_bytes (sock, buff, ret); break; } len += 8192; } free (buff); return ret; } #else int sock_write_fmt(sock_t sock, const char *fmt, va_list ap) { char buffer [1024], *buff = buffer; int len; int rc = SOCK_ERROR; va_list ap_retry; va_copy (ap_retry, ap); len = vsnprintf (buff, sizeof (buffer), fmt, ap); if (len > 0) { if ((size_t)len < sizeof (buffer)) /* common case */ rc = sock_write_bytes(sock, buff, (size_t)len); else { /* truncated */ buff = malloc (++len); if (buff) { len = vsnprintf (buff, len, fmt, ap_retry); if (len > 0) rc = sock_write_bytes (sock, buff, len); free (buff); } } } va_end (ap_retry); return rc; } #endif int sock_read_bytes(sock_t sock, char *buff, size_t len) { /*if (!sock_valid_socket(sock)) return 0; */ if (!buff) return 0; if (len <= 0) return 0; return recv(sock, buff, len, 0); } /* sock_read_line ** ** Read one line of at max len bytes from sock into buff. ** If ok, return 1 and nullterminate buff. Otherwize return 0. ** Terminating \n is not put into the buffer. ** ** this function will probably not work on sockets in nonblocking mode */ int sock_read_line(sock_t sock, char *buff, const int len) { char c = '\0'; int read_bytes, pos; /*if (!sock_valid_socket(sock)) { return 0; } else*/ if (!buff) { return 0; } else if (len <= 0) { return 0; } pos = 0; read_bytes = recv(sock, &c, 1, 0); if (read_bytes < 0) { return 0; } while ((c != '\n') && (pos < len) && (read_bytes == 1)) { if (c != '\r') buff[pos++] = c; read_bytes = recv(sock, &c, 1, 0); } if (read_bytes == 1) { buff[pos] = '\0'; return 1; } else { return 0; } } /* see if a connection has been established. If timeout is < 0 then wait * indefinitely, else wait for the stated number of seconds. * return SOCK_TIMEOUT for timeout * return SOCK_ERROR for failure * return 0 for try again, interrupted * return 1 for ok */ #ifdef HAVE_POLL int sock_connected (sock_t sock, int timeout) { struct pollfd check; int val = SOCK_ERROR; socklen_t size = sizeof val; check.fd = sock; check.events = POLLOUT; switch (poll (&check, 1, timeout*1000)) { case 0: return SOCK_TIMEOUT; default: /* on windows getsockopt.val is defined as char* */ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*) &val, &size) == 0) { if (val == 0) return 1; sock_set_error (val); } /* fall through */ case -1: if (sock_recoverable (sock_error())) return 0; return SOCK_ERROR; } } #else int sock_connected (sock_t sock, int timeout) { fd_set wfds; int val = SOCK_ERROR; socklen_t size = sizeof val; struct timeval tv, *timeval = NULL; /* make a timeout of <0 be indefinite */ if (timeout >= 0) { tv.tv_sec = timeout; tv.tv_usec = 0; timeval = &tv; } FD_ZERO(&wfds); FD_SET(sock, &wfds); switch (select(sock + 1, NULL, &wfds, NULL, timeval)) { case 0: return SOCK_TIMEOUT; default: /* on windows getsockopt.val is defined as char* */ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*) &val, &size) == 0) { if (val == 0) return 1; sock_set_error (val); } /* fall through */ case -1: if (sock_recoverable (sock_error())) return 0; return SOCK_ERROR; } } #endif sock_t sock_connect_wto (const char *hostname, int port, int timeout) { return sock_connect_wto_bind(hostname, port, NULL, timeout); } #ifdef HAVE_GETADDRINFO sock_t sock_connect_non_blocking (const char *hostname, unsigned port) { int sock = SOCK_ERROR; struct addrinfo *ai, *head, hints; char service[8]; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf (service, sizeof (service), "%u", port); if (getaddrinfo (hostname, service, &hints, &head)) return SOCK_ERROR; ai = head; while (ai) { if ((sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol)) > -1) { sock_set_blocking (sock, 0); if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && !sock_connect_pending(sock_error())) { sock_close (sock); sock = SOCK_ERROR; } else break; } ai = ai->ai_next; } if (head) freeaddrinfo (head); return sock; } /* issue a connect, but return after the timeout (seconds) is reached. If * timeout is 0 or less then we will wait until the OS gives up on the connect * The socket is returned */ sock_t sock_connect_wto_bind (const char *hostname, int port, const char *bnd, int timeout) { sock_t sock = SOCK_ERROR; struct addrinfo *ai, *head, *b_head=NULL, hints; char service[8]; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf (service, sizeof (service), "%u", port); if (getaddrinfo (hostname, service, &hints, &head)) return SOCK_ERROR; ai = head; while (ai) { if ((sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol)) >= 0) { if (timeout > 0) sock_set_blocking (sock, 0); if (bnd) { struct addrinfo b_hints; memset (&b_hints, 0, sizeof(b_hints)); b_hints.ai_family = ai->ai_family; b_hints.ai_socktype = ai->ai_socktype; b_hints.ai_protocol = ai->ai_protocol; if (getaddrinfo (bnd, NULL, &b_hints, &b_head) || bind (sock, b_head->ai_addr, b_head->ai_addrlen) < 0) { sock_close (sock); sock = SOCK_ERROR; break; } } if (connect (sock, ai->ai_addr, ai->ai_addrlen) == 0) break; /* loop as the connect maybe async */ while (sock != SOCK_ERROR) { if (sock_recoverable (sock_error())) { int connected = sock_connected (sock, timeout); if (connected == 0) /* try again, interrupted */ continue; if (connected == 1) /* connected */ { if (timeout >= 0) sock_set_blocking(sock, 1); break; } } sock_close (sock); sock = SOCK_ERROR; } if (sock != SOCK_ERROR) break; } ai = ai->ai_next; } if (b_head) freeaddrinfo (b_head); freeaddrinfo (head); return sock; } sock_t sock_get_server_socket (int port, const char *sinterface) { struct sockaddr_storage sa; struct addrinfo hints, *res, *ai; char service [10]; int sock; if (port < 0) return SOCK_ERROR; memset (&sa, 0, sizeof(sa)); memset (&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV | AI_NUMERICHOST; hints.ai_socktype = SOCK_STREAM; snprintf (service, sizeof (service), "%d", port); if (getaddrinfo (sinterface, service, &hints, &res)) return SOCK_ERROR; ai = res; do { int on = 1; sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) continue; setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)); on = 0; #ifdef IPV6_V6ONLY setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof on); #endif if (bind (sock, ai->ai_addr, ai->ai_addrlen) < 0) { sock_close (sock); continue; } freeaddrinfo (res); return sock; } while ((ai = ai->ai_next)); freeaddrinfo (res); return SOCK_ERROR; } #else int sock_try_connection (sock_t sock, const char *hostname, unsigned int port) { struct sockaddr_in sin, server; char ip[MAX_ADDR_LEN]; if (!hostname || !hostname[0] || port == 0) return -1; memset(&sin, 0, sizeof(struct sockaddr_in)); memset(&server, 0, sizeof(struct sockaddr_in)); if (!resolver_getip(hostname, ip, MAX_ADDR_LEN)) { sock_close (sock); return -1; } if (inet_aton(ip, (struct in_addr *)&sin.sin_addr) == 0) { sock_close(sock); return -1; } memcpy(&server.sin_addr, &sin.sin_addr, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons((short)port); return connect(sock, (struct sockaddr *)&server, sizeof(server)); } sock_t sock_connect_non_blocking (const char *hostname, unsigned port) { sock_t sock; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == SOCK_ERROR) return SOCK_ERROR; sock_set_blocking (sock, 0); sock_try_connection (sock, hostname, port); return sock; } sock_t sock_connect_wto_bind (const char *hostname, int port, const char *bnd, int timeout) { sock_t sock; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == SOCK_ERROR) return SOCK_ERROR; if (bnd) { struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; if (inet_aton (bnd, &sa.sin_addr) == 0 || bind (sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { sock_close (sock); return SOCK_ERROR; } } if (timeout) { sock_set_blocking (sock, 0); if (sock_try_connection (sock, hostname, port) < 0) { int ret = sock_connected (sock, timeout); if (ret <= 0) { sock_close (sock); return SOCK_ERROR; } } sock_set_blocking(sock, 1); } else { if (sock_try_connection (sock, hostname, port) < 0) { sock_close (sock); sock = SOCK_ERROR; } } return sock; } /* sock_get_server_socket ** ** create a socket for incoming requests on a specified port and ** interface. if interface is null, listen on all interfaces. ** returns the socket, or SOCK_ERROR on failure */ sock_t sock_get_server_socket(int port, const char *sinterface) { struct sockaddr_in sa; int error, opt; sock_t sock; char ip[MAX_ADDR_LEN]; if (port < 0) return SOCK_ERROR; /* defaults */ memset(&sa, 0, sizeof(sa)); /* set the interface to bind to if specified */ if (sinterface != NULL) { if (!resolver_getip(sinterface, ip, sizeof (ip))) return SOCK_ERROR; if (!inet_aton(ip, &sa.sin_addr)) { return SOCK_ERROR; } else { sa.sin_family = AF_INET; sa.sin_port = htons((short)port); } } else { sa.sin_addr.s_addr = INADDR_ANY; sa.sin_family = AF_INET; sa.sin_port = htons((short)port); } /* get a socket */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock == -1) return SOCK_ERROR; /* reuse it if we can */ opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(int)); /* bind socket to port */ error = bind(sock, (struct sockaddr *)&sa, sizeof (struct sockaddr_in)); if (error == -1) return SOCK_ERROR; return sock; } #endif void sock_set_send_buffer (sock_t sock, int win_size) { setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *) &win_size, sizeof(win_size)); } int sock_listen(sock_t serversock, int backlog) { if (!sock_valid_socket(serversock)) return 0; if (backlog <= 0) backlog = 10; return (listen(serversock, backlog) == 0); } sock_t sock_accept(sock_t serversock, char *ip, size_t len) { #ifdef HAVE_GETNAMEINFO struct sockaddr_storage sa; #else struct sockaddr_in sa; #endif sock_t ret; socklen_t slen; if (ip == NULL || len == 0 || !sock_valid_socket(serversock)) return SOCK_ERROR; slen = sizeof(sa); ret = accept(serversock, (struct sockaddr *)&sa, &slen); if (ret != SOCK_ERROR) { #ifdef HAVE_GETNAMEINFO if (getnameinfo ((struct sockaddr *)&sa, slen, ip, len, NULL, 0, NI_NUMERICHOST)) snprintf (ip, len, "unknown"); #else /* inet_ntoa is not reentrant, we should protect this */ strncpy(ip, inet_ntoa(sa.sin_addr), len); #endif sock_set_nolinger(ret); sock_set_keepalive(ret); } return ret; } icecast-2.4.2/src/net/test_resolver.c0000664000175000017500000000057212511160565014504 00000000000000#include #include #include "resolver.h" int main() { char buff[1024]; resolver_initialize(); printf("I got %s, when looking up %s.\n", resolver_getip("bach.greenwitch.com", buff, 1024), "bach.greenwitch.com"); printf("I got %s, when looking up %s.\n", resolver_getname("207.181.249.14", buff, 1024), "207.181.249.14"); return 0; } icecast-2.4.2/src/net/Makefile.in0000664000175000017500000005163412511177306013513 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/net DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) COPYING README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libicenet_la_LIBADD = am_libicenet_la_OBJECTS = libicenet_la-sock.lo \ libicenet_la-resolver.lo libicenet_la_OBJECTS = $(am_libicenet_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libicenet_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libicenet_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libicenet_la_SOURCES) DIST_SOURCES = $(libicenet_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO test_resolver.c noinst_LTLIBRARIES = libicenet.la noinst_HEADERS = resolver.h sock.h libicenet_la_SOURCES = sock.c resolver.c libicenet_la_CFLAGS = @XIPH_CFLAGS@ INCLUDES = -I$(srcdir)/.. all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/net/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/net/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libicenet.la: $(libicenet_la_OBJECTS) $(libicenet_la_DEPENDENCIES) $(EXTRA_libicenet_la_DEPENDENCIES) $(AM_V_CCLD)$(libicenet_la_LINK) $(libicenet_la_OBJECTS) $(libicenet_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libicenet_la-resolver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libicenet_la-sock.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libicenet_la-sock.lo: sock.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicenet_la_CFLAGS) $(CFLAGS) -MT libicenet_la-sock.lo -MD -MP -MF $(DEPDIR)/libicenet_la-sock.Tpo -c -o libicenet_la-sock.lo `test -f 'sock.c' || echo '$(srcdir)/'`sock.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libicenet_la-sock.Tpo $(DEPDIR)/libicenet_la-sock.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sock.c' object='libicenet_la-sock.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicenet_la_CFLAGS) $(CFLAGS) -c -o libicenet_la-sock.lo `test -f 'sock.c' || echo '$(srcdir)/'`sock.c libicenet_la-resolver.lo: resolver.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicenet_la_CFLAGS) $(CFLAGS) -MT libicenet_la-resolver.lo -MD -MP -MF $(DEPDIR)/libicenet_la-resolver.Tpo -c -o libicenet_la-resolver.lo `test -f 'resolver.c' || echo '$(srcdir)/'`resolver.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libicenet_la-resolver.Tpo $(DEPDIR)/libicenet_la-resolver.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='resolver.c' object='libicenet_la-resolver.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicenet_la_CFLAGS) $(CFLAGS) -c -o libicenet_la-resolver.lo `test -f 'resolver.c' || echo '$(srcdir)/'`resolver.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/net/BUILDING0000664000175000017500000000006012511160565012550 00000000000000defines that affect compilation none currently icecast-2.4.2/src/net/sock.h0000664000175000017500000001117412511160565012550 00000000000000/* sock.h * - General Socket Function Headers * * Copyright (c) 1999 the icecast team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __SOCK_H #define __SOCK_H #include #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_UNISTD_H #include #elif _WIN32 #include #endif #ifdef HAVE_SYS_UIO_H #include #else #ifndef _SYS_UIO_H struct iovec { void *iov_base; size_t iov_len; }; #endif #endif #if !defined(HAVE_INET_ATON) && defined(HAVE_INET_PTON) #define inet_aton(a,b) inet_pton(AF_INET, (a), (b)) #endif #ifdef INET6_ADDRSTRLEN #define MAX_ADDR_LEN INET6_ADDRSTRLEN #else #define MAX_ADDR_LEN 46 #endif #ifndef sock_t #define sock_t int #endif /* The following values are based on unix avoiding errno value clashes */ #define SOCK_SUCCESS 0 #define SOCK_ERROR (sock_t)-1 #define SOCK_TIMEOUT -2 /* sock connect macro */ #define sock_connect(h, p) sock_connect_wto(h, p, 0) #ifdef _mangle # define sock_initialize _mangle(sock_initialize) # define sock_shutdown _mangle(sock_shutdown) # define sock_get_localip _mangle(sock_get_localip) # define sock_error _mangle(sock_error) # define sock_set_error _mangle(sock_set_error) # define sock_recoverable _mangle(sock_recoverable) # define sock_stalled _mangle(sock_stalled) # define sock_valid_socket _mangle(sock_valid_socket) # define sock_set_blocking _mangle(sock_set_blocking) # define sock_set_nolinger _mangle(sock_set_nolinger) # define sock_set_nodelay _mangle(sock_set_nodelay) # define sock_set_keepalive _mangle(sock_set_keepalive) # define sock_close _mangle(sock_close) # define sock_connect_wto _mangle(sock_connect_wto) # define sock_connect_wto_bind _mangle(sock_connect_wto_bind) # define sock_connect_non_blocking _mangle(sock_connect_non_blocking) # define sock_connected _mangle(sock_connected) # define sock_write_bytes _mangle(sock_write_bytes) # define sock_write _mangle(sock_write) # define sock_write_fmt _mangle(sock_write_fmt) # define sock_write_string _mangle(sock_write_string) # define sock_writev _mangle(sock_writev) # define sock_read_bytes _mangle(sock_read_bytes) # define sock_read_line _mangle(sock_read_line) # define sock_get_server_socket _mangle(sock_get_server_socket) # define sock_listen _mangle(sock_listen) # define sock_set_send_buffer _mangle(sock_set_send_buffer) # define sock_accept _mangle(sock_accept) #endif /* Misc socket functions */ void sock_initialize(void); void sock_shutdown(void); char *sock_get_localip(char *buff, int len); int sock_error(void); int sock_recoverable(int error); int sock_stalled(int error); int sock_valid_socket(sock_t sock); int sock_active (sock_t sock); int sock_set_blocking(sock_t sock, int block); int sock_set_nolinger(sock_t sock); int sock_set_keepalive(sock_t sock); int sock_set_nodelay(sock_t sock); void sock_set_send_buffer (sock_t sock, int win_size); void sock_set_error(int val); int sock_close(sock_t sock); /* Connection related socket functions */ sock_t sock_connect_wto(const char *hostname, int port, int timeout); sock_t sock_connect_wto_bind(const char *hostname, int port, const char *bnd, int timeout); sock_t sock_connect_non_blocking(const char *host, unsigned port); int sock_connected(sock_t sock, int timeout); /* Socket write functions */ int sock_write_bytes(sock_t sock, const void *buff, size_t len); int sock_write(sock_t sock, const char *fmt, ...); int sock_write_fmt(sock_t sock, const char *fmt, va_list ap); int sock_write_string(sock_t sock, const char *buff); ssize_t sock_writev (sock_t sock, const struct iovec *iov, size_t count); /* Socket read functions */ int sock_read_bytes(sock_t sock, char *buff, size_t len); int sock_read_line(sock_t sock, char *string, const int len); /* server socket functions */ sock_t sock_get_server_socket(int port, const char *sinterface); int sock_listen(sock_t serversock, int backlog); sock_t sock_accept(sock_t serversock, char *ip, size_t len); #ifdef _WIN32 int inet_aton(const char *s, struct in_addr *a); #endif #endif /* __SOCK_H */ icecast-2.4.2/src/net/COPYING0000664000175000017500000006127312511160565012500 00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! icecast-2.4.2/src/source.c0000664000175000017500000013164712511160565012326 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #ifndef _WIN32 #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 4096 #endif #else #include #include #define snprintf _snprintf #endif #ifndef _WIN32 /* for __setup_empty_script_environment() */ #include #include #endif #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "net/sock.h" #include "connection.h" #include "global.h" #include "refbuf.h" #include "client.h" #include "stats.h" #include "logging.h" #include "cfgfile.h" #include "util.h" #include "source.h" #include "format.h" #include "fserve.h" #include "auth.h" #include "compat.h" #undef CATMODULE #define CATMODULE "source" #define MAX_FALLBACK_DEPTH 10 mutex_t move_clients_mutex; /* avl tree helper */ static int _compare_clients(void *compare_arg, void *a, void *b); static int _free_client(void *key); static void _parse_audio_info (source_t *source, const char *s); static void source_shutdown (source_t *source); #ifdef _WIN32 #define source_run_script(x,y) ICECAST_LOG_WARN("on [dis]connect scripts disabled"); #else static void source_run_script (char *command, char *mountpoint); #endif /* Allocate a new source with the stated mountpoint, if one already * exists with that mountpoint in the global source tree then return * NULL. */ source_t *source_reserve (const char *mount) { source_t *src = NULL; if(mount[0] != '/') ICECAST_LOG_WARN("Source at \"%s\" does not start with '/', clients will be " "unable to connect", mount); do { avl_tree_wlock (global.source_tree); src = source_find_mount_raw (mount); if (src) { src = NULL; break; } src = calloc (1, sizeof(source_t)); if (src == NULL) break; src->client_tree = avl_tree_new(_compare_clients, NULL); src->pending_tree = avl_tree_new(_compare_clients, NULL); /* make duplicates for strings or similar */ src->mount = strdup (mount); src->max_listeners = -1; thread_mutex_create(&src->lock); avl_insert (global.source_tree, src); } while (0); avl_tree_unlock (global.source_tree); return src; } /* Find a mount with this raw name - ignoring fallbacks. You should have the * global source tree locked to call this. */ source_t *source_find_mount_raw(const char *mount) { source_t *source; avl_node *node; int cmp; if (!mount) { return NULL; } /* get the root node */ node = global.source_tree->root->right; while (node) { source = (source_t *)node->key; cmp = strcmp(mount, source->mount); if (cmp < 0) node = node->left; else if (cmp > 0) node = node->right; else return source; } /* didn't find it */ return NULL; } /* Search for mount, if the mount is there but not currently running then * check the fallback, and so on. Must have a global source lock to call * this function. */ source_t *source_find_mount (const char *mount) { source_t *source = NULL; ice_config_t *config; mount_proxy *mountinfo; int depth = 0; config = config_get_config(); while (mount && depth < MAX_FALLBACK_DEPTH) { source = source_find_mount_raw(mount); if (source) { if (source->running || source->on_demand) break; } /* we either have a source which is not active (relay) or no source * at all. Check the mounts list for fallback settings */ mountinfo = config_find_mount (config, mount, MOUNT_TYPE_NORMAL); source = NULL; if (mountinfo == NULL) break; mount = mountinfo->fallback_mount; depth++; } config_release_config(); return source; } int source_compare_sources(void *arg, void *a, void *b) { source_t *srca = (source_t *)a; source_t *srcb = (source_t *)b; return strcmp(srca->mount, srcb->mount); } void source_clear_source (source_t *source) { int c; ICECAST_LOG_DEBUG("clearing source \"%s\"", source->mount); avl_tree_wlock (source->pending_tree); client_destroy(source->client); source->client = NULL; source->parser = NULL; source->con = NULL; /* log bytes read in access log */ if (source->client && source->format) source->client->con->sent_bytes = source->format->read_bytes; if (source->dumpfile) { ICECAST_LOG_INFO("Closing dumpfile for %s", source->mount); fclose (source->dumpfile); source->dumpfile = NULL; } /* lets kick off any clients that are left on here */ avl_tree_wlock (source->client_tree); c=0; while (1) { avl_node *node = avl_get_first (source->client_tree); if (node) { client_t *client = node->key; if (client->respcode == 200) c++; /* only count clients that have had some processing */ avl_delete (source->client_tree, client, _free_client); continue; } break; } if (c) { stats_event_sub (NULL, "listeners", source->listeners); ICECAST_LOG_INFO("%d active listeners on %s released", c, source->mount); } avl_tree_unlock (source->client_tree); while (avl_get_first (source->pending_tree)) { avl_delete (source->pending_tree, avl_get_first(source->pending_tree)->key, _free_client); } if (source->format && source->format->free_plugin) source->format->free_plugin (source->format); source->format = NULL; /* Lets clear out the source queue too */ while (source->stream_data) { refbuf_t *p = source->stream_data; source->stream_data = p->next; p->next = NULL; /* can be referenced by burst handler as well */ while (p->_count > 1) refbuf_release (p); refbuf_release (p); } source->stream_data_tail = NULL; 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->max_listeners = -1; source->prev_listeners = 0; source->hidden = 0; source->shoutcast_compat = 0; source->client_stats_update = 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; if (source->intro_file) { fclose (source->intro_file); source->intro_file = NULL; } source->on_demand_req = 0; avl_tree_unlock (source->pending_tree); } /* Remove the provided source from the global tree and free it */ void source_free_source (source_t *source) { ICECAST_LOG_DEBUG("freeing source \"%s\"", source->mount); avl_tree_wlock (global.source_tree); avl_delete (global.source_tree, source, NULL); avl_tree_unlock (global.source_tree); avl_tree_free(source->pending_tree, _free_client); avl_tree_free(source->client_tree, _free_client); /* make sure all YP entries have gone */ yp_remove (source->mount); free (source->mount); free (source); return; } client_t *source_find_client(source_t *source, int id) { client_t fakeclient; void *result; connection_t fakecon; fakeclient.con = &fakecon; fakeclient.con->id = id; avl_tree_rlock(source->client_tree); if(avl_get_by_key(source->client_tree, &fakeclient, &result) == 0) { avl_tree_unlock(source->client_tree); return result; } avl_tree_unlock(source->client_tree); return NULL; } /* 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) { unsigned long count = 0; if (strcmp (source->mount, dest->mount) == 0) { ICECAST_LOG_WARN("src and dst are the same \"%s\", skipping", source->mount); return; } /* 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 */ avl_tree_wlock (dest->pending_tree); if (dest->running == 0 && dest->on_demand == 0) { ICECAST_LOG_WARN("destination mount %s not running, unable to move clients ", dest->mount); avl_tree_unlock (dest->pending_tree); thread_mutex_unlock (&move_clients_mutex); return; } do { client_t *client; /* we need to move the client and pending trees - we must take the * locks in this order to avoid deadlocks */ avl_tree_wlock (source->pending_tree); avl_tree_wlock (source->client_tree); if (source->on_demand == 0 && source->format == NULL) { ICECAST_LOG_INFO("source mount %s is not available", source->mount); break; } if (source->format && dest->format) { if (source->format->type != dest->format->type) { ICECAST_LOG_WARN("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); /* when switching a client to a different queue, be wary of the * refbuf it's referring to, if it's http headers then we need * to write them so don't release it. */ if (client->check_buffer != format_check_http_buffer) { client_set_queue (client, NULL); client->check_buffer = format_check_file_buffer; if (source->con == NULL) client->intro_offset = -1; } avl_insert (dest->pending_tree, (void *)client); count++; } 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); /* when switching a client to a different queue, be wary of the * refbuf it's referring to, if it's http headers then we need * to write them so don't release it. */ if (client->check_buffer != format_check_http_buffer) { client_set_queue (client, NULL); client->check_buffer = format_check_file_buffer; if (source->con == NULL) client->intro_offset = -1; } avl_insert (dest->pending_tree, (void *)client); count++; } ICECAST_LOG_INFO("passing %lu listeners to \"%s\"", count, dest->mount); source->listeners = 0; stats_event (source->mount, "listeners", "0"); } while (0); avl_tree_unlock (source->pending_tree); avl_tree_unlock (source->client_tree); /* see if we need to wake up an on-demand relay */ if (dest->running == 0 && dest->on_demand && count) dest->on_demand_req = 1; avl_tree_unlock (dest->pending_tree); thread_mutex_unlock (&move_clients_mutex); } /* get some data from the source. The stream data is placed in a refbuf * and sent back, however NULL is also valid as in the case of a short * timeout and there's no data pending. */ static refbuf_t *get_next_buffer (source_t *source) { refbuf_t *refbuf = NULL; int delay = 250; if (source->short_delay) delay = 0; while (global.running == ICECAST_RUNNING && source->running) { int fds = 0; time_t current = time (NULL); if (source->client) fds = util_timed_wait_for_fd (source->con->sock, delay); else { thread_sleep (delay*1000); source->last_read = current; } if (current >= source->client_stats_update) { stats_event_args (source->mount, "total_bytes_read", "%"PRIu64, source->format->read_bytes); stats_event_args (source->mount, "total_bytes_sent", "%"PRIu64, source->format->sent_bytes); source->client_stats_update = current + 5; } if (fds < 0) { if (! sock_recoverable (sock_error())) { ICECAST_LOG_WARN("Error while waiting on socket, Disconnecting source"); source->running = 0; } break; } if (fds == 0) { thread_mutex_lock(&source->lock); if ((source->last_read + (time_t)source->timeout) < current) { ICECAST_LOG_DEBUG("last %ld, timeout %d, now %ld", (long)source->last_read, source->timeout, (long)current); ICECAST_LOG_WARN("Disconnecting source due to socket timeout"); source->running = 0; } thread_mutex_unlock(&source->lock); break; } source->last_read = current; refbuf = source->format->get_buffer (source); if (source->client->con && source->client->con->error) { ICECAST_LOG_INFO("End of Stream %s", source->mount); source->running = 0; continue; } if (refbuf) break; } return refbuf; } /* general send routine per listener. The deletion_expected tells us whether * the last in the queue is about to disappear, so if this client is still * referring to it after writing then drop the client as it's fallen too far * behind */ static void send_to_listener (source_t *source, client_t *client, int deletion_expected) { int bytes; int loop = 10; /* max number of iterations in one go */ int total_written = 0; while (1) { /* check for limited listener time */ if (client->con->discon_time) if (time(NULL) >= client->con->discon_time) { ICECAST_LOG_INFO("time limit reached for client #%lu", client->con->id); client->con->error = 1; } /* jump out if client connection has died */ if (client->con->error) break; /* lets not send too much to one client in one go, but don't sleep for too long if more data can be sent */ if (total_written > 20000 || loop == 0) { if (client->check_buffer != format_check_file_buffer) source->short_delay = 1; break; } loop--; if (client->check_buffer (source, client) < 0) break; bytes = client->write_to_client (client); if (bytes <= 0) break; /* can't write any more */ total_written += bytes; } source->format->sent_bytes += total_written; /* the refbuf referenced at head (last in queue) may be marked for deletion * if so, check to see if this client is still referring to it */ if (deletion_expected && client->refbuf && client->refbuf == source->stream_data) { ICECAST_LOG_INFO("Client %lu (%s) has fallen too far behind, removing", client->con->id, client->con->ip); stats_event_inc (source->mount, "slow_listeners"); client->con->error = 1; } } /* Open the file for stream dumping. * This function should do all processing of the filename. */ static FILE * source_open_dumpfile(const char * filename) { #ifndef _WIN32 /* some of the below functions seems not to be standard winapi functions */ char buffer[PATH_MAX]; time_t curtime; struct tm *loctime; /* Get the current time. */ curtime = time (NULL); /* Convert it to local time representation. */ loctime = localtime (&curtime); strftime (buffer, sizeof(buffer), filename, loctime); filename = buffer; #endif return fopen (filename, "ab"); } /* Perform any initialisation just before the stream data is processed, the header * info is processed by now and the format details are setup */ static void source_init (source_t *source) { ice_config_t *config = config_get_config(); char *listenurl; const char *str; int listen_url_size; mount_proxy *mountinfo; /* 6 for max size of port */ listen_url_size = strlen("http://") + strlen(config->hostname) + strlen(":") + 6 + strlen(source->mount) + 1; listenurl = malloc (listen_url_size); memset (listenurl, '\000', listen_url_size); snprintf (listenurl, listen_url_size, "http://%s:%d%s", config->hostname, config->port, source->mount); config_release_config(); str = httpp_getvar(source->parser, "ice-audio-info"); source->audio_info = util_dict_new(); if (str) { _parse_audio_info (source, str); stats_event (source->mount, "audio_info", str); } stats_event (source->mount, "listenurl", listenurl); free(listenurl); if (source->dumpfilename != NULL) { source->dumpfile = source_open_dumpfile (source->dumpfilename); if (source->dumpfile == NULL) { ICECAST_LOG_WARN("Cannot open dump file \"%s\" for appending: %s, disabling.", source->dumpfilename, strerror(errno)); } } /* grab a read lock, to make sure we get a chance to cleanup */ thread_rwlock_rlock (source->shutdown_rwlock); /* start off the statistics */ source->listeners = 0; stats_event_inc (NULL, "source_total_connections"); stats_event (source->mount, "slow_listeners", "0"); stats_event_args (source->mount, "listeners", "%lu", source->listeners); stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners); stats_event_time (source->mount, "stream_start"); stats_event_time_iso8601 (source->mount, "stream_start_iso8601"); ICECAST_LOG_DEBUG("Source creation complete"); source->last_read = time (NULL); source->prev_listeners = -1; source->running = 1; mountinfo = config_find_mount (config_get_config(), source->mount, MOUNT_TYPE_NORMAL); if (mountinfo) { if (mountinfo->on_connect) source_run_script (mountinfo->on_connect, source->mount); auth_stream_start (mountinfo, source->mount); } config_release_config(); /* ** Now, if we have a fallback source and override is on, we want ** to steal its clients, because it means we've come back online ** after a failure and they should be gotten back from the waiting ** loop or jingle track or whatever the fallback is used for */ if (source->fallback_override && source->fallback_mount) { source_t *fallback_source; avl_tree_rlock(global.source_tree); fallback_source = source_find_mount(source->fallback_mount); if (fallback_source) source_move_clients (fallback_source, source); avl_tree_unlock(global.source_tree); } } void source_main (source_t *source) { refbuf_t *refbuf; client_t *client; avl_node *client_node; source_init (source); while (global.running == ICECAST_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; while (source->burst_offset > source->burst_size) { refbuf_t *to_release = source->burst_point; if (to_release->next) { source->burst_point = to_release->next; source->burst_offset -= to_release->len; refbuf_release (to_release); continue; } break; } /* 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 */ thread_mutex_lock(&source->lock); if (source->queue_size > source->queue_size_limit) remove_from_q = 1; thread_mutex_unlock(&source->lock); /* acquire write lock on pending_tree */ avl_tree_wlock(source->pending_tree); /* acquire write lock on client_tree */ avl_tree_wlock(source->client_tree); 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); if (client->respcode == 200) stats_event_dec (NULL, "listeners"); avl_delete(source->client_tree, (void *)client, _free_client); source->listeners--; ICECAST_LOG_DEBUG("Client removed"); continue; } client_node = avl_get_next(client_node); } /** add pending clients **/ client_node = avl_get_first(source->pending_tree); while (client_node) { if(source->max_listeners != -1 && source->listeners >= (unsigned long)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); ICECAST_LOG_INFO("Client deleted, exceeding maximum listeners for this " "mountpoint (%s).", source->mount); continue; } /* Otherwise, the client is accepted, add it */ avl_insert(source->client_tree, client_node->key); source->listeners++; ICECAST_LOG_DEBUG("Client added for mountpoint (%s)", source->mount); 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 != source->prev_listeners) { source->prev_listeners = source->listeners; ICECAST_LOG_INFO("listener count on %s now %lu", source->mount, source->listeners); if (source->listeners > source->peak_listeners) { source->peak_listeners = source->listeners; stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners); } stats_event_args (source->mount, "listeners", "%lu", source->listeners); if (source->listeners == 0 && source->on_demand) source->running = 0; } /* 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 */ ICECAST_LOG_ERROR("queue state is unexpected"); source->running = 0; break; } source->stream_data = to_go->next; source->queue_size -= to_go->len; to_go->next = NULL; refbuf_release (to_go); } } /* release write lock on client_tree */ avl_tree_unlock(source->client_tree); } source_shutdown (source); } static void source_shutdown (source_t *source) { mount_proxy *mountinfo; source->running = 0; ICECAST_LOG_INFO("Source from %s at \"%s\" exiting", source->con->ip, source->mount); mountinfo = config_find_mount (config_get_config(), source->mount, MOUNT_TYPE_NORMAL); if (mountinfo) { if (mountinfo->on_disconnect) source_run_script (mountinfo->on_disconnect, source->mount); auth_stream_end (mountinfo, source->mount); } config_release_config(); /* we have de-activated the source now, so no more clients will be * added, now move the listeners we have to the fallback (if any) */ if (source->fallback_mount) { source_t *fallback_source; avl_tree_rlock(global.source_tree); fallback_source = source_find_mount (source->fallback_mount); if (fallback_source != NULL) source_move_clients (source, fallback_source); avl_tree_unlock (global.source_tree); } /* delete this sources stats */ stats_event(source->mount, NULL, NULL); /* we don't remove the source from the tree here, it may be a relay and therefore reserved */ source_clear_source (source); global_lock(); global.sources--; stats_event_args (NULL, "sources", "%d", global.sources); global_unlock(); /* release our hold on the lock so the main thread can continue cleaning up */ thread_rwlock_unlock(source->shutdown_rwlock); } static int _compare_clients(void *compare_arg, void *a, void *b) { client_t *clienta = (client_t *)a; client_t *clientb = (client_t *)b; connection_t *cona = clienta->con; connection_t *conb = clientb->con; if (cona->id < conb->id) return -1; if (cona->id > conb->id) return 1; return 0; } int source_remove_client(void *key) { return 1; } static int _free_client(void *key) { client_t *client = (client_t *)key; /* if no response has been sent then send a 404 */ if (client->respcode == 0) client_send_404 (client, "Mount unavailable"); else client_destroy(client); return 1; } static void _parse_audio_info (source_t *source, const char *s) { const char *start = s; unsigned int len; while (start != NULL && *start != '\0') { if ((s = strchr (start, ';')) == NULL) len = strlen (start); else { len = (int)(s - start); s++; /* skip passed the ';' */ } if (len) { char name[100], value[200]; char *esc; sscanf (start, "%99[^=]=%199[^;\r\n]", name, value); esc = util_url_unescape (value); if (esc) { util_dict_set (source->audio_info, name, esc); stats_event (source->mount, name, esc); free (esc); } } start = s; } } /* Apply the mountinfo details to the source */ static void source_apply_mount (source_t *source, mount_proxy *mountinfo) { const char *str; int val; http_parser_t *parser = NULL; ICECAST_LOG_DEBUG("Applying mount information for \"%s\"", source->mount); avl_tree_rlock (source->client_tree); stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners); if (mountinfo) { source->max_listeners = mountinfo->max_listeners; source->fallback_override = mountinfo->fallback_override; source->hidden = mountinfo->hidden; } /* if a setting is available in the mount details then use it, else * check the parser details. */ if (source->client) parser = source->client->parser; /* to be done before possible non-utf8 stats */ if (source->format && source->format->apply_settings) source->format->apply_settings (source->client, source->format, mountinfo); /* public */ if (mountinfo && mountinfo->yp_public >= 0) val = mountinfo->yp_public; else { do { str = httpp_getvar (parser, "ice-public"); if (str) break; str = httpp_getvar (parser, "icy-pub"); if (str) break; str = httpp_getvar (parser, "x-audiocast-public"); if (str) break; /* handle header from icecast v2 release */ str = httpp_getvar (parser, "icy-public"); if (str) break; str = "0"; } while (0); val = atoi (str); } stats_event_args (source->mount, "public", "%d", val); if (source->yp_public != val) { ICECAST_LOG_DEBUG("YP changed to %d", val); if (val) yp_add (source->mount); else yp_remove (source->mount); source->yp_public = val; } /* stream name */ if (mountinfo && mountinfo->stream_name) stats_event (source->mount, "server_name", mountinfo->stream_name); else { do { str = httpp_getvar (parser, "ice-name"); if (str) break; str = httpp_getvar (parser, "icy-name"); if (str) break; str = httpp_getvar (parser, "x-audiocast-name"); if (str) break; str = "Unspecified name"; } while (0); if (source->format) stats_event_conv (source->mount, "server_name", str, source->format->charset); } /* stream description */ if (mountinfo && mountinfo->stream_description) stats_event (source->mount, "server_description", mountinfo->stream_description); else { do { str = httpp_getvar (parser, "ice-description"); if (str) break; str = httpp_getvar (parser, "icy-description"); if (str) break; str = httpp_getvar (parser, "x-audiocast-description"); if (str) break; str = "Unspecified description"; } while (0); if (source->format) stats_event_conv (source->mount, "server_description", str, source->format->charset); } /* stream URL */ if (mountinfo && mountinfo->stream_url) stats_event (source->mount, "server_url", mountinfo->stream_url); else { do { str = httpp_getvar (parser, "ice-url"); if (str) break; str = httpp_getvar (parser, "icy-url"); if (str) break; str = httpp_getvar (parser, "x-audiocast-url"); if (str) break; } while (0); if (str && source->format) stats_event_conv (source->mount, "server_url", str, source->format->charset); } /* stream genre */ if (mountinfo && mountinfo->stream_genre) stats_event (source->mount, "genre", mountinfo->stream_genre); else { do { str = httpp_getvar (parser, "ice-genre"); if (str) break; str = httpp_getvar (parser, "icy-genre"); if (str) break; str = httpp_getvar (parser, "x-audiocast-genre"); if (str) break; str = "various"; } while (0); if (source->format) stats_event_conv (source->mount, "genre", str, source->format->charset); } /* stream bitrate */ if (mountinfo && mountinfo->bitrate) str = mountinfo->bitrate; else { do { str = httpp_getvar (parser, "ice-bitrate"); if (str) break; str = httpp_getvar (parser, "icy-br"); if (str) break; str = httpp_getvar (parser, "x-audiocast-bitrate"); } while (0); } stats_event (source->mount, "bitrate", str); /* handle MIME-type */ if (mountinfo && mountinfo->type) stats_event (source->mount, "server_type", mountinfo->type); else if (source->format) stats_event (source->mount, "server_type", source->format->contenttype); if (mountinfo && mountinfo->subtype) stats_event (source->mount, "subtype", mountinfo->subtype); if (mountinfo && mountinfo->auth) stats_event (source->mount, "authenticator", mountinfo->auth->type); else stats_event (source->mount, "authenticator", NULL); if (mountinfo && mountinfo->fallback_mount) { char *mount = source->fallback_mount; source->fallback_mount = strdup (mountinfo->fallback_mount); free (mount); } else source->fallback_mount = NULL; if (mountinfo && mountinfo->dumpfile) { char *filename = source->dumpfilename; source->dumpfilename = strdup (mountinfo->dumpfile); free (filename); } else source->dumpfilename = NULL; if (source->intro_file) { fclose (source->intro_file); source->intro_file = NULL; } if (mountinfo && mountinfo->intro_filename) { ice_config_t *config = config_get_config_unlocked (); unsigned int len = strlen (config->webroot_dir) + strlen (mountinfo->intro_filename) + 2; char *path = malloc (len); if (path) { FILE *f; snprintf (path, len, "%s" PATH_SEPARATOR "%s", config->webroot_dir, mountinfo->intro_filename); f = fopen (path, "rb"); if (f) source->intro_file = f; else ICECAST_LOG_WARN("Cannot open intro file \"%s\": %s", path, strerror(errno)); free (path); } } if (mountinfo && mountinfo->queue_size_limit) source->queue_size_limit = mountinfo->queue_size_limit; if (mountinfo && mountinfo->source_timeout) source->timeout = mountinfo->source_timeout; if (mountinfo && mountinfo->burst_size >= 0) source->burst_size = (unsigned int)mountinfo->burst_size; if (mountinfo && mountinfo->fallback_when_full) source->fallback_when_full = mountinfo->fallback_when_full; avl_tree_unlock (source->client_tree); } /* update the specified source with details from the config or mount. * mountinfo can be NULL in which case default settings should be taken * This function is called by the Slave thread */ void source_update_settings (ice_config_t *config, source_t *source, mount_proxy *mountinfo) { thread_mutex_lock(&source->lock); /* skip if source is a fallback to file */ if (source->running && source->client == NULL) { stats_event_hidden (source->mount, NULL, 1); thread_mutex_unlock(&source->lock); return; } /* set global settings first */ source->queue_size_limit = config->queue_size_limit; source->timeout = config->source_timeout; source->burst_size = config->burst_size; stats_event_args (source->mount, "listenurl", "http://%s:%d%s", config->hostname, config->port, source->mount); source_apply_mount (source, mountinfo); if (source->fallback_mount) ICECAST_LOG_DEBUG("fallback %s", source->fallback_mount); if (mountinfo && mountinfo->intro_filename) ICECAST_LOG_DEBUG("intro file is %s", mountinfo->intro_filename); if (source->dumpfilename) ICECAST_LOG_DEBUG("Dumping stream to %s", source->dumpfilename); if (mountinfo && mountinfo->on_connect) ICECAST_LOG_DEBUG("connect script \"%s\"", mountinfo->on_connect); if (mountinfo && mountinfo->on_disconnect) ICECAST_LOG_DEBUG("disconnect script \"%s\"", mountinfo->on_disconnect); if (source->on_demand) { ICECAST_LOG_DEBUG("on_demand set"); stats_event (source->mount, "on_demand", "1"); stats_event_args (source->mount, "listeners", "%ld", source->listeners); } else stats_event (source->mount, "on_demand", NULL); if (source->hidden) { stats_event_hidden (source->mount, NULL, 1); ICECAST_LOG_DEBUG("hidden from public"); } else stats_event_hidden (source->mount, NULL, 0); if (source->max_listeners == -1) stats_event (source->mount, "max_listeners", "unlimited"); else { char buf [10]; snprintf (buf, sizeof (buf), "%ld", source->max_listeners); stats_event (source->mount, "max_listeners", buf); } ICECAST_LOG_DEBUG("public set to %d", source->yp_public); ICECAST_LOG_DEBUG("max listeners to %ld", source->max_listeners); ICECAST_LOG_DEBUG("queue size to %u", source->queue_size_limit); ICECAST_LOG_DEBUG("burst size to %u", source->burst_size); ICECAST_LOG_DEBUG("source timeout to %u", source->timeout); ICECAST_LOG_DEBUG("fallback_when_full to %u", source->fallback_when_full); thread_mutex_unlock(&source->lock); } void *source_client_thread (void *arg) { source_t *source = arg; stats_event_inc(NULL, "source_client_connections"); stats_event (source->mount, "listeners", "0"); source_main (source); source_free_source (source); slave_update_all_mounts(); return NULL; } void source_client_callback (client_t *client, void *arg) { const char *agent; source_t *source = arg; refbuf_t *old_data = client->refbuf; if (client->con->error) { global_lock(); global.sources--; global_unlock(); source_clear_source (source); source_free_source (source); return; } client->refbuf = old_data->associated; old_data->associated = NULL; refbuf_release (old_data); stats_event (source->mount, "source_ip", source->client->con->ip); agent = httpp_getvar (source->client->parser, "user-agent"); if (agent) stats_event (source->mount, "user_agent", agent); thread_create ("Source Thread", source_client_thread, source, THREAD_DETACHED); } #ifndef _WIN32 /* this sets up the new environment for script execution. * We ignore most failtures as we can not handle them anyway. */ static inline void __setup_empty_script_environment(void) { int i; /* close at least the first 1024 handles */ for (i = 0; i < 1024; i++) close(i); /* open null device */ i = open("/dev/null", O_RDWR); if (i != -1) { /* attach null device to stdin, stdout and stderr */ if (i != 0) dup2(i, 0); if (i != 1) dup2(i, 1); if (i != 2) dup2(i, 2); /* close null device */ if (i > 2) close(i); } } static void source_run_script (char *command, char *mountpoint) { pid_t pid, external_pid; /* do a fork twice so that the command has init as parent */ external_pid = fork(); switch (external_pid) { case 0: switch (pid = fork ()) { case -1: ICECAST_LOG_ERROR("Unable to fork %s (%s)", command, strerror (errno)); break; case 0: /* child */ if (access(command, R_OK|X_OK) != 0) { ICECAST_LOG_ERROR("Unable to run command %s (%s)", command, strerror(errno)); exit(1); } ICECAST_LOG_DEBUG("Starting command %s", command); __setup_empty_script_environment(); /* consider to add action here as well */ execl(command, command, mountpoint, (char *)NULL); exit(1); default: /* parent */ break; } exit (0); case -1: ICECAST_LOG_ERROR("Unable to fork %s", strerror (errno)); break; default: /* parent */ waitpid (external_pid, NULL, 0); break; } } #endif static void *source_fallback_file (void *arg) { char *mount = arg; char *type; char *path; unsigned int len; FILE *file = NULL; source_t *source = NULL; ice_config_t *config; http_parser_t *parser; do { if (mount == NULL || mount[0] != '/') break; config = config_get_config (); len = strlen (config->webroot_dir) + strlen (mount) + 1; path = malloc (len); if (path) snprintf (path, len, "%s%s", config->webroot_dir, mount); config_release_config (); if (path == NULL) break; file = fopen (path, "rb"); if (file == NULL) { ICECAST_LOG_WARN("unable to open file \"%s\"", path); free (path); break; } free (path); source = source_reserve (mount); if (source == NULL) { ICECAST_LOG_WARN("mountpoint \"%s\" already reserved", mount); break; } ICECAST_LOG_INFO("mountpoint %s is reserved", mount); type = fserve_content_type (mount); parser = httpp_create_parser(); httpp_initialize (parser, NULL); httpp_setvar (parser, "content-type", type); free (type); source->hidden = 1; source->yp_public = 0; source->intro_file = file; source->parser = parser; file = NULL; if (connection_complete_source (source, 0) < 0) break; source_client_thread (source); httpp_destroy (parser); } while (0); if (file) fclose (file); free (mount); return NULL; } /* rescan the mount list, so that xsl files are updated to show * unconnected but active fallback mountpoints */ void source_recheck_mounts (int update_all) { ice_config_t *config; mount_proxy *mount; avl_tree_rlock (global.source_tree); config = config_get_config(); mount = config->mounts; if (update_all) stats_clear_virtual_mounts (); for (; mount; mount = mount->next) { if (mount->mounttype != MOUNT_TYPE_NORMAL) continue; source_t *source = source_find_mount (mount->mountname); if (source) { source = source_find_mount_raw (mount->mountname); if (source) { mount_proxy *mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL); source_update_settings (config, source, mountinfo); } else if (update_all) { stats_event_hidden (mount->mountname, NULL, mount->hidden); stats_event_args (mount->mountname, "listenurl", "http://%s:%d%s", config->hostname, config->port, mount->mountname); stats_event (mount->mountname, "listeners", "0"); if (mount->max_listeners < 0) stats_event (mount->mountname, "max_listeners", "unlimited"); else stats_event_args (mount->mountname, "max_listeners", "%d", mount->max_listeners); } } else stats_event (mount->mountname, NULL, NULL); /* check for fallback to file */ if (global.running == ICECAST_RUNNING && mount->fallback_mount) { source_t *fallback = source_find_mount (mount->fallback_mount); if (fallback == NULL) { thread_create ("Fallback file thread", source_fallback_file, strdup (mount->fallback_mount), THREAD_DETACHED); } } } avl_tree_unlock (global.source_tree); config_release_config(); } icecast-2.4.2/src/util.h0000664000175000017500000000673312511160565012005 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft , */ #ifndef __UTIL_H__ #define __UTIL_H__ #define XSLT_CONTENT 1 #define HTML_CONTENT 2 #define READ_ENTIRE_HEADER 1 #define READ_LINE 0 #define MAX_LINE_LEN 512 int util_timed_wait_for_fd(sock_t fd, int timeout); int util_read_header(sock_t sock, char *buff, unsigned long len, int entire); int util_check_valid_extension(const char *uri); char *util_get_extension(const char *path); char *util_get_path_from_uri(char *uri); char *util_get_path_from_normalised_uri(const char *uri); char *util_normalise_uri(const char *uri); char *util_base64_encode(const char *data); char *util_base64_decode(const char *input); char *util_bin_to_hex(unsigned char *data, int len); char *util_url_unescape(const char *src); char *util_url_escape(const char *src); /* Function to build up a HTTP header. * out is the pointer to storage. * len is the total length of out. * offset is the offset in out we should start writing at if offset >= 0. * In this case the 'used' length is len-offset. * If offset is -1 we append at the end of out. * In this case the used length is len-strlen(out). * cache is a bool. If set allow the client to cache the content (static data). * if unset we will send no-caching headers. * status is the HTTP status code. If -1 no HTTP status header is generated. * statusmsg is the status header text. If NULL a default one * is used for the given status code. This is ignored if status is -1. * contenttype is the value for the Content-Type header. * if NULL no such header is generated. * charset is the charset for the object. If NULL no header is generated * or default is used. * datablock is random data added to the request. * If datablock is non NULL the end-of-header is appended as well as this datablock. * If datablock is NULL no end-of-header nor any data is appended. * Returns the number of bytes written or -1 on error. */ struct source_tag; /* use forward decleration so we do not need to * include that would cause other conflicts. */ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, int cache, int status, const char * statusmsg, const char * contenttype, const char * charset, const char * datablock, struct source_tag * source); /* String dictionary type, without support for NULL keys, or multiple * instances of the same key */ typedef struct _util_dict { char *key; char *val; struct _util_dict *next; } util_dict; util_dict *util_dict_new(void); void util_dict_free(util_dict *dict); /* dict, key must not be NULL. */ int util_dict_set(util_dict *dict, const char *key, const char *val); const char *util_dict_get(util_dict *dict, const char *key); char *util_dict_urlencode(util_dict *dict, char delim); #ifndef HAVE_LOCALTIME_R struct tm *localtime_r (const time_t *timep, struct tm *result); #endif char *util_conv_string (const char *string, const char *in_charset, const char *out_charset); int get_line(FILE *file, char *buf, size_t siz); #endif /* __UTIL_H__ */ icecast-2.4.2/src/fserve.h0000664000175000017500000000215612510726173012317 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FSERVE_H__ #define __FSERVE_H__ #include #include "cfgfile.h" typedef void (*fserve_callback_t)(client_t *, void *); typedef struct _fserve_t { client_t *client; FILE *file; int ready; void (*callback)(client_t *, void *); void *arg; struct _fserve_t *next; } fserve_t; void fserve_initialize(void); void fserve_shutdown(void); int fserve_client_create(client_t *httpclient, const char *path); int fserve_add_client (client_t *client, FILE *file); void fserve_add_client_callback (client_t *client, fserve_callback_t callback, void *arg); char *fserve_content_type (const char *path); void fserve_recheck_mime_types (ice_config_t *config); #endif icecast-2.4.2/src/event.c0000664000175000017500000000424712511160565012142 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifdef HAVE_CONFIG_H #include #endif #include "event.h" #include "cfgfile.h" #include "yp.h" #include "source.h" #include "refbuf.h" #include "client.h" #include "logging.h" #include "slave.h" #include "fserve.h" #include "stats.h" #define CATMODULE "event" void event_config_read(void *arg) { int ret; ice_config_t *config; ice_config_t new_config; /* reread config file */ config = config_grab_config(); /* Both to get the lock, and to be able to find out the config filename */ xmlSetGenericErrorFunc ("config", log_parse_failure); ret = config_parse_file(config->config_filename, &new_config); if(ret < 0) { ICECAST_LOG_ERROR("Error parsing config, not replacing existing config"); switch(ret) { case CONFIG_EINSANE: ICECAST_LOG_ERROR("Config filename null or blank"); break; case CONFIG_ENOROOT: ICECAST_LOG_ERROR("Root element not found in %s", config->config_filename); break; case CONFIG_EBADROOT: ICECAST_LOG_ERROR("Not an icecast2 config file: %s", config->config_filename); break; default: ICECAST_LOG_ERROR("Parse error in reading %s", config->config_filename); break; } config_release_config(); } else { config_clear(config); config_set_config(&new_config); config = config_get_config_unlocked(); restart_logging (config); yp_recheck_config (config); fserve_recheck_mime_types (config); stats_global (config); config_release_config(); slave_update_all_mounts(); } } icecast-2.4.2/src/logging.h0000664000175000017500000000503012511160565012443 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __LOGGING_H__ #define __LOGGING_H__ #include "cfgfile.h" #include "log/log.h" /* declare the global log descriptors */ extern int errorlog; extern int accesslog; extern int playlistlog; #ifdef _WIN32 #include #define __func__ strrchr (__FILE__, '\\') ? strrchr (__FILE__, '\\') + 1 : __FILE__ #endif /* ** Variadic macros for logging */ #define ICECAST_LOG_ERROR(...) log_write(errorlog, 1, CATMODULE "/", __func__, __VA_ARGS__) #define ICECAST_LOG_WARN(...) log_write(errorlog, 2, CATMODULE "/", __func__, __VA_ARGS__) #define ICECAST_LOG_INFO(...) log_write(errorlog, 3, CATMODULE "/", __func__, __VA_ARGS__) #define ICECAST_LOG_DEBUG(...) log_write(errorlog, 4, CATMODULE "/", __func__, __VA_ARGS__) /* CATMODULE is the category or module that logging messages come from. ** we set one here in cause someone forgets in the .c file. */ /*#define CATMODULE "unknown" */ /* this is the logging call to write entries to the access_log ** the combined log format is: ** ADDR USER AUTH DATE REQUEST CODE BYTES REFERER AGENT [TIME] ** ADDR = ip address of client ** USER = username if authenticated ** AUTH = auth type, not used, and set to "-" ** DATE = date in "[30/Apr/2001:01:25:34 -0700]" format ** REQUEST = request, ie "GET /live.ogg HTTP/1.0" ** CODE = response code, ie, 200 or 404 ** BYTES = total bytes of data sent (other than headers) ** REFERER = the refering URL ** AGENT = the user agent ** ** for icecast, we add on extra field at the end, which will be ** ignored by normal log parsers ** ** TIME = seconds that the connection lasted ** ** this allows you to get bitrates (BYTES / TIME) ** and figure out exact times of connections ** ** it should be noted also that events are sent on client disconnect, ** so the DATE is the timestamp of disconnection. DATE - TIME is the ** time of connection. */ #define LOGGING_FORMAT_CLF "%d/%b/%Y:%H:%M:%S %z" void logging_access(client_t *client); void logging_playlist(const char *mount, const char *metadata, long listeners); void restart_logging (ice_config_t *config); void log_parse_failure (void *ctx, const char *fmt, ...); #endif /* __LOGGING_H__ */ icecast-2.4.2/src/format_opus.c0000664000175000017500000000425312511160565013354 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, * version 2. A copy of this license is included with this source. * At your option, this specific source file can also be distributed * under the GNU GPL version 3. * * Copyright 2012, David Richards, Mozilla Foundation, * and others (see AUTHORS for details). */ /* Ogg codec handler for opus streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct source_tag source_t; #include "format_opus.h" #include "refbuf.h" #include "client.h" #define CATMODULE "format-opus" #include "logging.h" static void opus_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ogg_stream_clear (&codec->os); free (codec); } static refbuf_t *process_opus_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { refbuf_t *refbuf; if (codec->headers < 2) { ogg_packet packet; ogg_stream_pagein (&codec->os, page); while (ogg_stream_packetout (&codec->os, &packet) > 0) { /* first time around (normal case) yields comments */ codec->headers++; } /* add header page to associated list */ format_ogg_attach_header (ogg_info, page); return NULL; } refbuf = make_refbuf_with_page (page); return refbuf; } ogg_codec_t *initial_opus_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for opus codec"); if (strncmp((char *)packet.packet, "OpusHead", 8) != 0) { ogg_stream_clear (&codec->os); free (codec); return NULL; } ICECAST_LOG_INFO("seen initial opus header"); codec->process_page = process_opus_page; codec->codec_free = opus_codec_free; codec->headers = 1; format_ogg_attach_header (ogg_info, page); return codec; } icecast-2.4.2/src/format_speex.c0000664000175000017500000000453712511160565013517 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * Michael Smith , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for speex streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct source_tag source_t; #include "format_speex.h" #include "refbuf.h" #include "client.h" #define CATMODULE "format-speex" #include "logging.h" static void speex_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ogg_stream_clear (&codec->os); free (codec); } static refbuf_t *process_speex_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { refbuf_t *refbuf; if (codec->headers < 2) { ogg_packet packet; ogg_stream_pagein (&codec->os, page); while (ogg_stream_packetout (&codec->os, &packet) > 0) { /* first time around (normal case) yields comments */ codec->headers++; } /* add header page to associated list */ format_ogg_attach_header (ogg_info, page); return NULL; } refbuf = make_refbuf_with_page (page); return refbuf; } ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; SpeexHeader *header; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for speex codec"); header = speex_packet_to_header ((char*)packet.packet, packet.bytes); if (header == NULL) { ogg_stream_clear (&codec->os); free (header); free (codec); return NULL; } ICECAST_LOG_INFO("seen initial speex header"); codec->process_page = process_speex_page; codec->codec_free = speex_codec_free; codec->headers = 1; format_ogg_attach_header (ogg_info, page); free (header); return codec; } icecast-2.4.2/src/util.c0000664000175000017500000005525412511172374012003 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifndef _WIN32 #include #include #include #ifdef HAVE_POLL #include #endif #else #include #include #include #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp #endif #include "net/sock.h" #include "thread/thread.h" #include "cfgfile.h" #include "util.h" #include "compat.h" #include "refbuf.h" #include "connection.h" #include "client.h" #include "source.h" #define CATMODULE "util" #include "logging.h" /* Abstract out an interface to use either poll or select depending on which * is available (poll is preferred) to watch a single fd. * * timeout is in milliseconds. * * returns > 0 if activity on the fd occurs before the timeout. * 0 if no activity occurs * < 0 for error. */ int util_timed_wait_for_fd(sock_t fd, int timeout) { #ifdef HAVE_POLL struct pollfd ufds; ufds.fd = fd; ufds.events = POLLIN; ufds.revents = 0; return poll(&ufds, 1, timeout); #else fd_set rfds; struct timeval tv, *p=NULL; FD_ZERO(&rfds); FD_SET(fd, &rfds); if(timeout >= 0) { tv.tv_sec = timeout/1000; tv.tv_usec = (timeout % 1000)*1000; p = &tv; } return select(fd+1, &rfds, NULL, NULL, p); #endif } int util_read_header(sock_t sock, char *buff, unsigned long len, int entire) { int read_bytes, ret; unsigned long pos; char c; ice_config_t *config; int header_timeout; config = config_get_config(); header_timeout = config->header_timeout; config_release_config(); read_bytes = 1; pos = 0; ret = 0; while ((read_bytes == 1) && (pos < (len - 1))) { read_bytes = 0; if (util_timed_wait_for_fd(sock, header_timeout*1000) > 0) { if ((read_bytes = recv(sock, &c, 1, 0))) { if (c != '\r') buff[pos++] = c; if (entire) { if ((pos > 1) && (buff[pos - 1] == '\n' && buff[pos - 2] == '\n')) { ret = 1; break; } } else { if ((pos > 1) && (buff[pos - 1] == '\n')) { ret = 1; break; } } } } else { break; } } if (ret) buff[pos] = '\0'; return ret; } char *util_get_extension(const char *path) { char *ext = strrchr(path, '.'); if(ext == NULL) return ""; else return ext+1; } int util_check_valid_extension(const char *uri) { int ret = 0; char *p2; if (uri) { p2 = strrchr(uri, '.'); if (p2) { p2++; if (strncmp(p2, "xsl", strlen("xsl")) == 0) { /* Build the full path for the request, concatenating the webroot from the config. ** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch. */ ret = XSLT_CONTENT; } if (strncmp(p2, "htm", strlen("htm")) == 0) { /* Build the full path for the request, concatenating the webroot from the config. ** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch. */ ret = HTML_CONTENT; } if (strncmp(p2, "html", strlen("html")) == 0) { /* Build the full path for the request, concatenating the webroot from the config. ** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch. */ ret = HTML_CONTENT; } } } return ret; } static int hex(char c) { if(c >= '0' && c <= '9') return c - '0'; else if(c >= 'A' && c <= 'F') return c - 'A' + 10; else if(c >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; } static int verify_path(char *path) { int dir = 0, indotseq = 0; while(*path) { if(*path == '/' || *path == '\\') { if(indotseq) return 0; if(dir) return 0; dir = 1; path++; continue; } if(dir || indotseq) { if(*path == '.') indotseq = 1; else indotseq = 0; } dir = 0; path++; } return 1; } char *util_get_path_from_uri(char *uri) { char *path = util_normalise_uri(uri); char *fullpath; if(!path) return NULL; else { fullpath = util_get_path_from_normalised_uri(path); free(path); return fullpath; } } char *util_get_path_from_normalised_uri(const char *uri) { char *fullpath; char *webroot; ice_config_t *config = config_get_config(); webroot = config->webroot_dir; fullpath = malloc(strlen(uri) + strlen(webroot) + 1); if (fullpath) sprintf (fullpath, "%s%s", webroot, uri); config_release_config(); return fullpath; } static char hexchars[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; static char safechars[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; char *util_url_escape (const char *src) { size_t len; char *dst; unsigned char *source = (unsigned char *)src; size_t i, j; if (!src) return NULL; len = strlen(src); /* Efficiency not a big concern here, keep the code simple/conservative */ dst = calloc(1, len*3 + 1); for(i = 0, j = 0; i < len; i++) { if(safechars[source[i]]) { dst[j++] = source[i]; } else { dst[j++] = '%'; dst[j++] = hexchars[(source[i] >> 4) & 0x0F]; dst[j++] = hexchars[ source[i] & 0x0F]; } } dst[j] = 0; return dst; } char *util_url_unescape (const char *src) { int len = strlen(src); char *decoded; int i; char *dst; int done = 0; decoded = calloc(1, len + 1); dst = decoded; for(i=0; i < len; i++) { switch(src[i]) { case '%': if(i+2 >= len) { free(decoded); return NULL; } if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) { free(decoded); return NULL; } *dst++ = hex(src[i+1]) * 16 + hex(src[i+2]); i+= 2; break; case '#': done = 1; break; case 0: ICECAST_LOG_ERROR("Fatal internal logic error in util_url_unescape()"); free(decoded); return NULL; break; default: *dst++ = src[i]; break; } if(done) break; } *dst = 0; /* null terminator */ return decoded; } /* Get an absolute path (from the webroot dir) from a URI. Return NULL if the * path contains 'disallowed' sequences like foo/../ (which could be used to * escape from the webroot) or if it cannot be URI-decoded. * Caller should free the path. */ char *util_normalise_uri(const char *uri) { char *path; if(uri[0] != '/') return NULL; path = util_url_unescape(uri); if(path == NULL) { ICECAST_LOG_WARN("Error decoding URI: %s\n", uri); return NULL; } /* We now have a full URI-decoded path. Check it for allowability */ if(verify_path(path)) return path; else { ICECAST_LOG_WARN("Rejecting invalid path \"%s\"", path); free(path); return NULL; } } static char base64table[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; static signed char base64decode[256] = { -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -1, -2, -2, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2, -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 }; char *util_bin_to_hex(unsigned char *data, int len) { char *hex = malloc(len*2 + 1); int i; for(i = 0; i < len; i++) { hex[i*2] = hexchars[(data[i]&0xf0) >> 4]; hex[i*2+1] = hexchars[data[i]&0x0f]; } hex[len*2] = 0; return hex; } /* This isn't efficient, but it doesn't need to be */ char *util_base64_encode(const char *data) { int len = strlen(data); char *out = malloc(len*4/3 + 4); char *result = out; int chunk; while(len > 0) { chunk = (len >3)?3:len; *out++ = base64table[(*data & 0xFC)>>2]; *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)]; switch(chunk) { case 3: *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)]; *out++ = base64table[(*(data+2)) & 0x3F]; break; case 2: *out++ = base64table[((*(data+1) & 0x0F)<<2)]; *out++ = '='; break; case 1: *out++ = '='; *out++ = '='; break; } data += chunk; len -= chunk; } *out = 0; return result; } char *util_base64_decode(const char *data) { const unsigned char *input = (const unsigned char *)data; int len = strlen (data); char *out = malloc(len*3/4 + 5); char *result = out; signed char vals[4]; while(len > 0) { if(len < 4) { free(result); return NULL; /* Invalid Base64 data */ } vals[0] = base64decode[*input++]; vals[1] = base64decode[*input++]; vals[2] = base64decode[*input++]; vals[3] = base64decode[*input++]; if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) { len -= 4; continue; } *out++ = vals[0]<<2 | vals[1]>>4; /* vals[3] and (if that is) vals[2] can be '=' as padding, which is looked up in the base64decode table as '-1'. Check for this case, and output zero-terminators instead of characters if we've got padding. */ if(vals[2] >= 0) *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2); else *out++ = 0; if(vals[3] >= 0) *out++ = ((vals[2]&0x03)<<6) | (vals[3]); else *out++ = 0; len -= 4; } *out = 0; return result; } /* TODO, FIXME: handle memory allocation errors better. */ static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header, int status) { size_t headerlen; const char *name; const char *value; char * r = *ret; if (!header) return; do { /* filter out header's we don't use. */ if (header->status != 0 && header->status != status) continue; /* get the name of the header */ name = header->name; /* handle type of the header */ value = NULL; switch (header->type) { case HTTP_HEADER_TYPE_STATIC: value = header->value; break; } /* check data */ if (!name || !value) continue; /* append the header to the buffer */ headerlen = strlen(name) + strlen(value) + 4; *len += headerlen; r = realloc(r, *len); strcat(r, name); strcat(r, ": "); strcat(r, value); strcat(r, "\r\n"); } while ((header = header->next)); *ret = r; } static inline char * _build_headers(int status, ice_config_t *config, source_t *source) { mount_proxy *mountproxy = NULL; char *ret = NULL; size_t len = 1; if (source) mountproxy = config_find_mount(config, source->mount, MOUNT_TYPE_NORMAL); ret = calloc(1, 1); *ret = 0; _build_headers_loop(&ret, &len, config->http_headers, status); if (mountproxy && mountproxy->http_headers) _build_headers_loop(&ret, &len, mountproxy->http_headers, status); return ret; } ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, int cache, int status, const char * statusmsg, const char * contenttype, const char * charset, const char * datablock, struct source_tag * source) { const char * http_version = "1.0"; ice_config_t *config; time_t now; struct tm result; struct tm *gmtime_result; char currenttime_buffer[80]; char status_buffer[80]; char contenttype_buffer[80]; ssize_t ret; char * extra_headers; if (!out) return -1; if (offset == -1) offset = strlen (out); out += offset; len -= offset; if (status == -1) { status_buffer[0] = '\0'; } else { if (!statusmsg) { switch (status) { case 200: statusmsg = "OK"; break; case 206: statusmsg = "Partial Content"; http_version = "1.1"; break; case 400: statusmsg = "Bad Request"; break; case 401: statusmsg = "Authentication Required"; break; case 403: statusmsg = "Forbidden"; break; case 404: statusmsg = "File Not Found"; break; case 416: statusmsg = "Request Range Not Satisfiable"; break; default: statusmsg = "(unknown status code)"; break; } } snprintf (status_buffer, sizeof (status_buffer), "HTTP/%s %d %s\r\n", http_version, status, statusmsg); } if (contenttype) { if (charset) snprintf (contenttype_buffer, sizeof (contenttype_buffer), "Content-Type: %s; charset=%s\r\n", contenttype, charset); else snprintf (contenttype_buffer, sizeof (contenttype_buffer), "Content-Type: %s\r\n", contenttype); } else { contenttype_buffer[0] = '\0'; } time(&now); #ifndef _WIN32 gmtime_result = gmtime_r(&now, &result); #else /* gmtime() on W32 breaks POSIX and IS thread-safe (uses TLS) */ gmtime_result = gmtime (&now); if (gmtime_result) memcpy (&result, gmtime_result, sizeof (result)); #endif if (gmtime_result) strftime(currenttime_buffer, sizeof(currenttime_buffer), "Date: %a, %d %b %Y %X GMT\r\n", gmtime_result); else currenttime_buffer[0] = '\0'; config = config_get_config(); extra_headers = _build_headers(status, config, source); ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s%s", status_buffer, config->server_id, currenttime_buffer, contenttype_buffer, (status == 401 ? "WWW-Authenticate: Basic realm=\"Icecast2 Server\"\r\n" : ""), (cache ? "" : "Cache-Control: no-cache\r\n" "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" "Pragma: no-cache\r\n"), extra_headers, (datablock ? "\r\n" : ""), (datablock ? datablock : "")); free(extra_headers); config_release_config(); return ret; } util_dict *util_dict_new(void) { return (util_dict *)calloc(1, sizeof(util_dict)); } void util_dict_free(util_dict *dict) { util_dict *next; while (dict) { next = dict->next; if (dict->key) free (dict->key); if (dict->val) free (dict->val); free (dict); dict = next; } } const char *util_dict_get(util_dict *dict, const char *key) { while (dict) { if (!strcmp(key, dict->key)) return dict->val; dict = dict->next; } return NULL; } int util_dict_set(util_dict *dict, const char *key, const char *val) { util_dict *prev; if (!dict || !key) { ICECAST_LOG_ERROR("NULL values passed to util_dict_set()"); return 0; } prev = NULL; while (dict) { if (!dict->key || !strcmp(dict->key, key)) break; prev = dict; dict = dict->next; } if (!dict) { dict = util_dict_new(); if (!dict) { ICECAST_LOG_ERROR("unable to allocate new dictionary"); return 0; } if (prev) prev->next = dict; } if (dict->key) free (dict->val); else if (!(dict->key = strdup(key))) { if (prev) prev->next = NULL; util_dict_free (dict); ICECAST_LOG_ERROR("unable to allocate new dictionary key"); return 0; } dict->val = strdup(val); if (!dict->val) { ICECAST_LOG_ERROR("unable to allocate new dictionary value"); return 0; } return 1; } /* given a dictionary, URL-encode each val and stringify it in order as key=val&key=val... if val is set, or just key&key if val is NULL. TODO: Memory management needs overhaul. */ char *util_dict_urlencode(util_dict *dict, char delim) { char *res, *tmp; char *enc; int start = 1; for (res = NULL; dict; dict = dict->next) { /* encode key */ if (!dict->key) continue; if (start) { if (!(res = malloc(strlen(dict->key) + 1))) { return NULL; } sprintf(res, "%s", dict->key); start = 0; } else { if (!(tmp = realloc(res, strlen(res) + strlen(dict->key) + 2))) { free(res); return NULL; } else res = tmp; sprintf(res + strlen(res), "%c%s", delim, dict->key); } /* encode value */ if (!dict->val) continue; if (!(enc = util_url_escape(dict->val))) { free(res); return NULL; } if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) { free(enc); free(res); return NULL; } else res = tmp; sprintf(res + strlen(res), "=%s", enc); free(enc); } return res; } #ifndef HAVE_LOCALTIME_R struct tm *localtime_r (const time_t *timep, struct tm *result) { static mutex_t localtime_lock; static int initialised = 0; struct tm *tm; if (initialised == 0) { thread_mutex_create (&localtime_lock); initialised = 1; } thread_mutex_lock (&localtime_lock); tm = localtime (timep); memcpy (result, tm, sizeof (*result)); thread_mutex_unlock (&localtime_lock); return result; } #endif /* helper function for converting a passed string in one character set to another * we use libxml2 for this */ char *util_conv_string (const char *string, const char *in_charset, const char *out_charset) { xmlCharEncodingHandlerPtr in, out; char *ret = NULL; if (string == NULL || in_charset == NULL || out_charset == NULL) return NULL; in = xmlFindCharEncodingHandler (in_charset); out = xmlFindCharEncodingHandler (out_charset); if (in && out) { xmlBufferPtr orig = xmlBufferCreate (); xmlBufferPtr utf8 = xmlBufferCreate (); xmlBufferPtr conv = xmlBufferCreate (); ICECAST_LOG_INFO("converting metadata from %s to %s", in_charset, out_charset); xmlBufferCCat (orig, string); if (xmlCharEncInFunc (in, utf8, orig) > 0) { xmlCharEncOutFunc (out, conv, NULL); if (xmlCharEncOutFunc (out, conv, utf8) >= 0) ret = strdup ((const char *)xmlBufferContent (conv)); } xmlBufferFree (orig); xmlBufferFree (utf8); xmlBufferFree (conv); } xmlCharEncCloseFunc (in); xmlCharEncCloseFunc (out); return ret; } int get_line(FILE *file, char *buf, size_t siz) { if(fgets(buf, (int)siz, file)) { size_t len = strlen(buf); if(len > 0 && buf[len-1] == '\n') { buf[--len] = 0; if(len > 0 && buf[len-1] == '\r') buf[--len] = 0; } return 1; } return 0; } icecast-2.4.2/src/format_vorbis.c0000664000175000017500000004273012511160565013674 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for vorbis streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "refbuf.h" #include "source.h" #include "client.h" #include "format_ogg.h" #include "stats.h" #include "format.h" #define CATMODULE "format-vorbis" #include "logging.h" typedef struct vorbis_codec_tag { vorbis_info vi; vorbis_comment vc; int rebuild_comment; int stream_notify; int initial_audio_page; ogg_stream_state new_os; int page_samples_trigger; ogg_int64_t prev_granulepos; ogg_packet *prev_packet; ogg_int64_t granulepos; ogg_int64_t initial_page_granulepos; ogg_int64_t samples_in_page; int prev_window; int initial_audio_packet; ogg_page bos_page; ogg_packet *header [3]; ogg_int64_t prev_page_samples; int (*process_packet)(ogg_state_t *ogg_info, ogg_codec_t *codec); refbuf_t *(*get_buffer_page)(ogg_state_t *ogg_info, ogg_codec_t *codec); } vorbis_codec_t; static int process_vorbis_headers (ogg_state_t *ogg_info, ogg_codec_t *codec); static refbuf_t *process_vorbis_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page); static refbuf_t *process_vorbis (ogg_state_t *ogg_info, ogg_codec_t *codec); static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char *value, const char *charset); static void free_ogg_packet (ogg_packet *packet) { if (packet) { free (packet->packet); free (packet); } } static void vorbis_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *vorbis = codec->specific; ICECAST_LOG_DEBUG("freeing vorbis codec"); stats_event (ogg_info->mount, "audio_bitrate", NULL); stats_event (ogg_info->mount, "audio_channels", NULL); stats_event (ogg_info->mount, "audio_samplerate", NULL); vorbis_info_clear (&vorbis->vi); vorbis_comment_clear (&vorbis->vc); ogg_stream_clear (&codec->os); ogg_stream_clear (&vorbis->new_os); free_ogg_packet (vorbis->header[0]); free_ogg_packet (vorbis->header[1]); free_ogg_packet (vorbis->header[2]); free_ogg_packet (vorbis->prev_packet); free (vorbis->bos_page.header); free (vorbis); free (codec); } static ogg_packet *copy_ogg_packet (ogg_packet *packet) { ogg_packet *next; do { next = malloc (sizeof (ogg_packet)); if (next == NULL) break; memcpy (next, packet, sizeof (ogg_packet)); next->packet = malloc (next->bytes); if (next->packet == NULL) break; memcpy (next->packet, packet->packet, next->bytes); return next; } while (0); if (next) free (next); return NULL; } static void add_audio_packet (vorbis_codec_t *source_vorbis, ogg_packet *packet) { if (source_vorbis->initial_audio_packet) { packet->granulepos = 0; source_vorbis->initial_audio_packet = 0; } else { source_vorbis->samples_in_page += (packet->granulepos - source_vorbis->prev_granulepos); source_vorbis->prev_granulepos = packet->granulepos; source_vorbis->granulepos += source_vorbis->prev_window; } ogg_stream_packetin (&source_vorbis->new_os, packet); } static refbuf_t *get_buffer_audio (ogg_state_t *ogg_info, ogg_codec_t *codec) { refbuf_t *refbuf = NULL; ogg_page page; vorbis_codec_t *source_vorbis = codec->specific; int (*get_ogg_page)(ogg_stream_state*, ogg_page *) = ogg_stream_pageout; if (source_vorbis->samples_in_page > source_vorbis->page_samples_trigger) get_ogg_page = ogg_stream_flush; if (get_ogg_page (&source_vorbis->new_os, &page) > 0) { /* squeeze a page copy into a buffer */ source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples); source_vorbis->prev_page_samples = ogg_page_granulepos (&page); refbuf = make_refbuf_with_page (&page); } return refbuf; } static refbuf_t *get_buffer_header (ogg_state_t *ogg_info, ogg_codec_t *codec) { int headers_flushed = 0; ogg_page page; vorbis_codec_t *source_vorbis = codec->specific; while (ogg_stream_flush (&source_vorbis->new_os, &page) > 0) { format_ogg_attach_header (ogg_info, &page); headers_flushed = 1; } if (headers_flushed) { source_vorbis->get_buffer_page = get_buffer_audio; } return NULL; } static refbuf_t *get_buffer_finished (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *source_vorbis = codec->specific; ogg_page page; refbuf_t *refbuf; if (ogg_stream_flush (&source_vorbis->new_os, &page) > 0) { source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples); source_vorbis->prev_page_samples = ogg_page_granulepos (&page); refbuf = make_refbuf_with_page (&page); ICECAST_LOG_DEBUG("flushing page"); return refbuf; } ogg_stream_clear (&source_vorbis->new_os); ogg_stream_init (&source_vorbis->new_os, rand()); format_ogg_free_headers (ogg_info); source_vorbis->get_buffer_page = NULL; if (source_vorbis->prev_packet) source_vorbis->process_packet = process_vorbis_headers; else source_vorbis->process_packet = NULL; if (source_vorbis->initial_audio_packet == 0) source_vorbis->prev_window = 0; return NULL; } /* push last packet into stream marked with eos */ static void initiate_flush (vorbis_codec_t *source_vorbis) { if (source_vorbis->prev_packet) { /* insert prev_packet with eos */ ICECAST_LOG_DEBUG("adding EOS packet"); source_vorbis->prev_packet->e_o_s = 1; add_audio_packet (source_vorbis, source_vorbis->prev_packet); source_vorbis->prev_packet->e_o_s = 0; } source_vorbis->get_buffer_page = get_buffer_finished; source_vorbis->initial_audio_packet = 1; } /* process the vorbis audio packets. Here we just take each packet out * and add them into the new stream, flushing after so many samples. We * also check if an new headers are requested after each processed page */ static int process_vorbis_audio (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *source_vorbis = codec->specific; while (1) { int window; ogg_packet packet; /* now, lets extract what packets we can */ if (ogg_stream_packetout (&codec->os, &packet) <= 0) break; /* calculate granulepos for the packet */ window = vorbis_packet_blocksize (&source_vorbis->vi, &packet) / 4; source_vorbis->granulepos += window; if (source_vorbis->prev_packet) { ogg_packet *prev_packet = source_vorbis->prev_packet; add_audio_packet (source_vorbis, prev_packet); free_ogg_packet (prev_packet); /* check for short values on first initial page */ if (packet . packetno == 4) { if (source_vorbis->initial_page_granulepos < source_vorbis->granulepos) { source_vorbis->granulepos -= source_vorbis->initial_page_granulepos; source_vorbis->samples_in_page = source_vorbis->page_samples_trigger; } } /* check for long values on first page */ if (packet.granulepos == source_vorbis->initial_page_granulepos) { if (source_vorbis->initial_page_granulepos > source_vorbis->granulepos) source_vorbis->granulepos = source_vorbis->initial_page_granulepos; } if (packet.e_o_s == 0) packet . granulepos = source_vorbis->granulepos; } else { packet . granulepos = 0; } /* store the current packet details */ source_vorbis->prev_window = window; source_vorbis->prev_packet = copy_ogg_packet (&packet); if (packet.e_o_s) { initiate_flush (source_vorbis); free_ogg_packet (source_vorbis->prev_packet); source_vorbis->prev_packet = NULL; return 1; } /* allow for pages to be flushed if there's over a certain number of samples */ if (source_vorbis->samples_in_page > source_vorbis->page_samples_trigger) return 1; } if (source_vorbis->stream_notify) { initiate_flush (source_vorbis); source_vorbis->stream_notify = 0; return 1; } return -1; } /* This handles the headers at the backend, here we insert the header packets * we want for the queue. */ static int process_vorbis_headers (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *source_vorbis = codec->specific; if (source_vorbis->header [0] == NULL) return 0; ICECAST_LOG_DEBUG("Adding the 3 header packets"); ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [0]); /* NOTE: we could build a separate comment packet each time */ if (source_vorbis->rebuild_comment) { vorbis_comment vc; ogg_packet header; ice_config_t *config; vorbis_comment_init (&vc); if (ogg_info->artist) vorbis_comment_add_tag (&vc, "artist", ogg_info->artist); if (ogg_info->title) vorbis_comment_add_tag (&vc, "title", ogg_info->title); config = config_get_config(); vorbis_comment_add_tag (&vc, "server", config->server_id); config_release_config(); vorbis_commentheader_out (&vc, &header); ogg_stream_packetin (&source_vorbis->new_os, &header); vorbis_comment_clear (&vc); ogg_packet_clear (&header); } else ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [1]); ogg_stream_packetin (&source_vorbis->new_os, source_vorbis->header [2]); source_vorbis->rebuild_comment = 0; ogg_info->log_metadata = 1; source_vorbis->get_buffer_page = get_buffer_header; source_vorbis->process_packet = process_vorbis_audio; source_vorbis->granulepos = source_vorbis->prev_window; source_vorbis->initial_audio_packet = 1; return 1; } /* check if the provided BOS page is the start of a vorbis stream. If so * then setup a structure so it can be used */ ogg_codec_t *initial_vorbis_page (format_plugin_t *plugin, ogg_page *page) { ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; vorbis_codec_t *vorbis = calloc (1, sizeof (vorbis_codec_t)); ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); vorbis_info_init (&vorbis->vi); vorbis_comment_init (&vorbis->vc); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for vorbis codec"); if (vorbis_synthesis_headerin (&vorbis->vi, &vorbis->vc, &packet) < 0) { ogg_stream_clear (&codec->os); vorbis_info_clear (&vorbis->vi); vorbis_comment_clear (&vorbis->vc); free (vorbis); free (codec); return NULL; } ICECAST_LOG_INFO("seen initial vorbis header"); codec->specific = vorbis; codec->codec_free = vorbis_codec_free; codec->headers = 1; codec->name = "Vorbis"; free_ogg_packet (vorbis->header[0]); free_ogg_packet (vorbis->header[1]); free_ogg_packet (vorbis->header[2]); memset (vorbis->header, 0, sizeof (vorbis->header)); vorbis->header [0] = copy_ogg_packet (&packet); ogg_stream_init (&vorbis->new_os, rand()); codec->process_page = process_vorbis_page; codec->process = process_vorbis; plugin->set_tag = vorbis_set_tag; vorbis->bos_page.header = malloc (page->header_len + page->body_len); memcpy (vorbis->bos_page.header, page->header, page->header_len); vorbis->bos_page.header_len = page->header_len; vorbis->bos_page.body = vorbis->bos_page.header + page->header_len; memcpy (vorbis->bos_page.body, page->body, page->body_len); vorbis->bos_page.body_len = page->body_len; return codec; } /* called from the admin interface, here we update the artist/title info * and schedule a new set of header pages */ static void vorbis_set_tag (format_plugin_t *plugin, const char *tag, const char *in_value, const char *charset) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = ogg_info->codecs; vorbis_codec_t *source_vorbis; char *value; /* avoid updating if multiple codecs in use */ if (codec && codec->next == NULL) source_vorbis = codec->specific; else return; if (tag == NULL) { source_vorbis->stream_notify = 1; source_vorbis->rebuild_comment = 1; return; } value = util_conv_string (in_value, charset, "UTF-8"); if (value == NULL) value = strdup (in_value); if (strcmp (tag, "artist") == 0) { free (ogg_info->artist); ogg_info->artist = value; } else if (strcmp (tag, "title") == 0) { free (ogg_info->title); ogg_info->title = value; } else if (strcmp (tag, "song") == 0) { free (ogg_info->title); ogg_info->title = value; } else free (value); } /* main backend routine when rebuilding streams. Here we loop until we either * have a refbuf to add onto the queue, or we want more data to process. */ static refbuf_t *process_vorbis (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *source_vorbis = codec->specific; refbuf_t *refbuf; while (1) { if (source_vorbis->get_buffer_page) { refbuf = source_vorbis->get_buffer_page (ogg_info, codec); if (refbuf) return refbuf; } if (source_vorbis->process_packet && source_vorbis->process_packet (ogg_info, codec) > 0) continue; return NULL; } } /* no processing of pages, just wrap them up in a refbuf and pass * back for adding to the queue */ static refbuf_t *process_vorbis_passthru_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { return make_refbuf_with_page (page); } /* handle incoming page. as the stream is being rebuilt, we need to * add all pages from the stream before processing packets */ static refbuf_t *process_vorbis_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { ogg_packet header; vorbis_codec_t *source_vorbis = codec->specific; char *comment; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } if (codec->headers == 3) { if (source_vorbis->initial_audio_page) { source_vorbis->initial_page_granulepos = ogg_page_granulepos (page); source_vorbis->initial_audio_page = 0; } return NULL; } while (codec->headers < 3) { /* now, lets extract the packets */ ICECAST_LOG_DEBUG("processing incoming header packet (%d)", codec->headers); if (ogg_stream_packetout (&codec->os, &header) <= 0) { if (ogg_info->codecs->next) format_ogg_attach_header (ogg_info, page); return NULL; } /* change comments here if need be */ if (vorbis_synthesis_headerin (&source_vorbis->vi, &source_vorbis->vc, &header) < 0) { ogg_info->error = 1; ICECAST_LOG_WARN("Problem parsing ogg vorbis header"); return NULL; } header.granulepos = 0; source_vorbis->header [codec->headers] = copy_ogg_packet (&header); codec->headers++; } ICECAST_LOG_DEBUG("we have the header packets now"); /* if vorbis is the only codec then allow rebuilding of the streams */ if (ogg_info->codecs->next == NULL) { /* set queued vorbis pages to contain about 1/2 of a second worth of samples */ source_vorbis->page_samples_trigger = source_vorbis->vi.rate / 2; source_vorbis->process_packet = process_vorbis_headers; source_vorbis->initial_audio_page = 1; } else { format_ogg_attach_header (ogg_info, &source_vorbis->bos_page); format_ogg_attach_header (ogg_info, page); codec->process_page = process_vorbis_passthru_page; } free (ogg_info->title); comment = vorbis_comment_query (&source_vorbis->vc, "TITLE", 0); if (comment) ogg_info->title = strdup (comment); else ogg_info->title = NULL; free (ogg_info->artist); comment = vorbis_comment_query (&source_vorbis->vc, "ARTIST", 0); if (comment) ogg_info->artist = strdup (comment); else ogg_info->artist = NULL; ogg_info->log_metadata = 1; stats_event_args (ogg_info->mount, "audio_samplerate", "%ld", (long)source_vorbis->vi.rate); stats_event_args (ogg_info->mount, "audio_channels", "%ld", (long)source_vorbis->vi.channels); stats_event_args (ogg_info->mount, "audio_bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal); stats_event_args (ogg_info->mount, "ice-bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal/1000); return NULL; } icecast-2.4.2/src/Makefile.in0000664000175000017500000007071612511177305012726 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = icecast$(EXEEXT) subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_icecast_OBJECTS = cfgfile.$(OBJEXT) main.$(OBJEXT) \ logging.$(OBJEXT) sighandler.$(OBJEXT) connection.$(OBJEXT) \ global.$(OBJEXT) util.$(OBJEXT) slave.$(OBJEXT) \ source.$(OBJEXT) stats.$(OBJEXT) refbuf.$(OBJEXT) \ client.$(OBJEXT) xslt.$(OBJEXT) fserve.$(OBJEXT) \ event.$(OBJEXT) admin.$(OBJEXT) md5.$(OBJEXT) format.$(OBJEXT) \ format_ogg.$(OBJEXT) format_mp3.$(OBJEXT) \ format_midi.$(OBJEXT) format_flac.$(OBJEXT) \ format_ebml.$(OBJEXT) auth.$(OBJEXT) auth_htpasswd.$(OBJEXT) \ format_kate.$(OBJEXT) format_skeleton.$(OBJEXT) \ format_opus.$(OBJEXT) icecast_OBJECTS = $(am_icecast_OBJECTS) am__DEPENDENCIES_1 = net/libicenet.la thread/libicethread.la \ httpp/libicehttpp.la log/libicelog.la avl/libiceavl.la \ timing/libicetiming.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(icecast_SOURCES) $(EXTRA_icecast_SOURCES) DIST_SOURCES = $(icecast_SOURCES) $(EXTRA_icecast_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign SUBDIRS = avl thread httpp net log timing noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \ global.h util.h slave.h source.h stats.h refbuf.h client.h \ compat.h fserve.h xslt.h yp.h event.h md5.h \ auth.h auth_htpasswd.h auth_url.h \ format.h format_ogg.h format_mp3.h format_ebml.h \ format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \ format_kate.h format_skeleton.h format_opus.h icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \ util.c slave.c source.c stats.c refbuf.c client.c \ xslt.c fserve.c event.c admin.c md5.c \ format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \ auth.c auth_htpasswd.c format_kate.c format_skeleton.c format_opus.c EXTRA_icecast_SOURCES = yp.c \ auth_url.c \ format_vorbis.c format_theora.c format_speex.c icecast_DEPENDENCIES = @ICECAST_OPTIONAL@ net/libicenet.la thread/libicethread.la \ httpp/libicehttpp.la log/libicelog.la avl/libiceavl.la timing/libicetiming.la icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@ @KATE_LIBS@ AM_CFLAGS = @XIPH_CFLAGS@ AM_CPPFLAGS = @XIPH_CPPFLAGS@ AM_LDFLAGS = @XIPH_LDFLAGS@ @KATE_LIBS@ all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list icecast$(EXEEXT): $(icecast_OBJECTS) $(icecast_DEPENDENCIES) $(EXTRA_icecast_DEPENDENCIES) @rm -f icecast$(EXEEXT) $(AM_V_CCLD)$(LINK) $(icecast_OBJECTS) $(icecast_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/admin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_htpasswd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_url.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfgfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_ebml.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_flac.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_kate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_midi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_mp3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_ogg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_opus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_skeleton.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_speex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_theora.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_vorbis.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fserve.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refbuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sighandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slave.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xslt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yp.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(PROGRAMS) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-binPROGRAMS clean-generic clean-libtool \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/refbuf.c0000664000175000017500000000344412511160565012270 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* refbuf.c ** ** reference counting buffer implementation ** */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "refbuf.h" #define CATMODULE "refbuf" #include "logging.h" void refbuf_initialize(void) { } void refbuf_shutdown(void) { } refbuf_t *refbuf_new (unsigned int size) { refbuf_t *refbuf; refbuf = (refbuf_t *)malloc(sizeof(refbuf_t)); if (refbuf == NULL) abort(); refbuf->data = NULL; if (size) { refbuf->data = malloc (size); if (refbuf->data == NULL) abort(); } refbuf->len = size; refbuf->sync_point = 0; refbuf->_count = 1; refbuf->next = NULL; refbuf->associated = NULL; return refbuf; } void refbuf_addref(refbuf_t *self) { self->_count++; } static void refbuf_release_associated (refbuf_t *ref) { if (ref == NULL) return; while (ref) { refbuf_t *to_go = ref; ref = to_go->next; if ( to_go->_count == 1 ) to_go->next = NULL; refbuf_release (to_go); } } void refbuf_release(refbuf_t *self) { if (self == NULL) return; self->_count--; if (self->_count == 0) { refbuf_release_associated (self->associated); if (self->next) ICECAST_LOG_ERROR("next not null"); free(self->data); free(self); } } icecast-2.4.2/src/format.h0000664000175000017500000000430612511160565012312 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* format.h ** ** format plugin header ** */ #ifndef __FORMAT_H__ #define __FORMAT_H__ #include "client.h" #include "refbuf.h" #include "httpp/httpp.h" struct source_tag; struct _mount_proxy; typedef enum _format_type_tag { FORMAT_ERROR, /* No format, source not processable */ FORMAT_TYPE_OGG, FORMAT_TYPE_EBML, FORMAT_TYPE_GENERIC } format_type_t; typedef struct _format_plugin_tag { format_type_t type; /* we need to know the mount to report statistics */ char *mount; const char *contenttype; char *charset; uint64_t read_bytes; uint64_t sent_bytes; refbuf_t *(*get_buffer)(struct source_tag *); int (*write_buf_to_client)(client_t *client); void (*write_buf_to_file)(struct source_tag *source, refbuf_t *refbuf); int (*create_client_data)(struct source_tag *source, client_t *client); void (*set_tag)(struct _format_plugin_tag *plugin, const char *tag, const char *value, const char *charset); void (*free_plugin)(struct _format_plugin_tag *self); void (*apply_settings)(client_t *client, struct _format_plugin_tag *format, struct _mount_proxy *mount); /* for internal state management */ void *_state; } format_plugin_t; format_type_t format_get_type(const char *contenttype); char *format_get_mimetype(format_type_t type); int format_get_plugin(format_type_t type, struct source_tag *source); int format_generic_write_to_client (client_t *client); int format_advance_queue (struct source_tag *source, client_t *client); int format_check_http_buffer (struct source_tag *source, client_t *client); int format_check_file_buffer (struct source_tag *source, client_t *client); void format_send_general_headers(format_plugin_t *format, struct source_tag *source, client_t *client); #endif /* __FORMAT_H__ */ icecast-2.4.2/src/slave.c0000664000175000017500000005745312511160565012142 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* slave.c * by Ciaran Anscomb * * Periodically requests a list of streams from a master server * and creates source threads for any it doesn't already have. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifndef _WIN32 #include #include #else #include #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp #endif #include "compat.h" #include #include "thread/thread.h" #include "avl/avl.h" #include "net/sock.h" #include "httpp/httpp.h" #include "cfgfile.h" #include "global.h" #include "util.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "stats.h" #include "logging.h" #include "source.h" #include "format.h" #include "event.h" #define CATMODULE "slave" static void *_slave_thread(void *arg); static thread_type *_slave_thread_id; static int slave_running = 0; static volatile int update_settings = 0; static volatile int update_all_mounts = 0; static volatile unsigned int max_interval = 0; static mutex_t _slave_mutex; // protects update_settings, update_all_mounts, max_interval relay_server *relay_free (relay_server *relay) { relay_server *next = relay->next; ICECAST_LOG_DEBUG("freeing relay %s", relay->localmount); if (relay->source) source_free_source (relay->source); xmlFree (relay->server); xmlFree (relay->mount); xmlFree (relay->localmount); if (relay->username) xmlFree (relay->username); if (relay->password) xmlFree (relay->password); free (relay); return next; } relay_server *relay_copy (relay_server *r) { relay_server *copy = calloc (1, sizeof (relay_server)); if (copy) { copy->server = (char *)xmlCharStrdup (r->server); copy->mount = (char *)xmlCharStrdup (r->mount); copy->localmount = (char *)xmlCharStrdup (r->localmount); if (r->username) copy->username = (char *)xmlCharStrdup (r->username); if (r->password) copy->password = (char *)xmlCharStrdup (r->password); copy->port = r->port; copy->mp3metadata = r->mp3metadata; copy->on_demand = r->on_demand; } return copy; } /* force a recheck of the relays. This will recheck the master server if * this is a slave and rebuild all mountpoints in the stats tree */ void slave_update_all_mounts (void) { thread_mutex_lock(&_slave_mutex); max_interval = 0; update_all_mounts = 1; update_settings = 1; thread_mutex_unlock(&_slave_mutex); } /* Request slave thread to check the relay list for changes and to * update the stats for the current streams. */ void slave_rebuild_mounts (void) { thread_mutex_lock(&_slave_mutex); update_settings = 1; thread_mutex_unlock(&_slave_mutex); } void slave_initialize(void) { if (slave_running) return; slave_running = 1; max_interval = 0; thread_mutex_create (&_slave_mutex); _slave_thread_id = thread_create("Slave Thread", _slave_thread, NULL, THREAD_ATTACHED); } void slave_shutdown(void) { if (!slave_running) return; slave_running = 0; ICECAST_LOG_DEBUG("waiting for slave thread"); thread_join (_slave_thread_id); } /* Actually open the connection and do some http parsing, handle any 302 * responses within here. */ static client_t *open_relay_connection (relay_server *relay) { int redirects = 0; char *server_id = NULL; ice_config_t *config; http_parser_t *parser = NULL; connection_t *con=NULL; char *server = strdup (relay->server); char *mount = strdup (relay->mount); int port = relay->port; char *auth_header; char header[4096]; config = config_get_config (); server_id = strdup (config->server_id); config_release_config (); /* build any authentication header before connecting */ if (relay->username && relay->password) { char *esc_authorisation; unsigned len = strlen(relay->username) + strlen(relay->password) + 2; 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); } else auth_header = strdup (""); while (redirects < 10) { sock_t streamsock; ICECAST_LOG_INFO("connecting to %s:%d", server, port); streamsock = sock_connect_wto_bind (server, port, relay->bind, 10); if (streamsock == SOCK_ERROR) { ICECAST_LOG_WARN("Failed to connect to %s:%d", server, port); break; } con = connection_create (streamsock, -1, strdup (server)); /* At this point we may not know if we are relaying an mp3 or vorbis * stream, but only send the icy-metadata header if the relay details * state so (the typical case). It's harmless in the vorbis case. If * we don't send in this header then relay will not have mp3 metadata. */ sock_write(streamsock, "GET %s HTTP/1.0\r\n" "User-Agent: %s\r\n" "Host: %s\r\n" "%s" "%s" "\r\n", mount, server_id, server, relay->mp3metadata?"Icy-MetaData: 1\r\n":"", auth_header); memset (header, 0, sizeof(header)); if (util_read_header (con->sock, header, 4096, READ_ENTIRE_HEADER) == 0) { ICECAST_LOG_ERROR("Header read failed for %s (%s:%d%s)", relay->localmount, server, port, mount); break; } parser = httpp_create_parser(); httpp_initialize (parser, NULL); if (! httpp_parse_response (parser, header, strlen(header), relay->localmount)) { ICECAST_LOG_ERROR("Error parsing relay request for %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"); ICECAST_LOG_INFO("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); con = NULL; parser = NULL; } else { client_t *client = NULL; if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE)) { ICECAST_LOG_ERROR("Error from relay request: %s (%s)", relay->localmount, httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE)); break; } global_lock (); if (client_create (&client, con, parser) < 0) { global_unlock (); /* make sure only the client_destory frees these */ con = NULL; parser = NULL; client_destroy (client); break; } global_unlock (); sock_set_blocking (streamsock, 0); client_set_queue (client, NULL); free (server); free (mount); free (server_id); free (auth_header); return client; } redirects++; } /* failed, better clean up */ free (server); free (mount); free (server_id); free (auth_header); if (con) connection_close (con); if (parser) httpp_destroy (parser); return NULL; } /* This does the actual connection for a relay. A thread is * started off if a connection can be acquired */ static void *start_relay_stream (void *arg) { relay_server *relay = arg; source_t *src = relay->source; client_t *client; ICECAST_LOG_INFO("Starting relayed source at mountpoint \"%s\"", relay->localmount); do { client = open_relay_connection (relay); if (client == NULL) continue; src->client = client; src->parser = client->parser; src->con = client->con; if (connection_complete_source (src, 0) < 0) { ICECAST_LOG_INFO("Failed to complete source initialisation"); client_destroy (client); src->client = NULL; continue; } stats_event_inc(NULL, "source_relay_connections"); stats_event (relay->localmount, "source_ip", client->con->ip); source_main (relay->source); if (relay->on_demand == 0) { /* only keep refreshing YP entries for inactive on-demand relays */ yp_remove (relay->localmount); relay->source->yp_public = -1; relay->start = time(NULL) + 10; /* prevent busy looping if failing */ slave_update_all_mounts(); } /* we've finished, now get cleaned up */ relay->cleanup = 1; slave_rebuild_mounts(); return NULL; } while (0); /* TODO allow looping through multiple servers */ if (relay->source->fallback_mount) { source_t *fallback_source; ICECAST_LOG_DEBUG("failed relay, fallback to %s", relay->source->fallback_mount); avl_tree_rlock(global.source_tree); fallback_source = source_find_mount (relay->source->fallback_mount); if (fallback_source != NULL) source_move_clients (relay->source, fallback_source); avl_tree_unlock (global.source_tree); } source_clear_source (relay->source); /* cleanup relay, but prevent this relay from starting up again too soon */ thread_mutex_lock(&_slave_mutex); thread_mutex_lock(&(config_locks()->relay_lock)); relay->source->on_demand = 0; relay->start = time(NULL) + max_interval; relay->cleanup = 1; thread_mutex_unlock(&(config_locks()->relay_lock)); thread_mutex_unlock(&_slave_mutex); return NULL; } /* wrapper for starting the provided relay stream */ static void check_relay_stream (relay_server *relay) { if (relay->source == NULL) { if (relay->localmount[0] != '/') { ICECAST_LOG_WARN("relay mountpoint \"%s\" does not start with /, skipping", relay->localmount); return; } /* new relay, reserve the name */ relay->source = source_reserve (relay->localmount); if (relay->source) { ICECAST_LOG_DEBUG("Adding relay source at mountpoint \"%s\"", relay->localmount); if (relay->on_demand) { ice_config_t *config = config_get_config (); mount_proxy *mountinfo = config_find_mount (config, relay->localmount, MOUNT_TYPE_NORMAL); if (mountinfo == NULL) source_update_settings (config, relay->source, mountinfo); config_release_config (); stats_event (relay->localmount, "listeners", "0"); slave_update_all_mounts(); } } else { if (relay->start == 0) { ICECAST_LOG_WARN("new relay but source \"%s\" already exists", relay->localmount); relay->start = 1; } return; } } do { source_t *source = relay->source; /* skip relay if active, not configured or just not time yet */ if (relay->source == NULL || relay->running || relay->start > time(NULL)) break; /* check if an inactive on-demand relay has a fallback that has listeners */ if (relay->on_demand && source->on_demand_req == 0) { relay->source->on_demand = relay->on_demand; if (source->fallback_mount && source->fallback_override) { source_t *fallback; avl_tree_rlock (global.source_tree); fallback = source_find_mount (source->fallback_mount); if (fallback && fallback->running && fallback->listeners) { ICECAST_LOG_DEBUG("fallback running %d with %lu listeners", fallback->running, fallback->listeners); source->on_demand_req = 1; } avl_tree_unlock (global.source_tree); } if (source->on_demand_req == 0) break; } relay->start = time(NULL) + 5; relay->running = 1; relay->thread = thread_create ("Relay Thread", start_relay_stream, relay, THREAD_ATTACHED); return; } while (0); /* the relay thread may of shut down itself */ if (relay->cleanup) { if (relay->thread) { ICECAST_LOG_DEBUG("waiting for relay thread for \"%s\"", relay->localmount); thread_join (relay->thread); relay->thread = NULL; } relay->cleanup = 0; relay->running = 0; if (relay->on_demand && relay->source) { ice_config_t *config = config_get_config (); mount_proxy *mountinfo = config_find_mount (config, relay->localmount, MOUNT_TYPE_NORMAL); source_update_settings (config, relay->source, mountinfo); config_release_config (); stats_event (relay->localmount, "listeners", "0"); } } } /* compare the 2 relays to see if there are any changes, return 1 if * the relay needs to be restarted, 0 otherwise */ static int relay_has_changed (relay_server *new, relay_server *old) { do { if (strcmp (new->mount, old->mount) != 0) break; if (strcmp (new->server, old->server) != 0) break; if (new->port != old->port) break; if (new->mp3metadata != old->mp3metadata) break; if (new->on_demand != old->on_demand) old->on_demand = new->on_demand; return 0; } while (0); return 1; } /* go through updated looking for relays that are different configured. The * returned list contains relays that should be kept running, current contains * the list of relays to shutdown */ static relay_server * update_relay_set (relay_server **current, relay_server *updated) { relay_server *relay = updated; relay_server *existing_relay, **existing_p; relay_server *new_list = NULL; while (relay) { existing_relay = *current; existing_p = current; while (existing_relay) { /* break out if keeping relay */ if (strcmp (relay->localmount, existing_relay->localmount) == 0) if (relay_has_changed (relay, existing_relay) == 0) break; existing_p = &existing_relay->next; existing_relay = existing_relay->next; } if (existing_relay == NULL) { /* new one, copy and insert */ existing_relay = relay_copy (relay); } else { *existing_p = existing_relay->next; } existing_relay->next = new_list; new_list = existing_relay; relay = relay->next; } return new_list; } /* update the relay_list with entries from new_relay_list. Any new relays * are added to the list, and any not listed in the provided new_relay_list * are separated and returned in a separate list */ static relay_server * update_relays (relay_server **relay_list, relay_server *new_relay_list) { relay_server *active_relays, *cleanup_relays; active_relays = update_relay_set (relay_list, new_relay_list); cleanup_relays = *relay_list; /* re-assign new set */ *relay_list = active_relays; return cleanup_relays; } static void relay_check_streams (relay_server *to_start, relay_server *to_free, int skip_timer) { relay_server *relay; while (to_free) { if (to_free->source) { if (to_free->running) { /* relay has been removed from xml, shut down active relay */ ICECAST_LOG_DEBUG("source shutdown request on \"%s\"", to_free->localmount); to_free->running = 0; to_free->source->running = 0; thread_join (to_free->thread); } else stats_event (to_free->localmount, NULL, NULL); } to_free = relay_free (to_free); } relay = to_start; while (relay) { if (skip_timer) relay->start = 0; check_relay_stream (relay); relay = relay->next; } } static int update_from_master(ice_config_t *config) { char *master = NULL, *password = NULL, *username= NULL; int port; sock_t mastersock; int ret = 0; char buf[256]; do { char *authheader, *data; relay_server *new_relays = NULL, *cleanup_relays; int len, count = 1; int on_demand; username = strdup (config->master_username); if (config->master_password) password = strdup (config->master_password); if (config->master_server) master = strdup (config->master_server); port = config->master_server_port; if (password == NULL || master == NULL || port == 0) break; on_demand = config->on_demand; ret = 1; config_release_config(); mastersock = sock_connect_wto (master, port, 10); if (mastersock == SOCK_ERROR) { ICECAST_LOG_WARN("Relay slave failed to contact master server to fetch stream list"); break; } len = strlen(username) + strlen(password) + 2; authheader = malloc(len); snprintf (authheader, len, "%s:%s", username, password); data = util_base64_encode(authheader); sock_write (mastersock, "GET /admin/streamlist.txt HTTP/1.0\r\n" "Authorization: Basic %s\r\n" "\r\n", data); free(authheader); free(data); if (sock_read_line(mastersock, buf, sizeof(buf)) == 0 || strncmp (buf, "HTTP/1.0 200", 12) != 0) { sock_close (mastersock); ICECAST_LOG_WARN("Master rejected streamlist request"); break; } while (sock_read_line(mastersock, buf, sizeof(buf))) { if (!strlen(buf)) break; } while (sock_read_line(mastersock, buf, sizeof(buf))) { relay_server *r; if (!strlen(buf)) continue; ICECAST_LOG_DEBUG("read %d from master \"%s\"", count++, buf); xmlURIPtr parsed_uri = xmlParseURI(buf); if (parsed_uri == NULL) { ICECAST_LOG_DEBUG("Error while parsing line from master. Ignoring line."); continue; } r = calloc (1, sizeof (relay_server)); if (r) { if (parsed_uri->server != NULL) { r->server = strdup(parsed_uri->server); if (parsed_uri->port == 0) r->port = 80; else r->port = parsed_uri->port; } else { r->server = (char *)xmlCharStrdup (master); r->port = port; } r->mount = strdup(parsed_uri->path); r->localmount = strdup(parsed_uri->path); r->mp3metadata = 1; r->on_demand = on_demand; r->next = new_relays; ICECAST_LOG_DEBUG("Added relay host=\"%s\", port=%d, mount=\"%s\"", r->server, r->port, r->mount); new_relays = r; } xmlFreeURI(parsed_uri); } sock_close (mastersock); thread_mutex_lock (&(config_locks()->relay_lock)); cleanup_relays = update_relays (&global.master_relays, new_relays); relay_check_streams (global.master_relays, cleanup_relays, 0); relay_check_streams (NULL, new_relays, 0); thread_mutex_unlock (&(config_locks()->relay_lock)); } while(0); if (master) free (master); if (username) free (username); if (password) free (password); return ret; } static void *_slave_thread(void *arg) { ice_config_t *config; unsigned int interval = 0; thread_mutex_lock(&_slave_mutex); update_settings = 0; update_all_mounts = 0; thread_mutex_unlock(&_slave_mutex); config = config_get_config(); stats_global (config); config_release_config(); source_recheck_mounts (1); while (1) { relay_server *cleanup_relays = NULL; int skip_timer = 0; /* re-read xml file if requested */ global_lock(); if (global . schedule_config_reread) { event_config_read (NULL); global . schedule_config_reread = 0; } global_unlock(); thread_sleep (1000000); if (slave_running == 0) break; ++interval; /* only update relays lists when required */ thread_mutex_lock(&_slave_mutex); if (max_interval <= interval) { ICECAST_LOG_DEBUG("checking master stream list"); config = config_get_config(); if (max_interval == 0) skip_timer = 1; interval = 0; max_interval = config->master_update_interval; thread_mutex_unlock(&_slave_mutex); /* the connection could take some time, so the lock can drop */ if (update_from_master (config)) config = config_get_config(); thread_mutex_lock (&(config_locks()->relay_lock)); cleanup_relays = update_relays (&global.relays, config->relay); config_release_config(); } else { thread_mutex_unlock(&_slave_mutex); thread_mutex_lock (&(config_locks()->relay_lock)); } relay_check_streams (global.relays, cleanup_relays, skip_timer); relay_check_streams (global.master_relays, NULL, skip_timer); thread_mutex_unlock (&(config_locks()->relay_lock)); thread_mutex_lock(&_slave_mutex); if (update_settings) { source_recheck_mounts (update_all_mounts); update_settings = 0; update_all_mounts = 0; } thread_mutex_unlock(&_slave_mutex); } ICECAST_LOG_INFO("shutting down current relays"); relay_check_streams (NULL, global.relays, 0); relay_check_streams (NULL, global.master_relays, 0); ICECAST_LOG_INFO("Slave thread shutdown complete"); return NULL; } icecast-2.4.2/src/auth_url.c0000664000175000017500000005357112511172374012651 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * Michael Smith , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft , */ /* * Client authentication via URL functions * * authenticate user via a URL, this is done via libcurl so https can also * be handled. The request will have POST information about the request in * the form of * * action=listener_add&client=1&server=host&port=8000&mount=/live&user=fred&pass=mypass&ip=127.0.0.1&agent="" * * For a user to be accecpted the following HTTP header needs * to be returned (the actual string can be specified in the xml file) * * icecast-auth-user: 1 * * A listening client may also be configured as only to stay connected for a * certain length of time. eg The auth server may only allow a 15 minute * playback by sending back. * * icecast-auth-timelimit: 900 * * On client disconnection another request can be sent to a URL with the POST * information of * * action=listener_remove&server=host&port=8000&client=1&mount=/live&user=fred&pass=mypass&duration=3600 * * client refers to the icecast client identification number. mount refers * to the mountpoint (beginning with / and may contain query parameters eg ?& * encoded) and duration is the amount of time in seconds. user and pass * setting can be blank * * On stream start and end, another url can be issued to help clear any user * info stored at the auth server. Useful for abnormal outage/termination * cases. * * action=mount_add&mount=/live&server=myserver.com&port=8000 * action=mount_remove&mount=/live&server=myserver.com&port=8000 * * On source client connection, a request can be made to trigger a URL request * to verify the details externally. Post info is * * action=stream_auth&mount=/stream&ip=IP&server=SERVER&port=8000&user=fred&pass=pass * * As admin requests can come in for a stream (eg metadata update) these requests * can be issued while stream is active. For these &admin=1 is added to the POST * details. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifndef _WIN32 #include #include #else #define snprintf _snprintf #define strncasecmp strnicmp #endif #include #include "auth.h" #include "source.h" #include "client.h" #include "cfgfile.h" #include "httpp/httpp.h" #include "logging.h" #define CATMODULE "auth_url" typedef struct { char *pass_headers; // headers passed from client to addurl. char *prefix_headers; // prefix for passed headers. char *addurl; char *removeurl; char *stream_start; char *stream_end; char *stream_auth; char *username; char *password; char *auth_header; int auth_header_len; char *timelimit_header; int timelimit_header_len; char *userpwd; CURL *handle; char errormsg [CURL_ERROR_SIZE]; } auth_url; static void auth_url_clear(auth_t *self) { auth_url *url; ICECAST_LOG_INFO("Doing auth URL cleanup"); url = self->state; self->state = NULL; curl_easy_cleanup (url->handle); free (url->username); free (url->password); free (url->pass_headers); free (url->prefix_headers); free (url->removeurl); free (url->addurl); free (url->stream_start); free (url->stream_end); free (url->auth_header); free (url->timelimit_header); free (url->userpwd); free (url); } #ifdef CURLOPT_PASSWDFUNCTION /* make sure that prompting at the console does not occur */ static int my_getpass(void *client, char *prompt, char *buffer, int buflen) { buffer[0] = '\0'; return 0; } #endif static size_t handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream) { auth_client *auth_user = stream; unsigned bytes = size * nmemb; client_t *client = auth_user->client; if (client) { auth_t *auth = client->auth; auth_url *url = auth->state; if (strncasecmp (ptr, url->auth_header, url->auth_header_len) == 0) client->authenticated = 1; if (strncasecmp (ptr, url->timelimit_header, url->timelimit_header_len) == 0) { unsigned int limit = 0; sscanf ((char *)ptr+url->timelimit_header_len, "%u\r\n", &limit); client->con->discon_time = time(NULL) + limit; } if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0) { char *eol; snprintf (url->errormsg, sizeof (url->errormsg), "%s", (char*)ptr+22); eol = strchr (url->errormsg, '\r'); if (eol == NULL) eol = strchr (url->errormsg, '\n'); if (eol) *eol = '\0'; } } return (int)bytes; } /* capture returned data, but don't do anything with it */ static size_t handle_returned_data (void *ptr, size_t size, size_t nmemb, void *stream) { return (int)(size*nmemb); } static auth_result url_remove_listener (auth_client *auth_user) { client_t *client = auth_user->client; auth_t *auth = client->auth; auth_url *url = auth->state; time_t duration = time(NULL) - client->con->con_time; char *username, *password, *mount, *server; const char *mountreq; ice_config_t *config; int port; char *userpwd = NULL, post [4096]; const char *agent; char *user_agent, *ipaddr; if (url->removeurl == NULL) return AUTH_OK; config = config_get_config (); server = util_url_escape (config->hostname); port = config->port; config_release_config (); agent = httpp_getvar (client->parser, "user-agent"); if (agent) user_agent = util_url_escape (agent); else user_agent = strdup ("-"); if (client->username) username = util_url_escape (client->username); else username = strdup (""); if (client->password) password = util_url_escape (client->password); else password = strdup (""); /* get the full uri (with query params if available) */ mountreq = httpp_getvar (client->parser, HTTPP_VAR_RAWURI); if (mountreq == NULL) mountreq = httpp_getvar (client->parser, HTTPP_VAR_URI); mount = util_url_escape (mountreq); ipaddr = util_url_escape (client->con->ip); snprintf (post, sizeof (post), "action=listener_remove&server=%s&port=%d&client=%lu&mount=%s" "&user=%s&pass=%s&duration=%lu&ip=%s&agent=%s", server, port, client->con->id, mount, username, password, (long unsigned)duration, ipaddr, user_agent); free (server); free (mount); free (username); free (password); free (ipaddr); free (user_agent); if (strchr (url->removeurl, '@') == NULL) { if (url->userpwd) curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd); else { /* auth'd requests may not have a user/pass, but may use query args */ if (client->username && client->password) { size_t len = strlen (client->username) + strlen (client->password) + 2; userpwd = malloc (len); snprintf (userpwd, len, "%s:%s", client->username, client->password); curl_easy_setopt (url->handle, CURLOPT_USERPWD, userpwd); } else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } } else { /* url has user/pass but libcurl may need to clear any existing settings */ curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } curl_easy_setopt (url->handle, CURLOPT_URL, url->removeurl); curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post); curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user); if (curl_easy_perform (url->handle)) ICECAST_LOG_WARN("auth to server %s failed with %s", url->removeurl, url->errormsg); free (userpwd); return AUTH_OK; } static auth_result url_add_listener (auth_client *auth_user) { client_t *client = auth_user->client; auth_t *auth = client->auth; auth_url *url = auth->state; int res = 0, port; const char *agent; char *user_agent, *username, *password; const char *mountreq; char *mount, *ipaddr, *server; ice_config_t *config; char *userpwd = NULL, post [4096]; ssize_t post_offset; char *pass_headers, *cur_header, *next_header; const char *header_val; char *header_valesc; if (url->addurl == NULL) return AUTH_OK; config = config_get_config (); server = util_url_escape (config->hostname); port = config->port; config_release_config (); agent = httpp_getvar (client->parser, "user-agent"); if (agent) user_agent = util_url_escape (agent); else user_agent = strdup ("-"); if (client->username) username = util_url_escape (client->username); else username = strdup (""); if (client->password) password = util_url_escape (client->password); else password = strdup (""); /* get the full uri (with query params if available) */ mountreq = httpp_getvar (client->parser, HTTPP_VAR_RAWURI); if (mountreq == NULL) mountreq = httpp_getvar (client->parser, HTTPP_VAR_URI); mount = util_url_escape (mountreq); ipaddr = util_url_escape (client->con->ip); post_offset = snprintf (post, sizeof (post), "action=listener_add&server=%s&port=%d&client=%lu&mount=%s" "&user=%s&pass=%s&ip=%s&agent=%s", server, port, client->con->id, mount, username, password, ipaddr, user_agent); free (server); free (mount); free (user_agent); free (username); free (password); free (ipaddr); pass_headers = NULL; if (url->pass_headers) pass_headers = strdup (url->pass_headers); if (pass_headers) { cur_header = pass_headers; while (cur_header) { next_header = strstr (cur_header, ","); if (next_header) { *next_header=0; next_header++; } header_val = httpp_getvar (client->parser, cur_header); if (header_val) { header_valesc = util_url_escape (header_val); post_offset += snprintf (post+post_offset, sizeof (post)-post_offset, "&%s%s=%s", url->prefix_headers ? url->prefix_headers : "", cur_header, header_valesc); free (header_valesc); } cur_header = next_header; } } if (strchr (url->addurl, '@') == NULL) { if (url->userpwd) curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd); else { /* auth'd requests may not have a user/pass, but may use query args */ if (client->username && client->password) { size_t len = strlen (client->username) + strlen (client->password) + 2; userpwd = malloc (len); snprintf (userpwd, len, "%s:%s", client->username, client->password); curl_easy_setopt (url->handle, CURLOPT_USERPWD, userpwd); } else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } } else { /* url has user/pass but libcurl may need to clear any existing settings */ curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } curl_easy_setopt (url->handle, CURLOPT_URL, url->addurl); curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post); curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user); url->errormsg[0] = '\0'; res = curl_easy_perform (url->handle); free (userpwd); if (res) { ICECAST_LOG_WARN("auth to server %s failed with %s", url->addurl, url->errormsg); return AUTH_FAILED; } /* we received a response, lets see what it is */ if (client->authenticated) return AUTH_OK; ICECAST_LOG_INFO("client auth (%s) failed with \"%s\"", url->addurl, url->errormsg); return AUTH_FAILED; } /* called by auth thread when a source starts, there is no client_t in * this case */ static void url_stream_start (auth_client *auth_user) { char *mount, *server; ice_config_t *config = config_get_config (); mount_proxy *mountinfo = config_find_mount (config, auth_user->mount, MOUNT_TYPE_NORMAL); auth_t *auth = mountinfo->auth; auth_url *url = auth->state; char *stream_start_url; int port; char post [4096]; if (url->stream_start == NULL) { config_release_config (); return; } server = util_url_escape (config->hostname); port = config->port; stream_start_url = strdup (url->stream_start); /* we don't want this auth disappearing from under us while * the connection is in progress */ mountinfo->auth->refcount++; config_release_config (); mount = util_url_escape (auth_user->mount); snprintf (post, sizeof (post), "action=mount_add&mount=%s&server=%s&port=%d", mount, server, port); free (server); free (mount); if (strchr (url->stream_start, '@') == NULL) { if (url->userpwd) curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd); else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); curl_easy_setopt (url->handle, CURLOPT_URL, stream_start_url); curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post); curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user); if (curl_easy_perform (url->handle)) ICECAST_LOG_WARN("auth to server %s failed with %s", stream_start_url, url->errormsg); auth_release (auth); free (stream_start_url); return; } static void url_stream_end (auth_client *auth_user) { char *mount, *server; ice_config_t *config = config_get_config (); mount_proxy *mountinfo = config_find_mount (config, auth_user->mount, MOUNT_TYPE_NORMAL); auth_t *auth = mountinfo->auth; auth_url *url = auth->state; char *stream_end_url; int port; char post [4096]; if (url->stream_end == NULL) { config_release_config (); return; } server = util_url_escape (config->hostname); port = config->port; stream_end_url = strdup (url->stream_end); /* we don't want this auth disappearing from under us while * the connection is in progress */ mountinfo->auth->refcount++; config_release_config (); mount = util_url_escape (auth_user->mount); snprintf (post, sizeof (post), "action=mount_remove&mount=%s&server=%s&port=%d", mount, server, port); free (server); free (mount); if (strchr (url->stream_end, '@') == NULL) { if (url->userpwd) curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd); else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); curl_easy_setopt (url->handle, CURLOPT_URL, url->stream_end); curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post); curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user); if (curl_easy_perform (url->handle)) ICECAST_LOG_WARN("auth to server %s failed with %s", stream_end_url, url->errormsg); auth_release (auth); free (stream_end_url); return; } static void url_stream_auth (auth_client *auth_user) { ice_config_t *config; int port; client_t *client = auth_user->client; auth_url *url = client->auth->state; char *mount, *host, *user, *pass, *ipaddr, *admin=""; char post [4096]; if (strchr (url->stream_auth, '@') == NULL) { if (url->userpwd) curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd); else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); } else curl_easy_setopt (url->handle, CURLOPT_USERPWD, ""); curl_easy_setopt (url->handle, CURLOPT_URL, url->stream_auth); curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post); curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user); if (strcmp (auth_user->mount, httpp_getvar (client->parser, HTTPP_VAR_URI)) != 0) admin = "&admin=1"; mount = util_url_escape (auth_user->mount); config = config_get_config (); host = util_url_escape (config->hostname); port = config->port; config_release_config (); ipaddr = util_url_escape (client->con->ip); if (client->username) { user = util_url_escape(client->username); } else { user = strdup(""); } if (client->password) { pass = util_url_escape(client->password); } else { pass = strdup(""); } snprintf (post, sizeof (post), "action=stream_auth&mount=%s&ip=%s&server=%s&port=%d&user=%s&pass=%s%s", mount, ipaddr, host, port, user, pass, admin); free (ipaddr); free (user); free (pass); free (mount); free (host); client->authenticated = 0; if (curl_easy_perform (url->handle)) ICECAST_LOG_WARN("auth to server %s failed with %s", url->stream_auth, url->errormsg); } static auth_result auth_url_adduser(auth_t *auth, const char *username, const char *password) { return AUTH_FAILED; } static auth_result auth_url_deleteuser (auth_t *auth, const char *username) { return AUTH_FAILED; } static auth_result auth_url_listuser (auth_t *auth, xmlNodePtr srcnode) { return AUTH_FAILED; } int auth_get_url_auth (auth_t *authenticator, config_options_t *options) { auth_url *url_info; authenticator->free = auth_url_clear; authenticator->adduser = auth_url_adduser; authenticator->deleteuser = auth_url_deleteuser; authenticator->listuser = auth_url_listuser; url_info = calloc(1, sizeof(auth_url)); authenticator->state = url_info; /* default headers */ url_info->auth_header = strdup ("icecast-auth-user: 1\r\n"); url_info->timelimit_header = strdup ("icecast-auth-timelimit:"); /* force auth thread to call function. this makes sure the auth_t is attached to client */ authenticator->authenticate = url_add_listener; while(options) { if(!strcmp(options->name, "username")) { free (url_info->username); url_info->username = strdup (options->value); } if(!strcmp(options->name, "password")) { free (url_info->password); url_info->password = strdup (options->value); } if(!strcmp(options->name, "headers")) { free (url_info->pass_headers); url_info->pass_headers = strdup (options->value); } if(!strcmp(options->name, "header_prefix")) { free (url_info->prefix_headers); url_info->prefix_headers = strdup (options->value); } if(!strcmp(options->name, "listener_add")) { free (url_info->addurl); url_info->addurl = strdup (options->value); } if(!strcmp(options->name, "listener_remove")) { authenticator->release_listener = url_remove_listener; free (url_info->removeurl); url_info->removeurl = strdup (options->value); } if(!strcmp(options->name, "mount_add")) { authenticator->stream_start = url_stream_start; free (url_info->stream_start); url_info->stream_start = strdup (options->value); } if(!strcmp(options->name, "mount_remove")) { authenticator->stream_end = url_stream_end; free (url_info->stream_end); url_info->stream_end = strdup (options->value); } if(!strcmp(options->name, "stream_auth")) { authenticator->stream_auth = url_stream_auth; free (url_info->stream_auth); url_info->stream_auth = strdup (options->value); } if(!strcmp(options->name, "auth_header")) { free (url_info->auth_header); url_info->auth_header = strdup (options->value); } if (strcmp(options->name, "timelimit_header") == 0) { free (url_info->timelimit_header); url_info->timelimit_header = strdup (options->value); } options = options->next; } url_info->handle = curl_easy_init (); if (url_info->handle == NULL) { auth_url_clear (authenticator); return -1; } if (url_info->auth_header) url_info->auth_header_len = strlen (url_info->auth_header); if (url_info->timelimit_header) url_info->timelimit_header_len = strlen (url_info->timelimit_header); curl_easy_setopt (url_info->handle, CURLOPT_USERAGENT, ICECAST_VERSION_STRING); curl_easy_setopt (url_info->handle, CURLOPT_HEADERFUNCTION, handle_returned_header); curl_easy_setopt (url_info->handle, CURLOPT_WRITEFUNCTION, handle_returned_data); curl_easy_setopt (url_info->handle, CURLOPT_WRITEDATA, url_info->handle); curl_easy_setopt (url_info->handle, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (url_info->handle, CURLOPT_TIMEOUT, 15L); #ifdef CURLOPT_PASSWDFUNCTION curl_easy_setopt (url_info->handle, CURLOPT_PASSWDFUNCTION, my_getpass); #endif curl_easy_setopt (url_info->handle, CURLOPT_ERRORBUFFER, &url_info->errormsg[0]); if (url_info->username && url_info->password) { int len = strlen (url_info->username) + strlen (url_info->password) + 2; url_info->userpwd = malloc (len); snprintf (url_info->userpwd, len, "%s:%s", url_info->username, url_info->password); } ICECAST_LOG_INFO("URL based authentication setup"); return 0; } icecast-2.4.2/src/sighandler.h0000664000175000017500000000105012510726173013135 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __SIGHANDLER_H__ #define __SIGHANDLER_H__ void sighandler_initialize(void); #endif /* __SIGHANDLER_H__ */ icecast-2.4.2/src/format_ogg.c0000664000175000017500000003640512511160565013146 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* format_ogg.c * * format plugin for Ogg * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "refbuf.h" #include "source.h" #include "client.h" #include "stats.h" #include "format.h" #include "format_ogg.h" #include "format_vorbis.h" #ifdef HAVE_THEORA #include "format_theora.h" #endif #ifdef HAVE_SPEEX #include "format_speex.h" #endif #include "format_opus.h" #include "format_midi.h" #include "format_flac.h" #include "format_kate.h" #include "format_skeleton.h" #ifdef _WIN32 #define snprintf _snprintf #endif #define CATMODULE "format-ogg" #include "logging.h" struct _ogg_state_tag; static void format_ogg_free_plugin (format_plugin_t *plugin); static int create_ogg_client_data(source_t *source, client_t *client); static void free_ogg_client_data (client_t *client); static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf); static refbuf_t *ogg_get_buffer (source_t *source); static int write_buf_to_client (client_t *client); struct ogg_client { refbuf_t *headers; refbuf_t *header_page; unsigned pos; int headers_sent; }; refbuf_t *make_refbuf_with_page (ogg_page *page) { refbuf_t *refbuf = refbuf_new (page->header_len + page->body_len); memcpy (refbuf->data, page->header, page->header_len); memcpy (refbuf->data+page->header_len, page->body, page->body_len); return refbuf; } /* routine for taking the provided page (should be a header page) and * placing it on the collection of header pages */ void format_ogg_attach_header (ogg_state_t *ogg_info, ogg_page *page) { refbuf_t *refbuf = make_refbuf_with_page (page); if (ogg_page_bos (page)) { ICECAST_LOG_DEBUG("attaching BOS page"); if (*ogg_info->bos_end == NULL) ogg_info->header_pages_tail = refbuf; refbuf->next = *ogg_info->bos_end; *ogg_info->bos_end = refbuf; ogg_info->bos_end = &refbuf->next; return; } ICECAST_LOG_DEBUG("attaching header page"); if (ogg_info->header_pages_tail) ogg_info->header_pages_tail->next = refbuf; ogg_info->header_pages_tail = refbuf; if (ogg_info->header_pages == NULL) ogg_info->header_pages = refbuf; } void format_ogg_free_headers (ogg_state_t *ogg_info) { refbuf_t *header; /* release the header pages first */ ICECAST_LOG_DEBUG("releasing header pages"); header = ogg_info->header_pages; while (header) { refbuf_t *to_release = header; header = header->next; refbuf_release (to_release); } ogg_info->header_pages = NULL; ogg_info->header_pages_tail = NULL; ogg_info->bos_end = &ogg_info->header_pages; } /* release the memory used for the codec and header pages from the module */ static void free_ogg_codecs (ogg_state_t *ogg_info) { ogg_codec_t *codec; if (ogg_info == NULL) return; format_ogg_free_headers (ogg_info); /* now free the codecs */ codec = ogg_info->codecs; ICECAST_LOG_DEBUG("freeing codecs"); while (codec) { ogg_codec_t *next = codec->next; if (codec->possible_start) refbuf_release (codec->possible_start); codec->codec_free (ogg_info, codec); codec = next; } ogg_info->codecs = NULL; ogg_info->current = NULL; ogg_info->bos_completed = 0; ogg_info->codec_count = 0; } int format_ogg_get_plugin (source_t *source) { format_plugin_t *plugin; ogg_state_t *state = calloc (1, sizeof (ogg_state_t)); plugin = (format_plugin_t *)calloc(1, sizeof(format_plugin_t)); plugin->type = FORMAT_TYPE_OGG; plugin->get_buffer = ogg_get_buffer; plugin->write_buf_to_client = write_buf_to_client; plugin->write_buf_to_file = write_ogg_to_file; plugin->create_client_data = create_ogg_client_data; plugin->free_plugin = format_ogg_free_plugin; plugin->set_tag = NULL; if (strcmp (httpp_getvar (source->parser, "content-type"), "application/x-ogg") == 0) httpp_setvar (source->parser, "content-type", "application/ogg"); plugin->contenttype = httpp_getvar (source->parser, "content-type"); ogg_sync_init (&state->oy); plugin->_state = state; source->format = plugin; state->mount = source->mount; state->bos_end = &state->header_pages; return 0; } static void format_ogg_free_plugin (format_plugin_t *plugin) { ogg_state_t *state = plugin->_state; /* free memory associated with this plugin instance */ free_ogg_codecs (state); free (state->artist); free (state->title); ogg_sync_clear (&state->oy); free (state); free (plugin); } /* a new BOS page has been seen so check which codec it is */ static int process_initial_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec; if (ogg_info->bos_completed) { ogg_info->bitrate = 0; ogg_info->codec_sync = NULL; /* need to zap old list of codecs when next group of BOS pages appear */ free_ogg_codecs (ogg_info); } do { if (ogg_info->codec_count > 10) { ICECAST_LOG_ERROR("many codecs in stream, playing safe, dropping source"); ogg_info->error = 1; return -1; } codec = initial_vorbis_page (plugin, page); if (codec) break; #ifdef HAVE_THEORA codec = initial_theora_page (plugin, page); if (codec) break; #endif codec = initial_midi_page (plugin, page); if (codec) break; codec = initial_flac_page (plugin, page); if (codec) break; #ifdef HAVE_SPEEX codec = initial_speex_page (plugin, page); if (codec) break; #endif codec = initial_kate_page (plugin, page); if (codec) break; codec = initial_skeleton_page (plugin, page); if (codec) break; codec = initial_opus_page (plugin, page); if (codec) break; /* any others */ ICECAST_LOG_ERROR("Seen BOS page with unknown type"); ogg_info->error = 1; return -1; } while (0); if (codec) { /* add codec to list */ codec->next = ogg_info->codecs; ogg_info->codecs = codec; ogg_info->codec_count++; } return 0; } /* This is called when there has been a change in the metadata. Usually * artist and title are provided separately so here we update the stats * and write log entry if required. */ static void update_comments (source_t *source) { ogg_state_t *ogg_info = source->format->_state; char *title = ogg_info->title; char *artist = ogg_info->artist; char *metadata = NULL; unsigned int len = 1; /* space for the nul byte at least */ ogg_codec_t *codec; char codec_names [100] = ""; if (ogg_info->artist) { if (title) { len += strlen(artist) + strlen(title) + 3; metadata = calloc (1, len); snprintf (metadata, len, "%s - %s", artist, title); } else { len += strlen(artist); metadata = calloc (1, len); snprintf (metadata, len, "%s", artist); } } else { if (title) { len += strlen (title); metadata = calloc (1, len); snprintf (metadata, len, "%s", title); } } if (metadata) { logging_playlist (source->mount, metadata, source->listeners); free (metadata); } stats_event (source->mount, "artist", artist); stats_event (source->mount, "title", title); codec = ogg_info->codecs; while (codec) { if (codec->name) { int len = strlen (codec_names); int remaining = sizeof (codec_names) - len; char *where = codec_names + len; char *separator = "/"; if (len == 0) separator = ""; snprintf (where, remaining, "%s%s", separator, codec->name); } codec = codec->next; } stats_event (source->mount, "subtype", codec_names); yp_touch (source->mount); } /* called when preparing a refbuf with audio data to be passed * back for queueing */ static refbuf_t *complete_buffer (source_t *source, refbuf_t *refbuf) { ogg_state_t *ogg_info = source->format->_state; refbuf_t *header = ogg_info->header_pages; while (header) { refbuf_addref (header); header = header->next; } refbuf->associated = ogg_info->header_pages; if (ogg_info->log_metadata) { update_comments (source); ogg_info->log_metadata = 0; } /* listeners can start anywhere unless the codecs themselves are * marking starting points */ if (ogg_info->codec_sync == NULL) refbuf->sync_point = 1; return refbuf; } /* process the incoming page. this requires searching through the * currently known codecs that have been seen in the stream */ static refbuf_t *process_ogg_page (ogg_state_t *ogg_info, ogg_page *page) { ogg_codec_t *codec = ogg_info->codecs; refbuf_t *refbuf = NULL; while (codec) { if (ogg_page_serialno (page) == codec->os.serialno) { if (codec->process_page) refbuf = codec->process_page (ogg_info, codec, page); break; } codec = codec->next; } ogg_info->current = codec; return refbuf; } /* main plugin handler for getting a buffer for the queue. In here we * just add an incoming page to the codecs and process it until either * more data is needed or we prodice a buffer for the queue. */ static refbuf_t *ogg_get_buffer (source_t *source) { ogg_state_t *ogg_info = source->format->_state; format_plugin_t *format = source->format; char *data = NULL; int bytes = 0; while (1) { while (1) { ogg_page page; refbuf_t *refbuf = NULL; ogg_codec_t *codec = ogg_info->current; /* if a codec has just been given a page then process it */ if (codec && codec->process) { refbuf = codec->process (ogg_info, codec); if (refbuf) return complete_buffer (source, refbuf); ogg_info->current = NULL; } if (ogg_sync_pageout (&ogg_info->oy, &page) > 0) { if (ogg_page_bos (&page)) { process_initial_page (source->format, &page); } else { ogg_info->bos_completed = 1; refbuf = process_ogg_page (ogg_info, &page); } if (ogg_info->error) { ICECAST_LOG_ERROR("Problem processing stream"); source->running = 0; return NULL; } if (refbuf) return complete_buffer (source, refbuf); continue; } /* need more stream data */ break; } /* we need more data to continue getting pages */ data = ogg_sync_buffer (&ogg_info->oy, 4096); bytes = client_read_bytes (source->client, data, 4096); if (bytes <= 0) { ogg_sync_wrote (&ogg_info->oy, 0); return NULL; } format->read_bytes += bytes; ogg_sync_wrote (&ogg_info->oy, bytes); } } static int create_ogg_client_data (source_t *source, client_t *client) { struct ogg_client *client_data = calloc (1, sizeof (struct ogg_client)); int ret = -1; if (client_data) { client_data->headers_sent = 1; client->format_data = client_data; client->free_client_data = free_ogg_client_data; ret = 0; } return ret; } static void free_ogg_client_data (client_t *client) { free (client->format_data); client->format_data = NULL; } /* send out the header pages. These are for all codecs but are * in the order for the stream, ie BOS pages first */ static int send_ogg_headers (client_t *client, refbuf_t *headers) { struct ogg_client *client_data = client->format_data; refbuf_t *refbuf; int written = 0; if (client_data->headers_sent) { client_data->header_page = headers; client_data->pos = 0; client_data->headers_sent = 0; } refbuf = client_data->header_page; while (refbuf) { char *data = refbuf->data + client_data->pos; unsigned len = refbuf->len - client_data->pos; int ret; ret = client_send_bytes (client, data, len); if (ret > 0) written += ret; if (ret < (int)len) return written ? written : -1; client_data->pos += ret; if (client_data->pos == refbuf->len) { refbuf = refbuf->next; client_data->header_page = refbuf; client_data->pos = 0; } } client_data->headers_sent = 1; client_data->headers = headers; return written; } /* main client write routine for sending ogg data. Each refbuf has a * single page so we only need to determine if there are new headers */ static int write_buf_to_client (client_t *client) { refbuf_t *refbuf = client->refbuf; char *buf = refbuf->data + client->pos; unsigned len = refbuf->len - client->pos; struct ogg_client *client_data = client->format_data; int ret, written = 0; do { if (client_data->headers != refbuf->associated) { ret = send_ogg_headers (client, refbuf->associated); if (client_data->headers_sent == 0) break; written += ret; } ret = client_send_bytes (client, buf, len); if (ret > 0) client->pos += ret; if (ret < (int)len) break; written += ret; /* we have now written the page(s) */ ret = 0; } while (0); if (ret > 0) written += ret; return written; } static int write_ogg_data (struct source_tag *source, refbuf_t *refbuf) { int ret = 1; if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) != refbuf->len) { ICECAST_LOG_WARN("Write to dump file failed, disabling"); fclose (source->dumpfile); source->dumpfile = NULL; ret = 0; } return ret; } static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf) { ogg_state_t *ogg_info = source->format->_state; if (ogg_info->file_headers != refbuf->associated) { refbuf_t *header = refbuf->associated; while (header) { if (write_ogg_data (source, header) == 0) return; header = header->next; } ogg_info->file_headers = refbuf->associated; } write_ogg_data (source, refbuf); } icecast-2.4.2/src/auth_htpasswd.h0000664000175000017500000000115412511160565013676 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __AUTH_HTPASSWD_H__ #define __AUTH_HTPASSWD_H__ #ifdef HAVE_CONFIG_H #include #endif int auth_get_htpasswd_auth (auth_t *auth, config_options_t *options); #endif icecast-2.4.2/src/auth_htpasswd.c0000664000175000017500000002575712511160565013710 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /** * Client authentication functions */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "auth.h" #include "source.h" #include "client.h" #include "cfgfile.h" #include "httpp/httpp.h" #include "md5.h" #include "logging.h" #define CATMODULE "auth_htpasswd" #ifdef WIN32 #define snprintf _snprintf #endif static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password); static auth_result htpasswd_deleteuser(auth_t *auth, const char *username); static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode); static int _free_user (void *key); typedef struct { char *name; char *pass; } htpasswd_user; typedef struct { char *filename; rwlock_t file_rwlock; avl_tree *users; time_t mtime; } htpasswd_auth_state; static void htpasswd_clear(auth_t *self) { htpasswd_auth_state *state = self->state; free(state->filename); if (state->users) avl_tree_free (state->users, _free_user); thread_rwlock_destroy(&state->file_rwlock); free(state); } /* md5 hash */ static char *get_hash(const char *data, int len) { struct MD5Context context; unsigned char digest[16]; MD5Init(&context); MD5Update(&context, (const unsigned char *)data, len); MD5Final(digest, &context); return util_bin_to_hex(digest, 16); } static int compare_users (void *arg, void *a, void *b) { htpasswd_user *user1 = (htpasswd_user *)a; htpasswd_user *user2 = (htpasswd_user *)b; return strcmp (user1->name, user2->name); } static int _free_user (void *key) { htpasswd_user *user = (htpasswd_user *)key; free (user->name); /* ->pass is part of same buffer */ free (user); return 1; } 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 (htpasswd->filename == NULL) return; if (stat (htpasswd->filename, &file_stat) < 0) { ICECAST_LOG_WARN("failed to check status of %s", htpasswd->filename); /* Create a dummy users tree for things to use later */ thread_rwlock_wlock (&htpasswd->file_rwlock); if(!htpasswd->users) htpasswd->users = avl_tree_new(compare_users, NULL); thread_rwlock_unlock (&htpasswd->file_rwlock); return; } if (file_stat.st_mtime == htpasswd->mtime) { /* common case, no update to file */ return; } ICECAST_LOG_INFO("re-reading htpasswd file \"%s\"", htpasswd->filename); passwdfile = fopen (htpasswd->filename, "rb"); if (passwdfile == NULL) { ICECAST_LOG_WARN("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) { ICECAST_LOG_WARN("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); } static auth_result htpasswd_auth (auth_client *auth_user) { auth_t *auth = auth_user->client->auth; htpasswd_auth_state *htpasswd = auth->state; client_t *client = auth_user->client; htpasswd_user entry; void *result; if (client->username == NULL || client->password == NULL) return AUTH_FAILED; if (htpasswd->filename == NULL) { ICECAST_LOG_ERROR("No filename given in options for authenticator."); return AUTH_FAILED; } htpasswd_recheckfile (htpasswd); thread_rwlock_rlock (&htpasswd->file_rwlock); entry.name = client->username; if (avl_get_by_key (htpasswd->users, &entry, &result) == 0) { htpasswd_user *found = result; char *hashed_pw; thread_rwlock_unlock (&htpasswd->file_rwlock); hashed_pw = get_hash (client->password, strlen (client->password)); if (strcmp (found->pass, hashed_pw) == 0) { free (hashed_pw); return AUTH_OK; } free (hashed_pw); ICECAST_LOG_DEBUG("incorrect password for client"); return AUTH_FAILED; } ICECAST_LOG_DEBUG("no such username: %s", client->username); thread_rwlock_unlock (&htpasswd->file_rwlock); return AUTH_FAILED; } int auth_get_htpasswd_auth (auth_t *authenticator, config_options_t *options) { htpasswd_auth_state *state; authenticator->authenticate = htpasswd_auth; authenticator->free = htpasswd_clear; authenticator->adduser = htpasswd_adduser; authenticator->deleteuser = htpasswd_deleteuser; authenticator->listuser = htpasswd_userlist; state = calloc(1, sizeof(htpasswd_auth_state)); while(options) { if(!strcmp(options->name, "filename")) { free (state->filename); state->filename = strdup(options->value); } options = options->next; } if (state->filename) ICECAST_LOG_INFO("Configured htpasswd authentication using password file \"%s\"", state->filename); else ICECAST_LOG_ERROR("No filename given in options for authenticator."); authenticator->state = state; thread_rwlock_create(&state->file_rwlock); htpasswd_recheckfile (state); return 0; } 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); ICECAST_LOG_WARN("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; } 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) { ICECAST_LOG_WARN("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) { ICECAST_LOG_WARN("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) { ICECAST_LOG_WARN("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) { ICECAST_LOG_DEBUG("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) { ICECAST_LOG_ERROR("Problem moving temp authentication file to original \"%s\" - \"%s\": %s", tmpfile, state->filename, strerror(errno)); } else { if (rename(tmpfile, state->filename) != 0) { ICECAST_LOG_ERROR("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; } static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode) { htpasswd_auth_state *state; xmlNodePtr newnode; avl_node *node; state = auth->state; htpasswd_recheckfile (state); thread_rwlock_rlock (&state->file_rwlock); node = avl_get_first (state->users); while (node) { htpasswd_user *user = (htpasswd_user *)node->key; newnode = xmlNewChild (srcnode, NULL, XMLSTR("User"), NULL); xmlNewChild(newnode, NULL, XMLSTR("username"), XMLSTR(user->name)); xmlNewChild(newnode, NULL, XMLSTR("password"), XMLSTR(user->pass)); node = avl_get_next (node); } thread_rwlock_unlock (&state->file_rwlock); return AUTH_OK; } icecast-2.4.2/src/format_mp3.h0000664000175000017500000000203312511160565013064 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* format_mp3.h ** ** mp3 format plugin ** */ #ifndef __FORMAT_MP3_H__ #define __FORMAT_MP3_H__ typedef struct { /* These are for inline metadata */ int inline_metadata_interval; int offset; int interval; char *url_artist; char *url_title; char *url; char *inline_url; int update_metadata; refbuf_t *metadata; refbuf_t *read_data; int read_count; mutex_t url_lock; unsigned build_metadata_len; unsigned build_metadata_offset; char build_metadata[4081]; } mp3_state; int format_mp3_get_plugin(struct source_tag *src); #endif /* __FORMAT_MP3_H__ */ icecast-2.4.2/src/auth.h0000664000175000017500000000607712511160565011772 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __AUTH_H__ #define __AUTH_H__ #ifdef HAVE_CONFIG_H #include #endif struct source_tag; struct auth_tag; #include #include #include #include "cfgfile.h" #include "client.h" #include "thread/thread.h" typedef enum { AUTH_UNDEFINED, AUTH_OK, AUTH_FAILED, AUTH_FORBIDDEN, AUTH_USERADDED, AUTH_USEREXISTS, AUTH_USERDELETED } auth_result; typedef struct auth_client_tag { char *mount; client_t *client; void (*process)(struct auth_tag *auth, struct auth_client_tag *auth_user); struct auth_client_tag *next; } auth_client; typedef struct auth_tag { char *mount; /* Authenticate using the given username and password */ auth_result (*authenticate)(auth_client *aclient); auth_result (*release_listener)(auth_client *auth_user); /* auth handler for authenicating a connecting source client */ void (*stream_auth)(auth_client *auth_user); /* auth handler for source startup, no client passed as it may disappear */ void (*stream_start)(auth_client *auth_user); /* auth handler for source exit, no client passed as it may disappear */ void (*stream_end)(auth_client *auth_user); /* auth state-specific free call */ void (*free)(struct auth_tag *self); auth_result (*adduser)(struct auth_tag *auth, const char *username, const char *password); auth_result (*deleteuser)(struct auth_tag *auth, const char *username); auth_result (*listuser)(struct auth_tag *auth, xmlNodePtr srcnode); mutex_t lock; int running; int refcount; int allow_duplicate_users; thread_type *thread; /* per-auth queue for clients */ auth_client *head, **tailp; int pending_count; void *state; char *type; } auth_t; void auth_add_listener (const char *mount, client_t *client); int auth_release_listener (client_t *client); void auth_initialise (void); void auth_shutdown (void); auth_t *auth_get_authenticator (xmlNodePtr node); void auth_release (auth_t *authenticator); /* call to trigger an event when a stream starts */ void auth_stream_start (struct _mount_proxy *mountinfo, const char *mount); /* call to trigger an event when a stream ends */ void auth_stream_end (struct _mount_proxy *mountinfo, const char *mount); /* call to trigger an event to authenticate a source client */ int auth_stream_authenticate (client_t *client, const char *mount, struct _mount_proxy *mountinfo); /* called from auth thread, after the client has successfully authenticated * and requires adding to source or fserve. */ int auth_postprocess_listener (auth_client *auth_user); #endif icecast-2.4.2/src/format_flac.h0000664000175000017500000000114512511160565013275 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_FLAC_H #define __FORMAT_FLAC_H #include "format_ogg.h" ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_FLAC_H */ icecast-2.4.2/src/format_theora.h0000664000175000017500000000115512510726173013655 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_THEORA_H #define __FORMAT_THEORA_H #include "format_ogg.h" ogg_codec_t *initial_theora_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_THEORA_H */ icecast-2.4.2/src/connection.h0000664000175000017500000000345012511160565013160 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __CONNECTION_H__ #define __CONNECTION_H__ #include #include #ifdef HAVE_OPENSSL #include #include #endif #include "compat.h" #include "httpp/httpp.h" #include "thread/thread.h" #include "net/sock.h" struct _client_tag; struct source_tag; struct ice_config_tag; typedef struct connection_tag { unsigned long id; time_t con_time; time_t discon_time; uint64_t sent_bytes; sock_t sock; sock_t serversock; int error; #ifdef HAVE_OPENSSL SSL *ssl; /* SSL handler */ #endif int (*send)(struct connection_tag *handle, const void *buf, size_t len); int (*read)(struct connection_tag *handle, void *buf, size_t len); char *ip; char *host; } connection_t; void connection_initialize(void); void connection_shutdown(void); void connection_accept_loop(void); int connection_setup_sockets (struct ice_config_tag *config); void connection_close(connection_t *con); connection_t *connection_create (sock_t sock, sock_t serversock, char *ip); int connection_complete_source (struct source_tag *source, int response); int connection_check_pass (http_parser_t *parser, const char *user, const char *pass); int connection_check_relay_pass(http_parser_t *parser); int connection_check_admin_pass(http_parser_t *parser); extern rwlock_t _source_shutdown_rwlock; #endif /* __CONNECTION_H__ */ icecast-2.4.2/src/stats.c0000664000175000017500000007317212511160565012162 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "net/sock.h" #include "connection.h" #include "source.h" #include "global.h" #include "refbuf.h" #include "client.h" #include "stats.h" #include "xslt.h" #include "util.h" #define CATMODULE "stats" #include "logging.h" #ifdef _WIN32 #define atoll _atoi64 #define vsnprintf _vsnprintf #define snprintf _snprintf #endif #define STATS_EVENT_SET 0 #define STATS_EVENT_INC 1 #define STATS_EVENT_DEC 2 #define STATS_EVENT_ADD 3 #define STATS_EVENT_SUB 4 #define STATS_EVENT_REMOVE 5 #define STATS_EVENT_HIDDEN 6 typedef struct _event_queue_tag { volatile stats_event_t *head; volatile stats_event_t **tail; } event_queue_t; #define event_queue_init(qp) { (qp)->head = NULL; (qp)->tail = &(qp)->head; } typedef struct _event_listener_tag { event_queue_t queue; mutex_t mutex; struct _event_listener_tag *next; } event_listener_t; static volatile int _stats_running = 0; static thread_type *_stats_thread_id; static volatile int _stats_threads = 0; static stats_t _stats; static mutex_t _stats_mutex; static event_queue_t _global_event_queue; mutex_t _global_event_mutex; static volatile event_listener_t *_event_listeners; static void *_stats_thread(void *arg); static int _compare_stats(void *a, void *b, void *arg); static int _compare_source_stats(void *a, void *b, void *arg); static int _free_stats(void *key); static int _free_source_stats(void *key); static void _add_event_to_queue(stats_event_t *event, event_queue_t *queue); static stats_node_t *_find_node(avl_tree *tree, const char *name); static stats_source_t *_find_source(avl_tree *tree, const char *source); static void _free_event(stats_event_t *event); static stats_event_t *_get_event_from_queue (event_queue_t *queue); /* simple helper function for creating an event */ static stats_event_t *build_event (const char *source, const char *name, const char *value) { stats_event_t *event; event = (stats_event_t *)calloc(1, sizeof(stats_event_t)); if (event) { if (source) event->source = (char *)strdup(source); if (name) event->name = (char *)strdup(name); if (value) event->value = (char *)strdup(value); else event->action = STATS_EVENT_REMOVE; } return event; } static void queue_global_event (stats_event_t *event) { thread_mutex_lock(&_global_event_mutex); _add_event_to_queue (event, &_global_event_queue); thread_mutex_unlock(&_global_event_mutex); } void stats_initialize(void) { _event_listeners = NULL; /* set up global struct */ _stats.global_tree = avl_tree_new(_compare_stats, NULL); _stats.source_tree = avl_tree_new(_compare_source_stats, NULL); /* set up global mutex */ thread_mutex_create(&_stats_mutex); /* set up stats queues */ event_queue_init (&_global_event_queue); thread_mutex_create(&_global_event_mutex); /* fire off the stats thread */ _stats_running = 1; _stats_thread_id = thread_create("Stats Thread", _stats_thread, NULL, THREAD_ATTACHED); } void stats_shutdown(void) { int n; if(!_stats_running) /* We can't shutdown if we're not running. */ return; /* wait for thread to exit */ _stats_running = 0; thread_join(_stats_thread_id); /* wait for other threads to shut down */ do { thread_sleep(300000); thread_mutex_lock(&_stats_mutex); n = _stats_threads; thread_mutex_unlock(&_stats_mutex); } while (n > 0); ICECAST_LOG_INFO("stats thread finished"); /* free the queues */ /* destroy the queue mutexes */ thread_mutex_destroy(&_global_event_mutex); thread_mutex_destroy(&_stats_mutex); avl_tree_free(_stats.source_tree, _free_source_stats); avl_tree_free(_stats.global_tree, _free_stats); while (1) { stats_event_t *event = _get_event_from_queue (&_global_event_queue); if (event == NULL) break; if(event->source) free(event->source); if(event->value) free(event->value); if(event->name) free(event->name); free(event); } } stats_t *stats_get_stats(void) { /* lock global stats copy stats unlock global stats return copied stats */ return NULL; } /* simple name=tag stat create/update */ void stats_event(const char *source, const char *name, const char *value) { stats_event_t *event; if (value && xmlCheckUTF8 ((unsigned char *)value) == 0) { ICECAST_LOG_WARN("seen non-UTF8 data, probably incorrect metadata (%s, %s)", name, value); return; } event = build_event (source, name, value); if (event) queue_global_event (event); } /* wrapper for stats_event, this takes a charset to convert from */ void stats_event_conv(const char *mount, const char *name, const char *value, const char *charset) { const char *metadata = value; xmlBufferPtr conv = xmlBufferCreate (); if (charset) { xmlCharEncodingHandlerPtr handle = xmlFindCharEncodingHandler (charset); if (handle) { xmlBufferPtr raw = xmlBufferCreate (); xmlBufferAdd (raw, (const xmlChar *)value, strlen (value)); if (xmlCharEncInFunc (handle, conv, raw) > 0) metadata = (char *)xmlBufferContent (conv); xmlBufferFree (raw); xmlCharEncCloseFunc (handle); } else ICECAST_LOG_WARN("No charset found for \"%s\"", charset); } stats_event (mount, name, metadata); xmlBufferFree (conv); } /* make stat hidden (non-zero). name can be NULL if it applies to a whole * source stats tree. */ void stats_event_hidden (const char *source, const char *name, int hidden) { stats_event_t *event; const char *str = NULL; if (hidden) str = ""; event = build_event (source, name, str); if (event) { event->action = STATS_EVENT_HIDDEN; queue_global_event (event); } } /* printf style formatting for stat create/update */ void stats_event_args(const char *source, char *name, char *format, ...) { char buf[1024]; va_list val; int ret; if (name == NULL) return; va_start(val, format); ret = vsnprintf(buf, sizeof(buf), format, val); va_end(val); if (ret < 0 || (unsigned int)ret >= sizeof (buf)) { ICECAST_LOG_WARN("problem with formatting %s stat %s", source==NULL ? "global" : source, name); return; } stats_event(source, name, buf); } static char *_get_stats(const char *source, const char *name) { stats_node_t *stats = NULL; stats_source_t *src = NULL; char *value = NULL; thread_mutex_lock(&_stats_mutex); if (source == NULL) { stats = _find_node(_stats.global_tree, name); } else { src = _find_source(_stats.source_tree, source); if (src) { stats = _find_node(src->stats_tree, name); } } if (stats) value = (char *)strdup(stats->value); thread_mutex_unlock(&_stats_mutex); return value; } char *stats_get_value(const char *source, const char *name) { return(_get_stats(source, name)); } /* increase the value in the provided stat by 1 */ void stats_event_inc(const char *source, const char *name) { stats_event_t *event = build_event (source, name, NULL); /* ICECAST_LOG_DEBUG("%s on %s", name, source==NULL?"global":source); */ if (event) { event->action = STATS_EVENT_INC; queue_global_event (event); } } void stats_event_add(const char *source, const char *name, unsigned long value) { stats_event_t *event = build_event (source, name, NULL); /* ICECAST_LOG_DEBUG("%s on %s", name, source==NULL?"global":source); */ if (event) { event->value = malloc (16); snprintf (event->value, 16, "%ld", value); event->action = STATS_EVENT_ADD; queue_global_event (event); } } void stats_event_sub(const char *source, const char *name, unsigned long value) { stats_event_t *event = build_event (source, name, NULL); if (event) { event->value = malloc (16); snprintf (event->value, 16, "%ld", value); event->action = STATS_EVENT_SUB; queue_global_event (event); } } /* decrease the value in the provided stat by 1 */ void stats_event_dec(const char *source, const char *name) { /* ICECAST_LOG_DEBUG("%s on %s", name, source==NULL?"global":source); */ stats_event_t *event = build_event (source, name, NULL); if (event) { event->action = STATS_EVENT_DEC; queue_global_event (event); } } /* note: you must call this function only when you have exclusive access ** to the avl_tree */ static stats_node_t *_find_node(avl_tree *stats_tree, const char *name) { stats_node_t *stats; avl_node *node; int cmp; /* get the root node */ node = stats_tree->root->right; while (node) { stats = (stats_node_t *)node->key; cmp = strcmp(name, stats->name); if (cmp < 0) node = node->left; else if (cmp > 0) node = node->right; else return stats; } /* didn't find it */ return NULL; } /* note: you must call this function only when you have exclusive access ** to the avl_tree */ static stats_source_t *_find_source(avl_tree *source_tree, const char *source) { stats_source_t *stats; avl_node *node; int cmp; /* get the root node */ node = source_tree->root->right; while (node) { stats = (stats_source_t *)node->key; cmp = strcmp(source, stats->source); if (cmp < 0) node = node->left; else if (cmp > 0) node = node->right; else return stats; } /* didn't find it */ return NULL; } static stats_event_t *_copy_event(stats_event_t *event) { stats_event_t *copy = (stats_event_t *)calloc(1, sizeof(stats_event_t)); if (event->source) copy->source = (char *)strdup(event->source); else copy->source = NULL; if (event->name) copy->name = (char *)strdup(event->name); if (event->value) copy->value = (char *)strdup(event->value); else copy->value = NULL; copy->hidden = event->hidden; copy->next = NULL; return copy; } /* helper to apply specialised changes to a stats node */ static void modify_node_event (stats_node_t *node, stats_event_t *event) { char *str; if (event->action == STATS_EVENT_HIDDEN) { if (event->value) node->hidden = 1; else node->hidden = 0; return; } if (event->action != STATS_EVENT_SET) { int64_t value = 0; switch (event->action) { case STATS_EVENT_INC: value = atoi (node->value)+1; break; case STATS_EVENT_DEC: value = atoi (node->value)-1; break; case STATS_EVENT_ADD: value = atoi (node->value)+atoi (event->value); break; case STATS_EVENT_SUB: value = atoll (node->value) - atoll (event->value); break; default: ICECAST_LOG_WARN("unhandled event (%d) for %s", event->action, event->source); break; } str = malloc (16); snprintf (str, 16, "%" PRId64, value); if (event->value == NULL) event->value = strdup (str); } else str = (char *)strdup (event->value); free (node->value); node->value = str; if (event->source) ICECAST_LOG_DEBUG("update \"%s\" %s (%s)", event->source, node->name, node->value); else ICECAST_LOG_DEBUG("update global %s (%s)", node->name, node->value); } static void process_global_event (stats_event_t *event) { stats_node_t *node; /* ICECAST_LOG_DEBUG("global event %s %s %d", event->name, event->value, event->action); */ if (event->action == STATS_EVENT_REMOVE) { /* we're deleting */ node = _find_node(_stats.global_tree, event->name); if (node != NULL) avl_delete(_stats.global_tree, (void *)node, _free_stats); return; } node = _find_node(_stats.global_tree, event->name); if (node) { modify_node_event (node, event); } else { /* add node */ node = (stats_node_t *)calloc(1, sizeof(stats_node_t)); node->name = (char *)strdup(event->name); node->value = (char *)strdup(event->value); avl_insert(_stats.global_tree, (void *)node); } } 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; ICECAST_LOG_DEBUG("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) { ICECAST_LOG_DEBUG("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) { ICECAST_LOG_DEBUG("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) { ICECAST_LOG_DEBUG("delete source node %s", event->source); avl_delete(_stats.source_tree, (void *)snode, _free_source_stats); } } /* NOTE: implicit %z is added to format string. */ static inline void __format_time(char * buffer, size_t len, const char * format) { time_t now = time(NULL); struct tm local; char tzbuffer[32]; char timebuffer[128]; #ifdef _WIN32 struct tm *thetime; int time_days, time_hours, time_tz; int tempnum1, tempnum2; char sign; #endif localtime_r (&now, &local); #ifndef _WIN32 strftime (tzbuffer, sizeof(tzbuffer), "%z", &local); #else thetime = gmtime (&now); time_days = local.tm_yday - thetime->tm_yday; if (time_days < -1) { tempnum1 = 24; } else { tempnum1 = 1; } if (tempnum1 < time_days) { tempnum2 = -24; } else { tempnum2 = time_days*24; } time_hours = (tempnum2 + local.tm_hour - thetime->tm_hour); time_tz = time_hours * 60 + local.tm_min - thetime->tm_min; if (time_tz < 0) { sign = '-'; time_tz = -time_tz; } else { sign = '+'; } snprintf(tzbuffer, sizeof(tzbuffer), "%c%.2d%.2d", sign, time_tz / 60, time_tz % 60); #endif strftime (timebuffer, sizeof(timebuffer), format, &local); snprintf(buffer, len, "%s%s", timebuffer, tzbuffer); } void stats_event_time (const char *mount, const char *name) { char buffer[100]; __format_time(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S "); stats_event (mount, name, buffer); } void stats_event_time_iso8601 (const char *mount, const char *name) { char buffer[100]; __format_time(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S"); stats_event (mount, name, buffer); } void stats_global (ice_config_t *config) { stats_event (NULL, "server_id", config->server_id); stats_event (NULL, "host", config->hostname); stats_event (NULL, "location", config->location); stats_event (NULL, "admin", config->admin); } static void *_stats_thread(void *arg) { stats_event_t *event; stats_event_t *copy; event_listener_t *listener; stats_event_time (NULL, "server_start"); stats_event_time_iso8601 (NULL, "server_start_iso8601"); /* global currently active stats */ stats_event (NULL, "clients", "0"); stats_event (NULL, "connections", "0"); stats_event (NULL, "sources", "0"); stats_event (NULL, "stats", "0"); stats_event (NULL, "listeners", "0"); /* global accumulating stats */ stats_event (NULL, "client_connections", "0"); stats_event (NULL, "source_client_connections", "0"); stats_event (NULL, "source_relay_connections", "0"); stats_event (NULL, "source_total_connections", "0"); stats_event (NULL, "stats_connections", "0"); stats_event (NULL, "listener_connections", "0"); ICECAST_LOG_INFO("stats thread started"); while (_stats_running) { thread_mutex_lock(&_global_event_mutex); if (_global_event_queue.head != NULL) { /* grab the next event from the queue */ event = _get_event_from_queue (&_global_event_queue); thread_mutex_unlock(&_global_event_mutex); if (event == NULL) continue; event->next = NULL; thread_mutex_lock(&_stats_mutex); /* check if we are dealing with a global or source event */ if (event->source == NULL) process_global_event (event); else process_source_event (event); /* now we have an event that's been processed into the running stats */ /* this event should get copied to event listeners' queues */ listener = (event_listener_t *)_event_listeners; while (listener) { copy = _copy_event(event); thread_mutex_lock (&listener->mutex); _add_event_to_queue (copy, &listener->queue); thread_mutex_unlock (&listener->mutex); listener = listener->next; } /* now we need to destroy the event */ _free_event(event); thread_mutex_unlock(&_stats_mutex); continue; } else { thread_mutex_unlock(&_global_event_mutex); } thread_sleep(300000); } return NULL; } /* you must have the _stats_mutex locked here */ static void _unregister_listener(event_listener_t *listener) { event_listener_t **prev = (event_listener_t **)&_event_listeners, *current = *prev; while (current) { if (current == listener) { *prev = current->next; break; } prev = ¤t->next; current = *prev; } } static stats_event_t *_make_event_from_node(stats_node_t *node, char *source) { stats_event_t *event = (stats_event_t *)malloc(sizeof(stats_event_t)); if (source != NULL) event->source = (char *)strdup(source); else event->source = NULL; event->name = (char *)strdup(node->name); event->value = (char *)strdup(node->value); event->hidden = node->hidden; event->action = STATS_EVENT_SET; event->next = NULL; return event; } static void _add_event_to_queue(stats_event_t *event, event_queue_t *queue) { *queue->tail = event; queue->tail = (volatile stats_event_t **)&event->next; } static stats_event_t *_get_event_from_queue (event_queue_t *queue) { stats_event_t *event = NULL; if (queue && queue->head) { event = (stats_event_t *)queue->head; queue->head = event->next; if (queue->head == NULL) queue->tail = &queue->head; } return event; } static int _send_event_to_client(stats_event_t *event, client_t *client) { int len; char buf [200]; /* send data to the client!!!! */ len = snprintf (buf, sizeof (buf), "EVENT %s %s %s\n", (event->source != NULL) ? event->source : "global", event->name ? event->name : "null", event->value ? event->value : "null"); if (len > 0 && len < (int)sizeof (buf)) { client_send_bytes (client, buf, len); if (client->con->error) return -1; } return 0; } static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden) { avl_node *avlnode; xmlNodePtr ret = NULL; thread_mutex_lock(&_stats_mutex); /* general stats first */ avlnode = avl_get_first(_stats.global_tree); while (avlnode) { stats_node_t *stat = avlnode->key; if (stat->hidden <= hidden) xmlNewTextChild (root, NULL, XMLSTR(stat->name), XMLSTR(stat->value)); avlnode = avl_get_next (avlnode); } /* now per mount stats */ avlnode = avl_get_first(_stats.source_tree); while (avlnode) { stats_source_t *source = (stats_source_t *)avlnode->key; if (source->hidden <= hidden && (show_mount == NULL || strcmp (show_mount, source->source) == 0)) { avl_node *avlnode2 = avl_get_first (source->stats_tree); xmlNodePtr xmlnode = xmlNewTextChild (root, NULL, XMLSTR("source"), NULL); xmlSetProp (xmlnode, XMLSTR("mount"), XMLSTR(source->source)); if (ret == NULL) ret = xmlnode; while (avlnode2) { stats_node_t *stat = avlnode2->key; xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value)); avlnode2 = avl_get_next (avlnode2); } } avlnode = avl_get_next (avlnode); } thread_mutex_unlock(&_stats_mutex); return ret; } /* factoring out code for stats loops ** this function copies all stats to queue, and registers ** the queue for all new events atomically. ** note: mutex must already be created! */ static void _register_listener (event_listener_t *listener) { avl_node *node; avl_node *node2; stats_event_t *event; stats_source_t *source; thread_mutex_lock(&_stats_mutex); /* first we fill our queue with the current stats */ /* start with the global stats */ node = avl_get_first(_stats.global_tree); while (node) { event = _make_event_from_node((stats_node_t *)node->key, NULL); _add_event_to_queue (event, &listener->queue); node = avl_get_next(node); } /* now the stats for each source */ node = avl_get_first(_stats.source_tree); while (node) { source = (stats_source_t *)node->key; node2 = avl_get_first(source->stats_tree); while (node2) { event = _make_event_from_node((stats_node_t *)node2->key, source->source); _add_event_to_queue (event, &listener->queue); node2 = avl_get_next(node2); } node = avl_get_next(node); } /* now we register to receive future event notices */ listener->next = (event_listener_t *)_event_listeners; _event_listeners = listener; thread_mutex_unlock(&_stats_mutex); } void *stats_connection(void *arg) { client_t *client = (client_t *)arg; stats_event_t *event; event_listener_t listener; ICECAST_LOG_INFO("stats client starting"); event_queue_init (&listener.queue); /* increment the thread count */ thread_mutex_lock(&_stats_mutex); _stats_threads++; stats_event_args (NULL, "stats", "%d", _stats_threads); thread_mutex_unlock(&_stats_mutex); thread_mutex_create (&(listener.mutex)); _register_listener (&listener); while (_stats_running) { thread_mutex_lock (&listener.mutex); event = _get_event_from_queue (&listener.queue); thread_mutex_unlock (&listener.mutex); if (event != NULL) { if (_send_event_to_client(event, client) < 0) { _free_event(event); break; } _free_event(event); continue; } thread_sleep (500000); } thread_mutex_lock(&_stats_mutex); _unregister_listener (&listener); _stats_threads--; stats_event_args (NULL, "stats", "%d", _stats_threads); thread_mutex_unlock(&_stats_mutex); thread_mutex_destroy (&listener.mutex); client_destroy (client); ICECAST_LOG_INFO("stats client finished"); return NULL; } void stats_callback (client_t *client, void *notused) { if (client->con->error) { client_destroy (client); return; } client_set_queue (client, NULL); thread_create("Stats Connection", stats_connection, (void *)client, THREAD_DETACHED); } typedef struct _source_xml_tag { char *mount; xmlNodePtr node; struct _source_xml_tag *next; } source_xml_t; void stats_transform_xslt(client_t *client, const char *uri) { xmlDocPtr doc; char *xslpath = util_get_path_from_normalised_uri (uri); const char *mount = httpp_get_query_param (client->parser, "mount"); doc = stats_get_xml (0, mount); xslt_transform(doc, xslpath, client); xmlFreeDoc(doc); free (xslpath); } xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount) { xmlDocPtr doc; xmlNodePtr node; doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL); xmlDocSetRootElement(doc, node); node = _dump_stats_to_doc (node, show_mount, show_hidden); return doc; } static int _compare_stats(void *arg, void *a, void *b) { stats_node_t *nodea = (stats_node_t *)a; stats_node_t *nodeb = (stats_node_t *)b; return strcmp(nodea->name, nodeb->name); } static int _compare_source_stats(void *arg, void *a, void *b) { stats_source_t *nodea = (stats_source_t *)a; stats_source_t *nodeb = (stats_source_t *)b; return strcmp(nodea->source, nodeb->source); } static int _free_stats(void *key) { stats_node_t *node = (stats_node_t *)key; free(node->value); free(node->name); free(node); return 1; } static int _free_source_stats(void *key) { stats_source_t *node = (stats_source_t *)key; avl_tree_free(node->stats_tree, _free_stats); free(node->source); free(node); return 1; } static void _free_event(stats_event_t *event) { if (event->source) free(event->source); if (event->name) free(event->name); if (event->value) free(event->value); free(event); } refbuf_t *stats_get_streams (void) { #define STREAMLIST_BLKSIZE 4096 avl_node *node; unsigned int remaining = STREAMLIST_BLKSIZE; refbuf_t *start = refbuf_new (remaining), *cur = start; char *buffer = cur->data; /* now the stats for each source */ thread_mutex_lock (&_stats_mutex); node = avl_get_first(_stats.source_tree); while (node) { int ret; stats_source_t *source = (stats_source_t *)node->key; if (source->hidden == 0) { if (remaining <= strlen (source->source) + 3) { cur->len = STREAMLIST_BLKSIZE - remaining; cur->next = refbuf_new (STREAMLIST_BLKSIZE); remaining = STREAMLIST_BLKSIZE; cur = cur->next; buffer = cur->data; } ret = snprintf (buffer, remaining, "%s\r\n", source->source); if (ret > 0) { buffer += ret; remaining -= ret; } } node = avl_get_next(node); } thread_mutex_unlock (&_stats_mutex); cur->len = STREAMLIST_BLKSIZE - remaining; return start; } /* This removes any source stats from virtual mountpoints, ie mountpoints * where no source_t exists. This function requires the global sources lock * to be held before calling. */ void stats_clear_virtual_mounts (void) { avl_node *snode; thread_mutex_lock (&_stats_mutex); snode = avl_get_first(_stats.source_tree); while (snode) { stats_source_t *src = (stats_source_t *)snode->key; source_t *source = source_find_mount_raw (src->source); if (source == NULL) { /* no source_t is reserved so remove them now */ snode = avl_get_next (snode); ICECAST_LOG_DEBUG("releasing %s stats", src->source); avl_delete (_stats.source_tree, src, _free_source_stats); continue; } snode = avl_get_next (snode); } thread_mutex_unlock (&_stats_mutex); } icecast-2.4.2/src/fserve.c0000664000175000017500000005402512511160565012312 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011, Philipp "ph3-der-loewe" Schafft . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #ifdef HAVE_POLL #include #endif #ifndef _WIN32 #include #include #include #define SCN_OFF_T SCNdMAX #define PRI_OFF_T PRIdMAX #else #include #include #define fseeko fseek #define SCN_OFF_T "ld" #define PRI_OFF_T "ld" #define snprintf _snprintf #define strncasecmp _strnicmp #ifndef S_ISREG #define S_ISREG(mode) ((mode) & _S_IFREG) #endif #endif #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "net/sock.h" #include "connection.h" #include "global.h" #include "refbuf.h" #include "client.h" #include "stats.h" #include "format.h" #include "logging.h" #include "cfgfile.h" #include "util.h" #include "admin.h" #include "compat.h" #include "fserve.h" #undef CATMODULE #define CATMODULE "fserve" #define BUFSIZE 4096 static fserve_t *active_list = NULL; static fserve_t *pending_list = NULL; static spin_t pending_lock; static avl_tree *mimetypes = NULL; static volatile int run_fserv = 0; static unsigned int fserve_clients; static int client_tree_changed=0; #ifdef HAVE_POLL static struct pollfd *ufds = NULL; #else static fd_set fds; static sock_t fd_max = SOCK_ERROR; #endif typedef struct { char *ext; char *type; } mime_type; static void fserve_client_destroy(fserve_t *fclient); static int _delete_mapping(void *mapping); static void *fserv_thread_function(void *arg); void fserve_initialize(void) { ice_config_t *config = config_get_config(); mimetypes = NULL; active_list = NULL; pending_list = NULL; thread_spin_create (&pending_lock); fserve_recheck_mime_types (config); config_release_config(); stats_event (NULL, "file_connections", "0"); ICECAST_LOG_INFO("file serving started"); } void fserve_shutdown(void) { thread_spin_lock (&pending_lock); run_fserv = 0; while (pending_list) { fserve_t *to_go = (fserve_t *)pending_list; pending_list = to_go->next; fserve_client_destroy (to_go); } while (active_list) { fserve_t *to_go = active_list; active_list = to_go->next; fserve_client_destroy (to_go); } if (mimetypes) avl_tree_free (mimetypes, _delete_mapping); thread_spin_unlock (&pending_lock); thread_spin_destroy (&pending_lock); ICECAST_LOG_INFO("file serving stopped"); } #ifdef HAVE_POLL int fserve_client_waiting (void) { fserve_t *fclient; unsigned int i = 0; /* only rebuild ufds if there are clients added/removed */ if (client_tree_changed) { client_tree_changed = 0; ufds = realloc(ufds, fserve_clients * sizeof(struct pollfd)); fclient = active_list; while (fclient) { ufds[i].fd = fclient->client->con->sock; ufds[i].events = POLLOUT; ufds[i].revents = 0; fclient = fclient->next; i++; } } if (!ufds) { thread_spin_lock (&pending_lock); run_fserv = 0; thread_spin_unlock (&pending_lock); return -1; } else if (poll(ufds, fserve_clients, 200) > 0) { /* mark any clients that are ready */ fclient = active_list; for (i=0; iready = 1; fclient = fclient->next; } return 1; } return 0; } #else int fserve_client_waiting (void) { fserve_t *fclient; fd_set realfds; /* only rebuild fds if there are clients added/removed */ if(client_tree_changed) { client_tree_changed = 0; FD_ZERO(&fds); fd_max = SOCK_ERROR; fclient = active_list; while (fclient) { FD_SET (fclient->client->con->sock, &fds); if (fclient->client->con->sock > fd_max || fd_max == SOCK_ERROR) fd_max = fclient->client->con->sock; fclient = fclient->next; } } /* hack for windows, select needs at least 1 descriptor */ if (fd_max == SOCK_ERROR) { thread_spin_lock (&pending_lock); run_fserv = 0; thread_spin_unlock (&pending_lock); return -1; } else { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 200000; /* make a duplicate of the set so we do not have to rebuild it * each time around */ memcpy(&realfds, &fds, sizeof(fd_set)); if(select(fd_max+1, NULL, &realfds, NULL, &tv) > 0) { /* mark any clients that are ready */ fclient = active_list; while (fclient) { if (FD_ISSET (fclient->client->con->sock, &realfds)) fclient->ready = 1; fclient = fclient->next; } return 1; } } return 0; } #endif static int wait_for_fds(void) { fserve_t *fclient; int ret; while (run_fserv) { /* add any new clients here */ if (pending_list) { thread_spin_lock (&pending_lock); fclient = (fserve_t*)pending_list; while (fclient) { fserve_t *to_move = fclient; fclient = fclient->next; to_move->next = active_list; active_list = to_move; client_tree_changed = 1; fserve_clients++; } pending_list = NULL; thread_spin_unlock (&pending_lock); } /* drop out of here if someone is ready */ ret = fserve_client_waiting(); if (ret) return ret; } return -1; } static void *fserv_thread_function(void *arg) { fserve_t *fclient, **trail; size_t bytes; while (1) { if (wait_for_fds() < 0) break; fclient = active_list; trail = &active_list; while (fclient) { /* process this client, if it is ready */ if (fclient->ready) { client_t *client = fclient->client; refbuf_t *refbuf = client->refbuf; fclient->ready = 0; if (client->pos == refbuf->len) { /* Grab a new chunk */ if (fclient->file) bytes = fread (refbuf->data, 1, BUFSIZE, fclient->file); else bytes = 0; if (bytes == 0) { if (refbuf->next == NULL) { fserve_t *to_go = fclient; fclient = fclient->next; *trail = fclient; fserve_client_destroy (to_go); fserve_clients--; client_tree_changed = 1; continue; } refbuf = refbuf->next; client->refbuf->next = NULL; refbuf_release (client->refbuf); client->refbuf = refbuf; bytes = refbuf->len; } refbuf->len = (unsigned int)bytes; client->pos = 0; } /* Now try and send current chunk. */ format_generic_write_to_client (client); if (client->con->error) { fserve_t *to_go = fclient; fclient = fclient->next; *trail = fclient; fserve_clients--; fserve_client_destroy (to_go); client_tree_changed = 1; continue; } } trail = &fclient->next; fclient = fclient->next; } } ICECAST_LOG_DEBUG("fserve handler exit"); return NULL; } /* string returned needs to be free'd */ char *fserve_content_type (const char *path) { char *ext = util_get_extension(path); mime_type exttype = {ext, NULL}; void *result; char *type; thread_spin_lock (&pending_lock); if (mimetypes && !avl_get_by_key (mimetypes, &exttype, &result)) { mime_type *mime = result; type = strdup (mime->type); } else { /* Fallbacks for a few basic ones */ if(!strcmp(ext, "ogg")) type = strdup ("application/ogg"); else if(!strcmp(ext, "mp3")) type = strdup ("audio/mpeg"); else if(!strcmp(ext, "html")) type = strdup ("text/html"); else if(!strcmp(ext, "css")) type = strdup ("text/css"); else if(!strcmp(ext, "txt")) type = strdup ("text/plain"); else if(!strcmp(ext, "jpg")) type = strdup ("image/jpeg"); else if(!strcmp(ext, "png")) type = strdup ("image/png"); else if(!strcmp(ext, "m3u")) type = strdup ("audio/x-mpegurl"); else if(!strcmp(ext, "aac")) type = strdup ("audio/aac"); else type = strdup ("application/octet-stream"); } thread_spin_unlock (&pending_lock); return type; } static void fserve_client_destroy(fserve_t *fclient) { if (fclient) { if (fclient->file) fclose (fclient->file); if (fclient->callback) fclient->callback (fclient->client, fclient->arg); else if (fclient->client) client_destroy (fclient->client); free (fclient); } } /* client has requested a file, so check for it and send the file. Do not * refer to the client_t afterwards. return 0 for success, -1 on error. */ int fserve_client_create (client_t *httpclient, const char *path) { int bytes; struct stat file_buf; const char *range = NULL; off_t new_content_len = 0; off_t rangenumber = 0, content_length; int rangeproblem = 0; int ret = 0; char *fullpath; int m3u_requested = 0, m3u_file_available = 1; const char * xslt_playlist_requested = NULL; int xslt_playlist_file_available = 1; ice_config_t *config; FILE *file; fullpath = util_get_path_from_normalised_uri (path); ICECAST_LOG_INFO("checking for file %H (%H)", path, fullpath); if (strcmp (util_get_extension (fullpath), "m3u") == 0) m3u_requested = 1; if (strcmp (util_get_extension (fullpath), "xspf") == 0) xslt_playlist_requested = "xspf.xsl"; if (strcmp (util_get_extension (fullpath), "vclt") == 0) xslt_playlist_requested = "vclt.xsl"; /* check for the actual file */ if (stat (fullpath, &file_buf) != 0) { /* the m3u can be generated, but send an m3u file if available */ if (m3u_requested == 0 && xslt_playlist_requested == NULL) { ICECAST_LOG_WARN("req for file \"%H\" %s", fullpath, strerror (errno)); client_send_404 (httpclient, "The file you requested could not be found"); free (fullpath); return -1; } m3u_file_available = 0; xslt_playlist_file_available = 0; } httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE; if (m3u_requested && m3u_file_available == 0) { const char *host = httpp_getvar (httpclient->parser, "host"); char *sourceuri = strdup (path); char *dot = strrchr(sourceuri, '.'); /* at least a couple of players (fb2k/winamp) are reported to send a * host header but without the port number. So if we are missing the * port then lets treat it as if no host line was sent */ if (host && strchr (host, ':') == NULL) host = NULL; *dot = 0; httpclient->respcode = 200; ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, "audio/x-mpegurl", NULL, "", NULL); if (ret == -1 || ret >= (BUFSIZE - 512)) { /* we want at least 512 bytes left for the content of the playlist */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(httpclient, "Header generation failed."); return -1; } if (host == NULL) { config = config_get_config(); snprintf (httpclient->refbuf->data + ret, BUFSIZE - ret, "http://%s:%d%s\r\n", config->hostname, config->port, sourceuri ); config_release_config(); } else { snprintf (httpclient->refbuf->data + ret, BUFSIZE - ret, "http://%s%s\r\n", host, sourceuri ); } httpclient->refbuf->len = strlen (httpclient->refbuf->data); fserve_add_client (httpclient, NULL); free (sourceuri); free (fullpath); return 0; } if (xslt_playlist_requested && xslt_playlist_file_available == 0) { xmlDocPtr doc; char *reference = strdup (path); char *eol = strrchr (reference, '.'); if (eol) *eol = '\0'; doc = stats_get_xml (0, reference); free (reference); admin_send_response (doc, httpclient, TRANSFORMED, xslt_playlist_requested); xmlFreeDoc(doc); return 0; } /* on demand file serving check */ config = config_get_config(); if (config->fileserve == 0) { ICECAST_LOG_DEBUG("on demand file \"%H\" refused. Serving static files has been disabled in the config", fullpath); client_send_404 (httpclient, "The file you requested could not be found"); config_release_config(); free (fullpath); return -1; } config_release_config(); if (S_ISREG (file_buf.st_mode) == 0) { client_send_404 (httpclient, "The file you requested could not be found"); ICECAST_LOG_WARN("found requested file but there is no handler for it: %H", fullpath); free (fullpath); return -1; } file = fopen (fullpath, "rb"); if (file == NULL) { ICECAST_LOG_WARN("Problem accessing file \"%H\"", fullpath); client_send_404 (httpclient, "File not readable"); free (fullpath); return -1; } free (fullpath); content_length = file_buf.st_size; range = httpp_getvar (httpclient->parser, "range"); /* full http range handling is currently not done but we deal with the common case */ if (range != NULL) { ret = 0; if (strncasecmp (range, "bytes=", 6) == 0) ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber); if (ret != 1) { /* format not correct, so lets just assume we start from the beginning */ rangeproblem = 1; } if (rangenumber < 0) { rangeproblem = 1; } if (!rangeproblem) { ret = fseeko (file, rangenumber, SEEK_SET); if (ret != -1) { new_content_len = content_length - rangenumber; if (new_content_len < 0) { rangeproblem = 1; } } else { rangeproblem = 1; } if (!rangeproblem) { off_t endpos = rangenumber+new_content_len-1; char *type; if (endpos < 0) { endpos = 0; } httpclient->respcode = 206; type = fserve_content_type (path); bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 206, NULL, type, NULL, NULL, NULL); if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(httpclient, "Header generation failed."); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" "Content-Range: bytes %" PRI_OFF_T \ "-%" PRI_OFF_T "/%" PRI_OFF_T "\r\n\r\n", new_content_len, rangenumber, endpos, content_length); free (type); } else { goto fail; } } else { goto fail; } } else { char *type = fserve_content_type(path); httpclient->respcode = 200; bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, type, NULL, NULL, NULL); if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(httpclient, "Header generation failed."); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n\r\n", content_length); free (type); } httpclient->refbuf->len = bytes; httpclient->pos = 0; stats_event_inc (NULL, "file_connections"); fserve_add_client (httpclient, file); return 0; fail: fclose (file); httpclient->respcode = 416; sock_write (httpclient->con->sock, "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n"); client_destroy (httpclient); return -1; } /* Routine to actually add pre-configured client structure to pending list and * then to start off the file serving thread if it is not already running */ static void fserve_add_pending (fserve_t *fclient) { thread_spin_lock (&pending_lock); fclient->next = (fserve_t *)pending_list; pending_list = fclient; if (run_fserv == 0) { run_fserv = 1; ICECAST_LOG_DEBUG("fserve handler waking up"); thread_create("File Serving Thread", fserv_thread_function, NULL, THREAD_DETACHED); } thread_spin_unlock (&pending_lock); } /* Add client to fserve thread, client needs to have refbuf set and filled * but may provide a NULL file if no data needs to be read */ int fserve_add_client (client_t *client, FILE *file) { fserve_t *fclient = calloc (1, sizeof(fserve_t)); ICECAST_LOG_DEBUG("Adding client to file serving engine"); if (fclient == NULL) { client_send_404 (client, "memory exhausted"); return -1; } fclient->file = file; fclient->client = client; fclient->ready = 0; fserve_add_pending (fclient); return 0; } /* add client to file serving engine, but just write out the buffer contents, * then pass the client to the callback with the provided arg */ void fserve_add_client_callback (client_t *client, fserve_callback_t callback, void *arg) { fserve_t *fclient = calloc (1, sizeof(fserve_t)); ICECAST_LOG_DEBUG("Adding client to file serving engine"); if (fclient == NULL) { client_send_404 (client, "memory exhausted"); return; } fclient->file = NULL; fclient->client = client; fclient->ready = 0; fclient->callback = callback; fclient->arg = arg; fserve_add_pending (fclient); } static int _delete_mapping(void *mapping) { mime_type *map = mapping; free(map->ext); free(map->type); free(map); return 1; } static int _compare_mappings(void *arg, void *a, void *b) { return strcmp( ((mime_type *)a)->ext, ((mime_type *)b)->ext); } void fserve_recheck_mime_types (ice_config_t *config) { FILE *mimefile; char line[4096]; char *type, *ext, *cur; mime_type *mapping; avl_tree *new_mimetypes; if (config->mimetypes_fn == NULL) return; mimefile = fopen (config->mimetypes_fn, "r"); if (mimefile == NULL) { ICECAST_LOG_WARN("Cannot open mime types file %s", config->mimetypes_fn); return; } new_mimetypes = avl_tree_new(_compare_mappings, NULL); while(fgets(line, 4096, mimefile)) { line[4095] = 0; if(*line == 0 || *line == '#') continue; type = line; cur = line; while(*cur != ' ' && *cur != '\t' && *cur) cur++; if(*cur == 0) continue; *cur++ = 0; while(1) { while(*cur == ' ' || *cur == '\t') cur++; if(*cur == 0) break; ext = cur; while(*cur != ' ' && *cur != '\t' && *cur != '\n' && *cur) cur++; *cur++ = 0; if(*ext) { void *tmp; /* Add a new extension->type mapping */ mapping = malloc(sizeof(mime_type)); mapping->ext = strdup(ext); mapping->type = strdup(type); if (!avl_get_by_key (new_mimetypes, mapping, &tmp)) avl_delete (new_mimetypes, mapping, _delete_mapping); avl_insert (new_mimetypes, mapping); } } } fclose(mimefile); thread_spin_lock (&pending_lock); if (mimetypes) avl_tree_free (mimetypes, _delete_mapping); mimetypes = new_mimetypes; thread_spin_unlock (&pending_lock); } icecast-2.4.2/src/format_ebml.h0000664000175000017500000000142112510726173013306 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, * version 2. A copy of this license is included with this source. * At your option, this specific source file can also be distributed * under the GNU GPL version 3. * * Copyright 2012, David Richards, Mozilla Foundation, * and others (see AUTHORS for details). */ /* format_ebml.h ** ** ebml format plugin header ** */ #ifndef __FORMAT_EBML_H__ #define __FORMAT_EBML_H__ #include "format.h" typedef struct ebml_st ebml_t; typedef struct ebml_source_state_st ebml_source_state_t; struct ebml_source_state_st { ebml_t *ebml; refbuf_t *header; int file_headers_written; }; int format_ebml_get_plugin (source_t *source); #endif /* __FORMAT_EBML_H__ */ icecast-2.4.2/src/yp.h0000664000175000017500000000254012511160565011450 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #ifndef __YP_H__ #define __YP_H__ #define YP_SERVER_NAME 1 #define YP_SERVER_DESC 2 #define YP_SERVER_GENRE 3 #define YP_SERVER_URL 4 #define YP_BITRATE 5 #define YP_AUDIO_INFO 6 #define YP_SERVER_TYPE 7 #define YP_CURRENT_SONG 8 #define YP_CLUSTER_PASSWORD 9 #define YP_SUBTYPE 10 #define YP_ADD_ALL -1 #ifdef USE_YP void yp_add (const char *mount); void yp_remove (const char *mount); void yp_touch (const char *mount); void yp_recheck_config (ice_config_t *config); void yp_initialize(void); void yp_shutdown(void); #else #define yp_add(x) do{}while(0) #define yp_remove(x) do{}while(0) #define yp_touch(x) do{}while(0) #define yp_recheck_config(x) do{}while(0) #define yp_initialize() ICECAST_LOG_WARN("YP server handling has been disabled") #define yp_shutdown() do{}while(0) #endif /* USE_YP */ #endif icecast-2.4.2/src/refbuf.h0000664000175000017500000000170412510726173012274 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* refbuf.h ** ** reference counting data buffer ** */ #ifndef __REFBUF_H__ #define __REFBUF_H__ typedef struct _refbuf_tag { unsigned int len; unsigned int _count; char *data; struct _refbuf_tag *associated; struct _refbuf_tag *next; int sync_point; } refbuf_t; void refbuf_initialize(void); void refbuf_shutdown(void); refbuf_t *refbuf_new(unsigned int size); void refbuf_addref(refbuf_t *self); void refbuf_release(refbuf_t *self); #define PER_CLIENT_REFBUF_SIZE 4096 #endif /* __REFBUF_H__ */ icecast-2.4.2/src/format_skeleton.c0000664000175000017500000000474412511160565014217 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for skeleton logical streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct source_tag source_t; #include "refbuf.h" #include "format_ogg.h" #include "format_skeleton.h" #include "client.h" #include "stats.h" #define CATMODULE "format-skeleton" #include "logging.h" static void skeleton_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ICECAST_LOG_DEBUG("freeing skeleton codec"); ogg_stream_clear (&codec->os); free (codec); } /* skeleton pages are not rebuilt, so here we just for headers and then * pass them straight through to the the queue */ static refbuf_t *process_skeleton_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { ogg_packet packet; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } while (ogg_stream_packetout (&codec->os, &packet) > 0) { codec->headers++; } /* all skeleon packets are headers */ format_ogg_attach_header (ogg_info, page); return NULL; } /* Check if specified BOS page is the start of a skeleton stream and * if so, create a codec structure for handling it */ ogg_codec_t *initial_skeleton_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for skeleton codec"); if ((packet.bytes<8) || memcmp(packet.packet, "fishead\0", 8)) { ogg_stream_clear (&codec->os); free (codec); return NULL; } ICECAST_LOG_INFO("seen initial skeleton header"); codec->process_page = process_skeleton_page; codec->codec_free = skeleton_codec_free; codec->headers = 1; codec->name = "Skeleton"; format_ogg_attach_header (ogg_info, page); return codec; } icecast-2.4.2/src/format_speex.h0000664000175000017500000000115112511160565013511 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __FORMAT_SPEEX_H #define __FORMAT_SPEEX_H #include "format_ogg.h" ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page); #endif /* __FORMAT_SPEEX_H */ icecast-2.4.2/src/event.h0000664000175000017500000000112312511160565012135 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __EVENT_H__ #define __EVENT_H__ #define EVENT_NO_EVENT 0 #define EVENT_CONFIG_READ 1 void event_config_read(void *nothing); #endif /* __EVENT_H__ */ icecast-2.4.2/src/admin.h0000664000175000017500000000150212511160565012105 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __ADMIN_H__ #define __ADMIN_H__ #include #include #include "refbuf.h" #include "client.h" #define RAW 1 #define TRANSFORMED 2 #define PLAINTEXT 3 void admin_handle_request(client_t *client, const char *uri); void admin_send_response(xmlDocPtr doc, client_t *client, int response, const char *xslt_template); #endif /* __ADMIN_H__ */ icecast-2.4.2/src/admin.c0000664000175000017500000011402112511160565012101 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "cfgfile.h" #include "connection.h" #include "refbuf.h" #include "client.h" #include "source.h" #include "global.h" #include "event.h" #include "stats.h" #include "compat.h" #include "xslt.h" #include "fserve.h" #include "admin.h" #include "format.h" #include "logging.h" #include "auth.h" #ifdef _WIN32 #define snprintf _snprintf #endif #define CATMODULE "admin" #define COMMAND_ERROR (-1) /* Mount-specific commands */ #define COMMAND_RAW_FALLBACK 1 #define COMMAND_RAW_METADATA_UPDATE 2 #define COMMAND_RAW_SHOW_LISTENERS 3 #define COMMAND_RAW_MOVE_CLIENTS 4 #define COMMAND_RAW_MANAGEAUTH 5 #define COMMAND_SHOUTCAST_METADATA_UPDATE 6 #define COMMAND_RAW_UPDATEMETADATA 7 #define COMMAND_TRANSFORMED_FALLBACK 50 #define COMMAND_TRANSFORMED_SHOW_LISTENERS 53 #define COMMAND_TRANSFORMED_MOVE_CLIENTS 54 #define COMMAND_TRANSFORMED_MANAGEAUTH 55 #define COMMAND_TRANSFORMED_UPDATEMETADATA 56 #define COMMAND_TRANSFORMED_METADATA_UPDATE 57 /* Global commands */ #define COMMAND_RAW_LIST_MOUNTS 101 #define COMMAND_RAW_STATS 102 #define COMMAND_RAW_LISTSTREAM 103 #define COMMAND_PLAINTEXT_LISTSTREAM 104 #define COMMAND_TRANSFORMED_LIST_MOUNTS 201 #define COMMAND_TRANSFORMED_STATS 202 #define COMMAND_TRANSFORMED_LISTSTREAM 203 /* Client management commands */ #define COMMAND_RAW_KILL_CLIENT 301 #define COMMAND_RAW_KILL_SOURCE 302 #define COMMAND_TRANSFORMED_KILL_CLIENT 401 #define COMMAND_TRANSFORMED_KILL_SOURCE 402 /* Admin commands requiring no auth */ #define COMMAND_BUILDM3U 501 #define FALLBACK_RAW_REQUEST "fallbacks" #define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl" #define SHOUTCAST_METADATA_REQUEST "admin.cgi" #define METADATA_RAW_REQUEST "metadata" #define METADATA_TRANSFORMED_REQUEST "metadata.xsl" #define LISTCLIENTS_RAW_REQUEST "listclients" #define LISTCLIENTS_TRANSFORMED_REQUEST "listclients.xsl" #define STATS_RAW_REQUEST "stats" #define STATS_TRANSFORMED_REQUEST "stats.xsl" #define LISTMOUNTS_RAW_REQUEST "listmounts" #define LISTMOUNTS_TRANSFORMED_REQUEST "listmounts.xsl" #define STREAMLIST_RAW_REQUEST "streamlist" #define STREAMLIST_TRANSFORMED_REQUEST "streamlist.xsl" #define STREAMLIST_PLAINTEXT_REQUEST "streamlist.txt" #define MOVECLIENTS_RAW_REQUEST "moveclients" #define MOVECLIENTS_TRANSFORMED_REQUEST "moveclients.xsl" #define KILLCLIENT_RAW_REQUEST "killclient" #define KILLCLIENT_TRANSFORMED_REQUEST "killclient.xsl" #define KILLSOURCE_RAW_REQUEST "killsource" #define KILLSOURCE_TRANSFORMED_REQUEST "killsource.xsl" #define ADMIN_XSL_RESPONSE "response.xsl" #define MANAGEAUTH_RAW_REQUEST "manageauth" #define MANAGEAUTH_TRANSFORMED_REQUEST "manageauth.xsl" #define UPDATEMETADATA_RAW_REQUEST "updatemetadata" #define UPDATEMETADATA_TRANSFORMED_REQUEST "updatemetadata.xsl" #define DEFAULT_RAW_REQUEST "" #define DEFAULT_TRANSFORMED_REQUEST "" #define BUILDM3U_RAW_REQUEST "buildm3u" int admin_get_command(const char *command) { if(!strcmp(command, FALLBACK_RAW_REQUEST)) return COMMAND_RAW_FALLBACK; else if(!strcmp(command, FALLBACK_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_FALLBACK; else if(!strcmp(command, METADATA_RAW_REQUEST)) return COMMAND_RAW_METADATA_UPDATE; else if(!strcmp(command, METADATA_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_METADATA_UPDATE; else if(!strcmp(command, SHOUTCAST_METADATA_REQUEST)) return COMMAND_SHOUTCAST_METADATA_UPDATE; else if(!strcmp(command, LISTCLIENTS_RAW_REQUEST)) return COMMAND_RAW_SHOW_LISTENERS; else if(!strcmp(command, LISTCLIENTS_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_SHOW_LISTENERS; else if(!strcmp(command, STATS_RAW_REQUEST)) return COMMAND_RAW_STATS; else if(!strcmp(command, STATS_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_STATS; else if(!strcmp(command, "stats.xml")) /* The old way */ return COMMAND_RAW_STATS; else if(!strcmp(command, LISTMOUNTS_RAW_REQUEST)) return COMMAND_RAW_LIST_MOUNTS; else if(!strcmp(command, LISTMOUNTS_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_LIST_MOUNTS; else if(!strcmp(command, STREAMLIST_RAW_REQUEST)) return COMMAND_RAW_LISTSTREAM; else if(!strcmp(command, STREAMLIST_PLAINTEXT_REQUEST)) return COMMAND_PLAINTEXT_LISTSTREAM; else if(!strcmp(command, MOVECLIENTS_RAW_REQUEST)) return COMMAND_RAW_MOVE_CLIENTS; else if(!strcmp(command, MOVECLIENTS_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_MOVE_CLIENTS; else if(!strcmp(command, KILLCLIENT_RAW_REQUEST)) return COMMAND_RAW_KILL_CLIENT; else if(!strcmp(command, KILLCLIENT_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_KILL_CLIENT; else if(!strcmp(command, KILLSOURCE_RAW_REQUEST)) return COMMAND_RAW_KILL_SOURCE; else if(!strcmp(command, KILLSOURCE_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_KILL_SOURCE; else if(!strcmp(command, MANAGEAUTH_RAW_REQUEST)) return COMMAND_RAW_MANAGEAUTH; else if(!strcmp(command, MANAGEAUTH_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_MANAGEAUTH; else if(!strcmp(command, UPDATEMETADATA_RAW_REQUEST)) return COMMAND_RAW_UPDATEMETADATA; else if(!strcmp(command, UPDATEMETADATA_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_UPDATEMETADATA; else if(!strcmp(command, BUILDM3U_RAW_REQUEST)) return COMMAND_BUILDM3U; else if(!strcmp(command, DEFAULT_TRANSFORMED_REQUEST)) return COMMAND_TRANSFORMED_STATS; else if(!strcmp(command, DEFAULT_RAW_REQUEST)) return COMMAND_TRANSFORMED_STATS; else return COMMAND_ERROR; } static void command_fallback(client_t *client, source_t *source, int response); static void command_metadata(client_t *client, source_t *source, int response); static void command_shoutcast_metadata(client_t *client, source_t *source); static void command_show_listeners(client_t *client, source_t *source, int response); static void command_move_clients(client_t *client, source_t *source, int response); static void command_stats(client_t *client, const char *mount, int response); static void command_list_mounts(client_t *client, int response); static void command_kill_client(client_t *client, source_t *source, int response); static void command_manageauth(client_t *client, source_t *source, int response); static void command_buildm3u(client_t *client, const char *mount); static void command_kill_source(client_t *client, source_t *source, int response); static void command_updatemetadata(client_t *client, source_t *source, int response); static void admin_handle_mount_request(client_t *client, source_t *source, int command); static void admin_handle_general_request(client_t *client, int command); /* 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, MOUNT_TYPE_NORMAL); 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); } void admin_send_response (xmlDocPtr doc, client_t *client, int response, const char *xslt_template) { if (response == RAW) { xmlChar *buff = NULL; int len = 0; size_t buf_len; ssize_t ret; xmlDocDumpMemory(doc, &buff, &len); buf_len = len + 1024; if (buf_len < 4096) buf_len = 4096; client_set_queue (client, NULL); client->refbuf = refbuf_new (buf_len); ret = util_http_build_header(client->refbuf->data, buf_len, 0, 0, 200, NULL, "text/xml", "utf-8", NULL, NULL); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); xmlFree(buff); return; } else if (buf_len < (len + ret + 64)) { void *new_data; buf_len = ret + len + 64; new_data = realloc(client->refbuf->data, buf_len); if (new_data) { ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); client->refbuf->data = new_data; client->refbuf->len = buf_len; ret = util_http_build_header(client->refbuf->data, buf_len, 0, 0, 200, NULL, "text/xml", "utf-8", NULL, NULL); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); xmlFree(buff); return; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); client_send_500(client, "Buffer reallocation failed."); xmlFree(buff); return; } } /* FIXME: in this section we hope no function will ever return -1 */ ret += snprintf (client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff); client->refbuf->len = ret; xmlFree(buff); client->respcode = 200; fserve_add_client (client, NULL); } if (response == TRANSFORMED) { char *fullpath_xslt_template; int fullpath_xslt_template_len; ice_config_t *config = config_get_config(); fullpath_xslt_template_len = strlen (config->adminroot_dir) + strlen (xslt_template) + 2; fullpath_xslt_template = malloc(fullpath_xslt_template_len); snprintf(fullpath_xslt_template, fullpath_xslt_template_len, "%s%s%s", config->adminroot_dir, PATH_SEPARATOR, xslt_template); config_release_config(); ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template); xslt_transform(doc, fullpath_xslt_template, client); free(fullpath_xslt_template); } } void admin_handle_request(client_t *client, const char *uri) { const char *mount, *command_string; int command; ICECAST_LOG_DEBUG("Admin request (%s)", uri); if (!((strcmp(uri, "/admin.cgi") == 0) || (strncmp("/admin/", uri, 7) == 0))) { ICECAST_LOG_ERROR("Internal error: admin request isn't"); client_send_401(client); return; } if (strcmp(uri, "/admin.cgi") == 0) { command_string = uri + 1; } else { command_string = uri + 7; } ICECAST_LOG_DEBUG("Got command (%s)", command_string); command = admin_get_command(command_string); if(command < 0) { ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %s", command_string); client_send_400(client, "Unrecognised command"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE) { ice_config_t *config; const char *sc_mount; const char *pass = httpp_get_query_param (client->parser, "pass"); listener_t *listener; if (pass == NULL) { client_send_400 (client, "missing pass parameter"); return; } global_lock(); config = config_get_config (); sc_mount = config->shoutcast_mount; listener = config_get_listen_sock (config, client->con); if (listener && listener->shoutcast_mount) sc_mount = listener->shoutcast_mount; httpp_set_query_param (client->parser, "mount", sc_mount); httpp_setvar (client->parser, HTTPP_VAR_PROTOCOL, "ICY"); httpp_setvar (client->parser, HTTPP_VAR_ICYPASSWORD, pass); config_release_config (); global_unlock(); } mount = httpp_get_query_param(client->parser, "mount"); if(mount != NULL) { source_t *source; /* this request does not require auth but can apply to files on webroot */ if (command == COMMAND_BUILDM3U) { command_buildm3u (client, mount); return; } /* This is a mount request, handle it as such */ if (client->authenticated == 0 && !connection_check_admin_pass(client->parser)) { switch (client_check_source_auth (client, mount)) { case 0: break; default: ICECAST_LOG_INFO("Bad or missing password on mount modification admin " "request (command: %s)", command_string); client_send_401(client); /* fall through */ case 1: return; } } avl_tree_rlock(global.source_tree); source = source_find_mount_raw(mount); if (source == NULL) { ICECAST_LOG_WARN("Admin command %s on non-existent source %s", command_string, mount); avl_tree_unlock(global.source_tree); client_send_400(client, "Source does not exist"); } else { if (source->running == 0 && source->on_demand == 0) { avl_tree_unlock (global.source_tree); ICECAST_LOG_INFO("Received admin command %s on unavailable mount \"%s\"", command_string, mount); client_send_400 (client, "Source is not available"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE && source->shoutcast_compat == 0) { avl_tree_unlock (global.source_tree); ICECAST_LOG_ERROR("illegal change of metadata on non-shoutcast " "compatible stream"); client_send_400 (client, "illegal metadata call"); return; } ICECAST_LOG_INFO("Received admin command %s on mount \"%s\"", command_string, mount); admin_handle_mount_request(client, source, command); avl_tree_unlock(global.source_tree); } } else { if (command == COMMAND_PLAINTEXT_LISTSTREAM) { /* this request is used by a slave relay to retrieve mounts from the master, so handle this request validating against the relay password */ if(!connection_check_relay_pass(client->parser)) { ICECAST_LOG_INFO("Bad or missing password on admin command " "request (command: %s)", command_string); client_send_401(client); return; } } else { if(!connection_check_admin_pass(client->parser)) { ICECAST_LOG_INFO("Bad or missing password on admin command " "request (command: %s)", command_string); client_send_401(client); return; } } admin_handle_general_request(client, command); } } static void admin_handle_general_request(client_t *client, int command) { switch(command) { case COMMAND_RAW_STATS: command_stats(client, NULL, RAW); break; case COMMAND_RAW_LIST_MOUNTS: command_list_mounts(client, RAW); break; case COMMAND_RAW_LISTSTREAM: command_list_mounts(client, RAW); break; case COMMAND_PLAINTEXT_LISTSTREAM: command_list_mounts(client, PLAINTEXT); break; case COMMAND_TRANSFORMED_STATS: command_stats(client, NULL, TRANSFORMED); break; case COMMAND_TRANSFORMED_LIST_MOUNTS: command_list_mounts(client, TRANSFORMED); break; case COMMAND_TRANSFORMED_LISTSTREAM: command_list_mounts(client, TRANSFORMED); break; case COMMAND_TRANSFORMED_MOVE_CLIENTS: command_list_mounts(client, TRANSFORMED); break; default: ICECAST_LOG_WARN("General admin request not recognised"); client_send_400(client, "Unknown admin request"); return; } } static void admin_handle_mount_request(client_t *client, source_t *source, int command) { switch(command) { case COMMAND_RAW_STATS: command_stats(client, source->mount, RAW); break; case COMMAND_RAW_FALLBACK: command_fallback(client, source, RAW); break; case COMMAND_RAW_METADATA_UPDATE: command_metadata(client, source, RAW); break; case COMMAND_TRANSFORMED_METADATA_UPDATE: command_metadata(client, source, TRANSFORMED); break; case COMMAND_SHOUTCAST_METADATA_UPDATE: command_shoutcast_metadata(client, source); break; case COMMAND_RAW_SHOW_LISTENERS: command_show_listeners(client, source, RAW); break; case COMMAND_RAW_MOVE_CLIENTS: command_move_clients(client, source, RAW); break; case COMMAND_RAW_KILL_CLIENT: command_kill_client(client, source, RAW); break; case COMMAND_RAW_KILL_SOURCE: command_kill_source(client, source, RAW); break; case COMMAND_TRANSFORMED_STATS: command_stats(client, source->mount, TRANSFORMED); break; case COMMAND_TRANSFORMED_FALLBACK: command_fallback(client, source, RAW); break; case COMMAND_TRANSFORMED_SHOW_LISTENERS: command_show_listeners(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_MOVE_CLIENTS: command_move_clients(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_KILL_CLIENT: command_kill_client(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_KILL_SOURCE: command_kill_source(client, source, TRANSFORMED); break; case COMMAND_TRANSFORMED_MANAGEAUTH: command_manageauth(client, source, TRANSFORMED); break; case COMMAND_RAW_MANAGEAUTH: command_manageauth(client, source, RAW); break; case COMMAND_TRANSFORMED_UPDATEMETADATA: command_updatemetadata(client, source, TRANSFORMED); break; case COMMAND_RAW_UPDATEMETADATA: command_updatemetadata(client, source, RAW); break; default: ICECAST_LOG_WARN("Mount request not recognised"); client_send_400(client, "Mount request unknown"); break; } } #define COMMAND_REQUIRE(client,name,var) \ do { \ (var) = httpp_get_query_param((client)->parser, (name)); \ if((var) == NULL) { \ client_send_400((client), "Missing parameter"); \ return; \ } \ } while(0); #define COMMAND_OPTIONAL(client,name,var) \ (var) = httpp_get_query_param((client)->parser, (name)) static void html_success(client_t *client, char *message) { ssize_t ret; ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, 200, NULL, "text/html", "utf-8", "", NULL); if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); return; } snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Admin request successful" "

%s

", message); client->respcode = 200; client->refbuf->len = strlen (client->refbuf->data); fserve_add_client (client, NULL); } static void command_move_clients(client_t *client, source_t *source, int response) { const char *dest_source; source_t *dest; xmlDocPtr doc; xmlNodePtr node; char buf[255]; int parameters_passed = 0; ICECAST_LOG_DEBUG("Doing optional check"); if((COMMAND_OPTIONAL(client, "destination", dest_source))) { parameters_passed = 1; } ICECAST_LOG_DEBUG("Done optional check (%d)", parameters_passed); if (!parameters_passed) { doc = admin_build_sourcelist(source->mount); admin_send_response(doc, client, response, MOVECLIENTS_TRANSFORMED_REQUEST); xmlFreeDoc(doc); return; } dest = source_find_mount (dest_source); if (dest == NULL) { client_send_400 (client, "No such destination"); return; } if (strcmp (dest->mount, source->mount) == 0) { client_send_400 (client, "supplied mountpoints are identical"); return; } if (dest->running == 0 && dest->on_demand == 0) { client_send_400 (client, "Destination not running"); return; } ICECAST_LOG_INFO("source is \"%s\", destination is \"%s\"", source->mount, dest->mount); doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); source_move_clients (source, dest); memset(buf, '\000', sizeof(buf)); snprintf (buf, sizeof(buf), "Clients moved from %s to %s", source->mount, dest_source); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); } static void command_show_listeners(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node, srcnode, listenernode; avl_node *client_node; client_t *current; char buf[22]; const char *userAgent = NULL; time_t now = time(NULL); doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL); srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL); xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount)); xmlDocSetRootElement(doc, node); memset(buf, '\000', sizeof(buf)); snprintf (buf, sizeof(buf), "%lu", source->listeners); xmlNewChild(srcnode, NULL, XMLSTR("Listeners"), XMLSTR(buf)); avl_tree_rlock(source->client_tree); client_node = avl_get_first(source->client_tree); while(client_node) { current = (client_t *)client_node->key; listenernode = xmlNewChild(srcnode, NULL, XMLSTR("listener"), NULL); xmlNewChild(listenernode, NULL, XMLSTR("IP"), XMLSTR(current->con->ip)); userAgent = httpp_getvar(current->parser, "user-agent"); if (userAgent) { xmlNewChild(listenernode, NULL, XMLSTR("UserAgent"), XMLSTR(userAgent)); } else { xmlNewChild(listenernode, NULL, XMLSTR("UserAgent"), XMLSTR("Unknown")); } memset(buf, '\000', sizeof(buf)); snprintf(buf, sizeof(buf), "%lu", (unsigned long)(now - current->con->con_time)); xmlNewChild(listenernode, NULL, XMLSTR("Connected"), XMLSTR(buf)); memset(buf, '\000', sizeof(buf)); snprintf(buf, sizeof(buf)-1, "%lu", current->con->id); xmlNewChild(listenernode, NULL, XMLSTR("ID"), XMLSTR(buf)); if (current->username) { xmlNewChild(listenernode, NULL, XMLSTR("username"), XMLSTR(current->username)); } client_node = avl_get_next(client_node); } avl_tree_unlock(source->client_tree); admin_send_response(doc, client, response, LISTCLIENTS_TRANSFORMED_REQUEST); xmlFreeDoc(doc); } static void command_buildm3u(client_t *client, const char *mount) { const char *username = NULL; const char *password = NULL; ice_config_t *config; ssize_t ret; COMMAND_REQUIRE(client, "username", username); COMMAND_REQUIRE(client, "password", password); ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, 200, NULL, "audio/x-mpegurl", NULL, NULL, NULL); if (ret == -1 || ret >= (PER_CLIENT_REFBUF_SIZE - 512)) { /* we want at least 512 Byte left for data */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); return; } config = config_get_config(); snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Content-Disposition = attachment; filename=listen.m3u\r\n\r\n" "http://%s:%s@%s:%d%s\r\n", username, password, config->hostname, config->port, mount ); config_release_config(); client->respcode = 200; client->refbuf->len = strlen (client->refbuf->data); fserve_add_client (client, NULL); } static void command_manageauth(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node, srcnode, msgnode; const char *action = NULL; const char *username = NULL; char *message = NULL; int ret = AUTH_OK; ice_config_t *config = config_get_config (); mount_proxy *mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL); do { if (mountinfo == NULL || mountinfo->auth == NULL) { ICECAST_LOG_WARN("manage auth request for %s but no facility available", source->mount); break; } COMMAND_OPTIONAL(client, "action", action); COMMAND_OPTIONAL (client, "username", username); if (action == NULL) action = "list"; if (!strcmp(action, "add")) { const char *password = NULL; COMMAND_OPTIONAL (client, "password", password); if (username == NULL || password == NULL) { ICECAST_LOG_WARN("manage auth request add for %s but no user/pass", source->mount); break; } ret = mountinfo->auth->adduser(mountinfo->auth, username, password); if (ret == AUTH_FAILED) { message = strdup("User add failed - check the icecast error log"); } if (ret == AUTH_USERADDED) { message = strdup("User added"); } if (ret == AUTH_USEREXISTS) { message = strdup("User already exists - not added"); } } if (!strcmp(action, "delete")) { if (username == NULL) { ICECAST_LOG_WARN("manage auth request delete for %s but no username", source->mount); break; } ret = mountinfo->auth->deleteuser(mountinfo->auth, username); if (ret == AUTH_FAILED) { message = strdup("User delete failed - check the icecast error log"); } if (ret == AUTH_USERDELETED) { message = strdup("User deleted"); } } doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL); srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL); xmlSetProp(srcnode, XMLSTR("mount"), XMLSTR(source->mount)); if (message) { msgnode = xmlNewChild(node, NULL, XMLSTR("iceresponse"), NULL); xmlNewChild(msgnode, NULL, XMLSTR("message"), XMLSTR(message)); } xmlDocSetRootElement(doc, node); if (mountinfo && mountinfo->auth && mountinfo->auth->listuser) mountinfo->auth->listuser (mountinfo->auth, srcnode); config_release_config (); admin_send_response(doc, client, response, MANAGEAUTH_TRANSFORMED_REQUEST); free (message); xmlFreeDoc(doc); return; } while (0); config_release_config (); client_send_400 (client, "missing parameter"); } static void command_kill_source(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node; doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Source Removed")); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); xmlDocSetRootElement(doc, node); source->running = 0; admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); } static void command_kill_client(client_t *client, source_t *source, int response) { const char *idtext; int id; client_t *listener; xmlDocPtr doc; xmlNodePtr node; char buf[50] = ""; COMMAND_REQUIRE(client, "id", idtext); id = atoi(idtext); listener = source_find_client(source, id); doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); ICECAST_LOG_DEBUG("Response is %d", response); if(listener != NULL) { ICECAST_LOG_INFO("Admin request: client %d removed", id); /* This tags it for removal on the next iteration of the main source * loop */ listener->con->error = 1; memset(buf, '\000', sizeof(buf)); snprintf(buf, sizeof(buf)-1, "Client %d removed", id); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); } else { memset(buf, '\000', sizeof(buf)); snprintf(buf, sizeof(buf)-1, "Client %d not found", id); xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR(buf)); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("0")); } admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); } static void command_fallback(client_t *client, source_t *source, int response) { const char *fallback; char *old; ICECAST_LOG_DEBUG("Got fallback request"); COMMAND_REQUIRE(client, "fallback", fallback); old = source->fallback_mount; source->fallback_mount = strdup(fallback); free(old); html_success(client, "Fallback configured"); } static void command_metadata(client_t *client, source_t *source, int response) { const char *action; const char *song, *title, *artist, *charset; format_plugin_t *plugin; xmlDocPtr doc; xmlNodePtr node; int same_ip = 1; doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode (doc, NULL, XMLSTR("iceresponse"), NULL); xmlDocSetRootElement(doc, node); ICECAST_LOG_DEBUG("Got metadata update request"); COMMAND_REQUIRE(client, "mode", action); COMMAND_OPTIONAL(client, "song", song); COMMAND_OPTIONAL(client, "title", title); COMMAND_OPTIONAL(client, "artist", artist); COMMAND_OPTIONAL(client, "charset", charset); if (strcmp (action, "updinfo") != 0) { xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("No such action")); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("0")); admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); return; } plugin = source->format; if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0) if (response == RAW && connection_check_admin_pass (client->parser) == 0) same_ip = 0; if (same_ip && plugin && plugin->set_tag) { if (song) { plugin->set_tag (plugin, "song", song, charset); ICECAST_LOG_INFO("Metadata on mountpoint %s changed to \"%s\"", source->mount, song); } else { if (artist && title) { plugin->set_tag (plugin, "title", title, charset); plugin->set_tag (plugin, "artist", artist, charset); ICECAST_LOG_INFO("Metadata on mountpoint %s changed to \"%s - %s\"", source->mount, artist, title); } } /* updates are now done, let them be pushed into the stream */ plugin->set_tag (plugin, NULL, NULL, NULL); } else { xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Mountpoint will not accept URL updates")); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); return; } xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Metadata update successful")); xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1")); admin_send_response(doc, client, response, ADMIN_XSL_RESPONSE); xmlFreeDoc(doc); } static void command_shoutcast_metadata(client_t *client, source_t *source) { const char *action; const char *value; int same_ip = 1; ICECAST_LOG_DEBUG("Got shoutcast metadata update request"); COMMAND_REQUIRE(client, "mode", action); COMMAND_REQUIRE(client, "song", value); if (strcmp (action, "updinfo") != 0) { client_send_400 (client, "No such action"); return; } if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0) if (connection_check_admin_pass (client->parser) == 0) same_ip = 0; if (same_ip && source->format && source->format->set_tag) { source->format->set_tag (source->format, "title", value, NULL); source->format->set_tag (source->format, NULL, NULL, NULL); ICECAST_LOG_DEBUG("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); html_success(client, "Metadata update successful"); } else { client_send_400 (client, "mountpoint will not accept URL updates"); } } static void command_stats(client_t *client, const char *mount, int response) { xmlDocPtr doc; ICECAST_LOG_DEBUG("Stats request, sending xml stats"); doc = stats_get_xml(1, mount); admin_send_response(doc, client, response, STATS_TRANSFORMED_REQUEST); xmlFreeDoc(doc); return; } static void command_list_mounts(client_t *client, int response) { ICECAST_LOG_DEBUG("List mounts request"); if (response == PLAINTEXT) { ssize_t ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, 200, NULL, "text/plain", "utf-8", "", NULL); if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); return; } client->refbuf->len = strlen (client->refbuf->data); client->respcode = 200; client->refbuf->next = stats_get_streams (); fserve_add_client (client, NULL); } else { xmlDocPtr doc; avl_tree_rlock (global.source_tree); doc = admin_build_sourcelist(NULL); avl_tree_unlock (global.source_tree); admin_send_response(doc, client, response, LISTMOUNTS_TRANSFORMED_REQUEST); xmlFreeDoc(doc); } } static void command_updatemetadata(client_t *client, source_t *source, int response) { xmlDocPtr doc; xmlNodePtr node, srcnode; doc = xmlNewDoc (XMLSTR("1.0")); node = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL); srcnode = xmlNewChild (node, NULL, XMLSTR("source"), NULL); xmlSetProp (srcnode, XMLSTR("mount"), XMLSTR(source->mount)); xmlDocSetRootElement(doc, node); admin_send_response(doc, client, response, UPDATEMETADATA_TRANSFORMED_REQUEST); xmlFreeDoc(doc); } icecast-2.4.2/src/xslt.c0000664000175000017500000001771512511160565012017 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef WIN32 #define snprintf _snprintf #endif #include "thread/thread.h" #include "avl/avl.h" #include "httpp/httpp.h" #include "net/sock.h" #include "connection.h" #include "global.h" #include "refbuf.h" #include "client.h" #include "stats.h" #include "fserve.h" #include "util.h" #define CATMODULE "xslt" #include "logging.h" typedef struct { char *filename; time_t last_modified; time_t cache_age; xsltStylesheetPtr stylesheet; } stylesheet_cache_t; #ifndef HAVE_XSLTSAVERESULTTOSTRING int xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, xmlDocPtr result, xsltStylesheetPtr style) { xmlOutputBufferPtr buf; *doc_txt_ptr = NULL; *doc_txt_len = 0; if (result->children == NULL) return(0); buf = xmlAllocOutputBuffer(NULL); if (buf == NULL) return(-1); xsltSaveResultTo(buf, result, style); if (buf->conv != NULL) { *doc_txt_len = buf->conv->use; *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len); } else { *doc_txt_len = buf->buffer->use; *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len); } (void)xmlOutputBufferClose(buf); return 0; } #endif /* Keep it small... */ #define CACHESIZE 3 static stylesheet_cache_t cache[CACHESIZE]; static mutex_t xsltlock; void xslt_initialize(void) { memset(cache, 0, sizeof(stylesheet_cache_t)*CACHESIZE); thread_mutex_create(&xsltlock); xmlInitParser(); LIBXML_TEST_VERSION xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; } void xslt_shutdown(void) { int i; for(i=0; i < CACHESIZE; i++) { if(cache[i].filename) free(cache[i].filename); if(cache[i].stylesheet) xsltFreeStylesheet(cache[i].stylesheet); } thread_mutex_destroy (&xsltlock); xmlCleanupParser(); xsltCleanupGlobals(); } static int evict_cache_entry(void) { int i, age=0, oldest=0; for(i=0; i < CACHESIZE; i++) { if(cache[i].cache_age > age) { age = cache[i].cache_age; oldest = i; } } xsltFreeStylesheet(cache[oldest].stylesheet); free(cache[oldest].filename); return oldest; } static xsltStylesheetPtr xslt_get_stylesheet(const char *fn) { int i; int empty = -1; struct stat file; if(stat(fn, &file)) { ICECAST_LOG_WARN("Error checking for stylesheet file \"%s\": %s", fn, strerror(errno)); return NULL; } for(i=0; i < CACHESIZE; i++) { if(cache[i].filename) { #ifdef _WIN32 if(!stricmp(fn, cache[i].filename)) #else if(!strcmp(fn, cache[i].filename)) #endif { if(file.st_mtime > cache[i].last_modified) { xsltFreeStylesheet(cache[i].stylesheet); cache[i].last_modified = file.st_mtime; cache[i].stylesheet = xsltParseStylesheetFile (XMLSTR(fn)); cache[i].cache_age = time(NULL); } ICECAST_LOG_DEBUG("Using cached sheet %i", i); return cache[i].stylesheet; } } else empty = i; } if(empty>=0) i = empty; else i = evict_cache_entry(); cache[i].last_modified = file.st_mtime; cache[i].filename = strdup(fn); cache[i].stylesheet = xsltParseStylesheetFile (XMLSTR(fn)); cache[i].cache_age = time(NULL); return cache[i].stylesheet; } void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) { xmlDocPtr res; xsltStylesheetPtr cur; xmlChar *string; int len, problem = 0; const char *mediatype = NULL; const char *charset = NULL; xmlSetGenericErrorFunc ("", log_parse_failure); xsltSetGenericErrorFunc ("", log_parse_failure); thread_mutex_lock(&xsltlock); cur = xslt_get_stylesheet(xslfilename); if (cur == NULL) { thread_mutex_unlock(&xsltlock); ICECAST_LOG_ERROR("problem reading stylesheet \"%s\"", xslfilename); client_send_404 (client, "Could not parse XSLT file"); return; } res = xsltApplyStylesheet(cur, doc, NULL); if (xsltSaveResultToString (&string, &len, res, cur) < 0) problem = 1; /* lets find out the content type and character encoding to use */ if (cur->encoding) charset = (char *)cur->encoding; 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"; } if (problem == 0) { ssize_t ret; int failed = 0; refbuf_t *refbuf; size_t full_len = strlen (mediatype) + len + 1024; if (full_len < 4096) full_len = 4096; refbuf = refbuf_new (full_len); if (string == NULL) string = xmlCharStrdup (""); ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); } else { if ( full_len < (ret + len + 64) ) { void *new_data; full_len = ret + len + 64; new_data = realloc(refbuf->data, full_len); if (new_data) { ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); refbuf->data = new_data; refbuf->len = full_len; ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_500(client, "Header generation failed."); failed = 1; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); client_send_500(client, "Buffer reallocation failed."); failed = 1; } } if (!failed) { snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string); client->respcode = 200; client_set_queue (client, NULL); client->refbuf = refbuf; refbuf->len = strlen (refbuf->data); fserve_add_client (client, NULL); } } xmlFree (string); } else { ICECAST_LOG_WARN("problem applying stylesheet \"%s\"", xslfilename); client_send_404 (client, "XSLT problem"); } thread_mutex_unlock (&xsltlock); xmlFreeDoc(res); } icecast-2.4.2/src/thread/0000775000175000017500000000000012511177344012200 500000000000000icecast-2.4.2/src/thread/thread.h0000664000175000017500000001610312511160565013536 00000000000000/* thread.h * - Thread Abstraction Function Headers * * Copyright (c) 1999, 2000 the icecast team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __THREAD_H__ #define __THREAD_H__ #include /* renamed from thread_t due to conflict on OS X */ typedef struct { /* the local id for the thread, and it's name */ long thread_id; char *name; /* the time the thread was created */ time_t create_time; /* the file and line which created this thread */ char *file; int line; /* is the thread running detached? */ int detached; /* the system specific thread */ pthread_t sys_thread; } thread_type; typedef struct { #ifdef DEBUG_MUTEXES /* the local id and name of the mutex */ long mutex_id; char *name; /* the thread which is currently locking this mutex */ long thread_id; /* the file and line where the mutex was locked */ char *file; int line; #endif /* the system specific mutex */ pthread_mutex_t sys_mutex; } mutex_t; typedef struct { #ifdef THREAD_DEBUG long cond_id; char *name; #endif pthread_mutex_t cond_mutex; pthread_cond_t sys_cond; } cond_t; typedef struct { #ifdef THREAD_DEBUG long rwlock_id; char *name; /* information on which thread and where in the code ** this rwlock was write locked */ long thread_id; char *file; int line; #endif pthread_rwlock_t sys_rwlock; } rwlock_t; #ifdef HAVE_PTHREAD_SPIN_LOCK typedef struct { pthread_spinlock_t lock; } spin_t; void thread_spin_create (spin_t *spin); void thread_spin_destroy (spin_t *spin); void thread_spin_lock (spin_t *spin); void thread_spin_unlock (spin_t *spin); #else typedef mutex_t spin_t; #define thread_spin_create(x) thread_mutex_create(x) #define thread_spin_destroy(x) thread_mutex_destroy(x) #define thread_spin_lock(x) thread_mutex_lock(x) #define thread_spin_unlock(x) thread_mutex_unlock(x) #endif #define thread_create(n,x,y,z) thread_create_c(n,x,y,z,__LINE__,__FILE__) #define thread_mutex_create(x) thread_mutex_create_c(x,__LINE__,__FILE__) #define thread_mutex_lock(x) thread_mutex_lock_c(x,__LINE__,__FILE__) #define thread_mutex_unlock(x) thread_mutex_unlock_c(x,__LINE__,__FILE__) #define thread_cond_create(x) thread_cond_create_c(x,__LINE__,__FILE__) #define thread_cond_signal(x) thread_cond_signal_c(x,__LINE__,__FILE__) #define thread_cond_broadcast(x) thread_cond_broadcast_c(x,__LINE__,__FILE__) #define thread_cond_wait(x) thread_cond_wait_c(x,__LINE__,__FILE__) #define thread_cond_timedwait(x,t) thread_cond_wait_c(x,t,__LINE__,__FILE__) #define thread_rwlock_create(x) thread_rwlock_create_c(x,__LINE__,__FILE__) #define thread_rwlock_rlock(x) thread_rwlock_rlock_c(x,__LINE__,__FILE__) #define thread_rwlock_wlock(x) thread_rwlock_wlock_c(x,__LINE__,__FILE__) #define thread_rwlock_unlock(x) thread_rwlock_unlock_c(x,__LINE__,__FILE__) #define thread_exit(x) thread_exit_c(x,__LINE__,__FILE__) #define MUTEX_STATE_NOTLOCKED -1 #define MUTEX_STATE_NEVERLOCKED -2 #define MUTEX_STATE_UNINIT -3 #define THREAD_DETACHED 1 #define THREAD_ATTACHED 0 #ifdef _mangle # define thread_initialize _mangle(thread_initialize) # define thread_initialize_with_log_id _mangle(thread_initialize_with_log_id) # define thread_shutdown _mangle(thread_shutdown) # define thread_create_c _mangle(thread_create_c) # define thread_mutex_create_c _mangle(thread_mutex_create) # define thread_mutex_lock_c _mangle(thread_mutex_lock_c) # define thread_mutex_unlock_c _mangle(thread_mutex_unlock_c) # define thread_mutex_destroy _mangle(thread_mutex_destroy) # define thread_cond_create_c _mangle(thread_cond_create_c) # define thread_cond_signal_c _mangle(thread_cond_signal_c) # define thread_cond_broadcast_c _mangle(thread_cond_broadcast_c) # define thread_cond_wait_c _mangle(thread_cond_wait_c) # define thread_cond_timedwait_c _mangle(thread_cond_timedwait_c) # define thread_cond_destroy _mangle(thread_cond_destroy) # define thread_rwlock_create_c _mangle(thread_rwlock_create_c) # define thread_rwlock_rlock_c _mangle(thread_rwlock_rlock_c) # define thread_rwlock_wlock_c _mangle(thread_rwlock_wlock_c) # define thread_rwlock_unlock_c _mangle(thread_rwlock_unlock_c) # define thread_rwlock_destroy _mangle(thread_rwlock_destroy) # define thread_exit_c _mangle(thread_exit_c) # define thread_sleep _mangle(thread_sleep) # define thread_library_lock _mangle(thread_library_lock) # define thread_library_unlock _mangle(thread_library_unlock) # define thread_self _mangle(thread_self) # define thread_rename _mangle(thread_rename) # define thread_join _mangle(thread_join) #endif /* init/shutdown of the library */ void thread_initialize(void); void thread_initialize_with_log_id(int log_id); void thread_shutdown(void); /* creation, destruction, locking, unlocking, signalling and waiting */ thread_type *thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int detached, int line, char *file); void thread_mutex_create_c(mutex_t *mutex, int line, char *file); void thread_mutex_lock_c(mutex_t *mutex, int line, char *file); void thread_mutex_unlock_c(mutex_t *mutex, int line, char *file); void thread_mutex_destroy(mutex_t *mutex); void thread_cond_create_c(cond_t *cond, int line, char *file); void thread_cond_signal_c(cond_t *cond, int line, char *file); void thread_cond_broadcast_c(cond_t *cond, int line, char *file); void thread_cond_wait_c(cond_t *cond, int line, char *file); void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file); void thread_cond_destroy(cond_t *cond); void thread_rwlock_create_c(rwlock_t *rwlock, int line, char *file); void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, char *file); void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, char *file); void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, char *file); void thread_rwlock_destroy(rwlock_t *rwlock); void thread_exit_c(long val, int line, char *file); /* sleeping */ void thread_sleep(unsigned long len); /* for using library functions which aren't threadsafe */ void thread_library_lock(void); void thread_library_unlock(void); #define PROTECT_CODE(code) { thread_library_lock(); code; thread_library_unlock(); } /* thread information functions */ thread_type *thread_self(void); /* renames current thread */ void thread_rename(const char *name); /* waits until thread_exit is called for another thread */ void thread_join(thread_type *thread); #endif /* __THREAD_H__ */ icecast-2.4.2/src/thread/README0000664000175000017500000000047112511160565012777 00000000000000This is the cross platform thread and syncronization library. It depends on the avl library. This is a massively cleaned and picked through version of the code from the icecast 1.3.x base. It has not been heavily tested *YET*. But since it's just cleanups, it really shouldn't have that many problems. jack. icecast-2.4.2/src/thread/Makefile.am0000664000175000017500000000056212511160565014154 00000000000000## Process this with automake to create Makefile.in AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO noinst_LTLIBRARIES = libicethread.la noinst_HEADERS = thread.h libicethread_la_SOURCES = thread.c libicethread_la_CFLAGS = @XIPH_CFLAGS@ INCLUDES = -I$(srcdir)/.. debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" icecast-2.4.2/src/thread/TODO0000664000175000017500000000025212511160565012604 00000000000000- make DEBUG_MUTEXES and CHECK_MUTEXES work - recursive locking/unlocking (easy) - reader/writer locking (easy) - make a mode were _log is disabled (normal mode) (easy) icecast-2.4.2/src/thread/Makefile.in0000664000175000017500000004754612511177306014203 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/thread DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) COPYING README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ogg.m4 \ $(top_srcdir)/m4/speex.m4 $(top_srcdir)/m4/theora.m4 \ $(top_srcdir)/m4/vorbis.m4 $(top_srcdir)/m4/xiph_compiler.m4 \ $(top_srcdir)/m4/xiph_curl.m4 $(top_srcdir)/m4/xiph_net.m4 \ $(top_srcdir)/m4/xiph_openssl.m4 \ $(top_srcdir)/m4/xiph_types.m4 $(top_srcdir)/m4/xiph_xml2.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libicethread_la_LIBADD = am_libicethread_la_OBJECTS = libicethread_la-thread.lo libicethread_la_OBJECTS = $(am_libicethread_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libicethread_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libicethread_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libicethread_la_SOURCES) DIST_SOURCES = $(libicethread_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURL_CFLAGS = @CURL_CFLAGS@ CURL_CONFIG = @CURL_CONFIG@ CURL_LIBS = @CURL_LIBS@ CYGPATH_W = @CYGPATH_W@ DEBUG = @DEBUG@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ HAVE_KATE = @HAVE_KATE@ ICECAST_OPTIONAL = @ICECAST_OPTIONAL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KATE_LIBS = @KATE_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OGG_CFLAGS = @OGG_CFLAGS@ OGG_LDFLAGS = @OGG_LDFLAGS@ OGG_LIBS = @OGG_LIBS@ OGG_PREFIX = @OGG_PREFIX@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGCONFIG = @PKGCONFIG@ PROFILE = @PROFILE@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SPEEX = @SPEEX@ SPEEX_CFLAGS = @SPEEX_CFLAGS@ SPEEX_LDFLAGS = @SPEEX_LDFLAGS@ SPEEX_LIBS = @SPEEX_LIBS@ STRIP = @STRIP@ THEORA = @THEORA@ THEORA_CFLAGS = @THEORA_CFLAGS@ THEORA_LDFLAGS = @THEORA_LDFLAGS@ THEORA_LIBS = @THEORA_LIBS@ VERSION = @VERSION@ VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISFILE_LIBS = @VORBISFILE_LIBS@ VORBIS_CFLAGS = @VORBIS_CFLAGS@ VORBIS_LDFLAGS = @VORBIS_LDFLAGS@ VORBIS_LIBS = @VORBIS_LIBS@ VORBIS_PREFIX = @VORBIS_PREFIX@ XIPH_CFLAGS = @XIPH_CFLAGS@ XIPH_CPPFLAGS = @XIPH_CPPFLAGS@ XIPH_LDFLAGS = @XIPH_LDFLAGS@ XIPH_LIBS = @XIPH_LIBS@ XSLTCONFIG = @XSLTCONFIG@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign EXTRA_DIST = BUILDING COPYING README TODO noinst_LTLIBRARIES = libicethread.la noinst_HEADERS = thread.h libicethread_la_SOURCES = thread.c libicethread_la_CFLAGS = @XIPH_CFLAGS@ INCLUDES = -I$(srcdir)/.. all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/thread/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/thread/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libicethread.la: $(libicethread_la_OBJECTS) $(libicethread_la_DEPENDENCIES) $(EXTRA_libicethread_la_DEPENDENCIES) $(AM_V_CCLD)$(libicethread_la_LINK) $(libicethread_la_OBJECTS) $(libicethread_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libicethread_la-thread.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libicethread_la-thread.lo: thread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicethread_la_CFLAGS) $(CFLAGS) -MT libicethread_la-thread.lo -MD -MP -MF $(DEPDIR)/libicethread_la-thread.Tpo -c -o libicethread_la-thread.lo `test -f 'thread.c' || echo '$(srcdir)/'`thread.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libicethread_la-thread.Tpo $(DEPDIR)/libicethread_la-thread.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread.c' object='libicethread_la-thread.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libicethread_la_CFLAGS) $(CFLAGS) -c -o libicethread_la-thread.lo `test -f 'thread.c' || echo '$(srcdir)/'`thread.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am debug: $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: icecast-2.4.2/src/thread/BUILDING0000664000175000017500000000062512511160565013240 00000000000000defines that affect compilation _WIN32 this should be defined for Win32 platforms DEBUG_MUTEXES define this to turn on mutex debugging. this will log locks/unlocks. CHECK_MUTEXES (DEBUG_MUTEXES must also be defined) checks to make sure mutex operations make sense. ie, multi_mutex is locked when locking multiple mutexes, etc. THREAD_DEBUG (define to 1-4) turns on the thread.log logging icecast-2.4.2/src/thread/thread.c0000664000175000017500000005230212511160565013532 00000000000000/* threads.c: Thread Abstraction Functions * * Copyright (c) 1999, 2000 the icecast team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #ifndef _WIN32 #include #include #else #include #include #endif #include #include #include #ifdef THREAD_DEBUG #include #endif #ifdef _WIN32 #define __FUNCTION__ __FILE__ #endif #ifdef THREAD_DEBUG #define CATMODULE "thread" #define LOG_ERROR(y) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y) #define LOG_ERROR3(y, z1, z2, z3) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y, z1, z2, z3) #define LOG_ERROR7(y, z1, z2, z3, z4, z5, z6, z7) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5, z6, z7) #define LOG_WARN(y) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y) #define LOG_WARN3(y, z1, z2, z3) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3) #define LOG_WARN5(y, z1, z2, z3, z4, z5) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5) #define LOG_WARN7(y, z1, z2, z3, z4, z5, z6, z7) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5, z6, z7) #define LOG_INFO(y) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y) #define LOG_INFO4(y, z1, z2, z3, z4) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4) #define LOG_INFO5(y, z1, z2, z3, z4, z5) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5) #define LOG_DEBUG(y) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y) #define LOG_DEBUG2(y, z1, z2) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2) #define LOG_DEBUG5(y, z1, z2, z3, z4, z5) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5) #endif /* thread starting structure */ typedef struct thread_start_tag { /* the real start routine and arg */ void *(*start_routine)(void *); void *arg; /* the other stuff we need to make sure this thread is inserted into ** the thread tree */ thread_type *thread; pthread_t sys_thread; } thread_start_t; static long _next_thread_id = 0; static int _initialized = 0; static avl_tree *_threadtree = NULL; #ifdef DEBUG_MUTEXES static mutex_t _threadtree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, PTHREAD_MUTEX_INITIALIZER}; #else static mutex_t _threadtree_mutex = { PTHREAD_MUTEX_INITIALIZER }; #endif #ifdef DEBUG_MUTEXES static int _logid = -1; static long _next_mutex_id = 0; static avl_tree *_mutextree = NULL; static mutex_t _mutextree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, PTHREAD_MUTEX_INITIALIZER}; #endif #ifdef DEBUG_MUTEXES static mutex_t _library_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, PTHREAD_MUTEX_INITIALIZER}; #else static mutex_t _library_mutex = { PTHREAD_MUTEX_INITIALIZER }; #endif /* INTERNAL FUNCTIONS */ /* avl tree functions */ #ifdef DEBUG_MUTEXES static int _compare_mutexes(void *compare_arg, void *a, void *b); static int _free_mutex(void *key); #endif static int _compare_threads(void *compare_arg, void *a, void *b); static int _free_thread(void *key); /* mutex fuctions */ static void _mutex_create(mutex_t *mutex); static void _mutex_lock(mutex_t *mutex); static void _mutex_unlock(mutex_t *mutex); /* misc thread stuff */ static void *_start_routine(void *arg); static void _catch_signals(void); static void _block_signals(void); /* LIBRARY INITIALIZATION */ void thread_initialize(void) { thread_type *thread; /* set up logging */ #ifdef THREAD_DEBUG log_initialize(); _logid = log_open("thread.log"); log_set_level(_logid, THREAD_DEBUG); #endif #ifdef DEBUG_MUTEXES /* create all the internal mutexes, and initialize the mutex tree */ _mutextree = avl_tree_new(_compare_mutexes, NULL); /* we have to create this one by hand, because there's no ** mutextree_mutex to lock yet! */ _mutex_create(&_mutextree_mutex); _mutextree_mutex.mutex_id = _next_mutex_id++; avl_insert(_mutextree, (void *)&_mutextree_mutex); #endif thread_mutex_create(&_threadtree_mutex); thread_mutex_create(&_library_mutex); /* initialize the thread tree and insert the main thread */ _threadtree = avl_tree_new(_compare_threads, NULL); thread = (thread_type *)malloc(sizeof(thread_type)); thread->thread_id = _next_thread_id++; thread->line = 0; thread->file = strdup("main.c"); thread->sys_thread = pthread_self(); thread->create_time = time(NULL); thread->name = strdup("Main Thread"); avl_insert(_threadtree, (void *)thread); _catch_signals(); _initialized = 1; } void thread_shutdown(void) { if (_initialized == 1) { thread_mutex_destroy(&_library_mutex); thread_mutex_destroy(&_threadtree_mutex); #ifdef THREAD_DEBUG thread_mutex_destroy(&_mutextree_mutex); avl_tree_free(_mutextree, _free_mutex); #endif avl_tree_free(_threadtree, _free_thread); _threadtree = NULL; } #ifdef THREAD_DEBUG log_close(_logid); log_shutdown(); #endif } /* * Signals should be handled by the main thread, nowhere else. * I'm using POSIX signal interface here, until someone tells me * that I should use signal/sigset instead * * This function only valid for non-Win32 */ static void _block_signals(void) { #ifndef _WIN32 sigset_t ss; sigfillset(&ss); /* These ones we want */ sigdelset(&ss, SIGKILL); sigdelset(&ss, SIGSTOP); sigdelset(&ss, SIGSEGV); sigdelset(&ss, SIGCHLD); sigdelset(&ss, SIGBUS); if (pthread_sigmask(SIG_BLOCK, &ss, NULL) != 0) { #ifdef THREAD_DEBUG LOG_ERROR("Pthread_sigmask() failed for blocking signals"); #endif } #endif } /* * Let the calling thread catch all the relevant signals * * This function only valid for non-Win32 */ static void _catch_signals(void) { #ifndef _WIN32 sigset_t ss; sigemptyset(&ss); /* These ones should only be accepted by the signal handling thread (main thread) */ sigaddset(&ss, SIGHUP); sigaddset(&ss, SIGCHLD); sigaddset(&ss, SIGINT); sigaddset(&ss, SIGPIPE); sigaddset(&ss, SIGTERM); if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) != 0) { #ifdef THREAD_DEBUG LOG_ERROR("pthread_sigmask() failed for catching signals!"); #endif } #endif } thread_type *thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int detached, int line, char *file) { int ok = 1; thread_type *thread = NULL; thread_start_t *start = NULL; pthread_attr_t attr; thread = (thread_type *)calloc(1, sizeof(thread_type)); do { if (thread == NULL) break; start = (thread_start_t *)calloc(1, sizeof(thread_start_t)); if (start == NULL) break; if (pthread_attr_init (&attr) < 0) break; thread->line = line; thread->file = strdup(file); _mutex_lock (&_threadtree_mutex); thread->thread_id = _next_thread_id++; _mutex_unlock (&_threadtree_mutex); thread->name = strdup(name); thread->create_time = time(NULL); start->start_routine = start_routine; start->arg = arg; start->thread = thread; pthread_attr_setstacksize (&attr, 512*1024); pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED); if (detached) { pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); thread->detached = 1; } if (pthread_create (&thread->sys_thread, &attr, _start_routine, start) == 0) { pthread_attr_destroy (&attr); return thread; } else pthread_attr_destroy (&attr); } while (0); #ifdef THREAD_DEBUG LOG_ERROR("Could not create new thread %s", name); #endif if (start) free (start); if (thread) free (thread); return NULL; } /* _mutex_create ** ** creates a mutex */ static void _mutex_create(mutex_t *mutex) { #ifdef DEBUG_MUTEXES mutex->thread_id = MUTEX_STATE_NEVERLOCKED; mutex->line = -1; #endif pthread_mutex_init(&mutex->sys_mutex, NULL); } void thread_mutex_create_c(mutex_t *mutex, int line, char *file) { _mutex_create(mutex); #ifdef DEBUG_MUTEXES _mutex_lock(&_mutextree_mutex); mutex->mutex_id = _next_mutex_id++; avl_insert(_mutextree, (void *)mutex); _mutex_unlock(&_mutextree_mutex); #endif } void thread_mutex_destroy (mutex_t *mutex) { pthread_mutex_destroy(&mutex->sys_mutex); #ifdef DEBUG_MUTEXES _mutex_lock(&_mutextree_mutex); avl_delete(_mutextree, mutex, _free_mutex); _mutex_unlock(&_mutextree_mutex); #endif } void thread_mutex_lock_c(mutex_t *mutex, int line, char *file) { #ifdef DEBUG_MUTEXES thread_type *th = thread_self(); if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line); LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); # ifdef CHECK_MUTEXES /* Just a little sanity checking to make sure that we're locking ** mutexes correctly */ if (th) { int locks = 0; avl_node *node; mutex_t *tmutex; _mutex_lock(&_mutextree_mutex); node = avl_get_first (_mutextree); while (node) { tmutex = (mutex_t *)node->key; if (tmutex->mutex_id == mutex->mutex_id) { if (tmutex->thread_id == th->thread_id) { /* Deadlock, same thread can't lock the same mutex twice */ LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name); _mutex_unlock(&_mutextree_mutex); return; } } else if (tmutex->thread_id == th->thread_id) { /* Mutex locked by this thread (not this mutex) */ locks++; } node = avl_get_next(node); } if (locks > 0) { /* Has already got a mutex locked */ if (_multi_mutex.thread_id != th->thread_id) { /* Tries to lock two mutexes, but has not got the double mutex, norty boy! */ LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!", _multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line); } } _mutex_unlock(&_mutextree_mutex); } # endif /* CHECK_MUTEXES */ _mutex_lock(mutex); _mutex_lock(&_mutextree_mutex); LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1); mutex->line = line; if (th) { mutex->thread_id = th->thread_id; } _mutex_unlock(&_mutextree_mutex); #else _mutex_lock(mutex); #endif /* DEBUG_MUTEXES */ } void thread_mutex_unlock_c(mutex_t *mutex, int line, char *file) { #ifdef DEBUG_MUTEXES thread_type *th = thread_self(); if (!th) { LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line); } LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); mutex->line = line; # ifdef CHECK_MUTEXES if (th) { int locks = 0; avl_node *node; mutex_t *tmutex; _mutex_lock(&_mutextree_mutex); while (node) { tmutex = (mutex_t *)node->key; if (tmutex->mutex_id == mutex->mutex_id) { if (tmutex->thread_id != th->thread_id) { LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name); _mutex_unlock(&_mutextree_mutex); return; } } else if (tmutex->thread_id == th->thread_id) { locks++; } node = avl_get_next (node); } if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) { /* Don't have double mutex, has more than this mutex left */ LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!", _multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line); } _mutex_unlock(&_mutextree_mutex); } # endif /* CHECK_MUTEXES */ _mutex_unlock(mutex); _mutex_lock(&_mutextree_mutex); LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1); mutex->line = -1; if (mutex->thread_id == th->thread_id) { mutex->thread_id = MUTEX_STATE_NOTLOCKED; } _mutex_unlock(&_mutextree_mutex); #else _mutex_unlock(mutex); #endif /* DEBUG_MUTEXES */ } void thread_cond_create_c(cond_t *cond, int line, char *file) { pthread_cond_init(&cond->sys_cond, NULL); pthread_mutex_init(&cond->cond_mutex, NULL); } void thread_cond_destroy(cond_t *cond) { pthread_mutex_destroy(&cond->cond_mutex); pthread_cond_destroy(&cond->sys_cond); } void thread_cond_signal_c(cond_t *cond, int line, char *file) { pthread_cond_signal(&cond->sys_cond); } void thread_cond_broadcast_c(cond_t *cond, int line, char *file) { pthread_cond_broadcast(&cond->sys_cond); } void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file) { struct timespec time; time.tv_sec = millis/1000; time.tv_nsec = (millis - time.tv_sec*1000)*1000000; pthread_mutex_lock(&cond->cond_mutex); pthread_cond_timedwait(&cond->sys_cond, &cond->cond_mutex, &time); pthread_mutex_unlock(&cond->cond_mutex); } void thread_cond_wait_c(cond_t *cond, int line, char *file) { pthread_mutex_lock(&cond->cond_mutex); pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex); pthread_mutex_unlock(&cond->cond_mutex); } void thread_rwlock_create_c(rwlock_t *rwlock, int line, char *file) { pthread_rwlock_init(&rwlock->sys_rwlock, NULL); } void thread_rwlock_destroy(rwlock_t *rwlock) { pthread_rwlock_destroy(&rwlock->sys_rwlock); } void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, char *file) { pthread_rwlock_rdlock(&rwlock->sys_rwlock); } void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, char *file) { pthread_rwlock_wrlock(&rwlock->sys_rwlock); } void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, char *file) { pthread_rwlock_unlock(&rwlock->sys_rwlock); } void thread_exit_c(long val, int line, char *file) { thread_type *th = thread_self(); #if defined(DEBUG_MUTEXES) && defined(CHECK_MUTEXES) if (th) { avl_node *node; mutex_t *tmutex; char name[40]; _mutex_lock(&_mutextree_mutex); while (node) { tmutex = (mutex_t *)node->key; if (tmutex->thread_id == th->thread_id) { LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]", th->thread_id, th->name, file, line, mutex_to_string(tmutex, name)); } node = avl_get_next (node); } _mutex_unlock(&_mutextree_mutex); } #endif if (th && th->detached) { #ifdef THREAD_DEBUG LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line); #endif _mutex_lock(&_threadtree_mutex); avl_delete(_threadtree, th, _free_thread); _mutex_unlock(&_threadtree_mutex); } pthread_exit ((void*)val); } /* sleep for a number of microseconds */ void thread_sleep(unsigned long len) { #ifdef _WIN32 Sleep(len / 1000); #else # ifdef HAVE_NANOSLEEP struct timespec time_sleep; struct timespec time_remaining; int ret; time_sleep.tv_sec = len / 1000000; time_sleep.tv_nsec = (len % 1000000) * 1000; ret = nanosleep(&time_sleep, &time_remaining); while (ret != 0 && errno == EINTR) { time_sleep.tv_sec = time_remaining.tv_sec; time_sleep.tv_nsec = time_remaining.tv_nsec; ret = nanosleep(&time_sleep, &time_remaining); } # else struct timeval tv; tv.tv_sec = len / 1000000; tv.tv_usec = (len % 1000000); select(0, NULL, NULL, NULL, &tv); # endif #endif } static void *_start_routine(void *arg) { thread_start_t *start = (thread_start_t *)arg; void *(*start_routine)(void *) = start->start_routine; void *real_arg = start->arg; thread_type *thread = start->thread; _block_signals(); /* insert thread into thread tree here */ _mutex_lock(&_threadtree_mutex); thread->sys_thread = pthread_self(); avl_insert(_threadtree, (void *)thread); _mutex_unlock(&_threadtree_mutex); #ifdef THREAD_DEBUG LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line); #endif pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); free (start); (start_routine)(real_arg); if (thread->detached) { _mutex_lock (&_threadtree_mutex); avl_delete (_threadtree, thread, _free_thread); _mutex_unlock (&_threadtree_mutex); } return NULL; } thread_type *thread_self(void) { avl_node *node; thread_type *th; pthread_t sys_thread = pthread_self(); _mutex_lock(&_threadtree_mutex); if (_threadtree == NULL) { #ifdef THREAD_DEBUG LOG_WARN("Thread tree is empty, this must be wrong!"); #endif _mutex_unlock(&_threadtree_mutex); return NULL; } node = avl_get_first(_threadtree); while (node) { th = (thread_type *)node->key; if (th && pthread_equal(sys_thread, th->sys_thread)) { _mutex_unlock(&_threadtree_mutex); return th; } node = avl_get_next(node); } _mutex_unlock(&_threadtree_mutex); #ifdef THREAD_DEBUG LOG_ERROR("Nonexistant thread alive..."); #endif return NULL; } void thread_rename(const char *name) { thread_type *th; th = thread_self(); if (th->name) free(th->name); th->name = strdup(name); } static void _mutex_lock(mutex_t *mutex) { pthread_mutex_lock(&mutex->sys_mutex); } static void _mutex_unlock(mutex_t *mutex) { pthread_mutex_unlock(&mutex->sys_mutex); } void thread_library_lock(void) { _mutex_lock(&_library_mutex); } void thread_library_unlock(void) { _mutex_unlock(&_library_mutex); } void thread_join(thread_type *thread) { void *ret; int i; i = pthread_join(thread->sys_thread, &ret); _mutex_lock(&_threadtree_mutex); avl_delete(_threadtree, thread, _free_thread); _mutex_unlock(&_threadtree_mutex); } /* AVL tree functions */ #ifdef DEBUG_MUTEXES static int _compare_mutexes(void *compare_arg, void *a, void *b) { mutex_t *m1, *m2; m1 = (mutex_t *)a; m2 = (mutex_t *)b; if (m1->mutex_id > m2->mutex_id) return 1; if (m1->mutex_id < m2->mutex_id) return -1; return 0; } #endif static int _compare_threads(void *compare_arg, void *a, void *b) { thread_type *t1, *t2; t1 = (thread_type *)a; t2 = (thread_type *)b; if (t1->thread_id > t2->thread_id) return 1; if (t1->thread_id < t2->thread_id) return -1; return 0; } #ifdef DEBUG_MUTEXES static int _free_mutex(void *key) { mutex_t *m; m = (mutex_t *)key; if (m && m->file) { free(m->file); m->file = NULL; } /* all mutexes are static. don't need to free them */ return 1; } #endif static int _free_thread(void *key) { thread_type *t; t = (thread_type *)key; if (t->file) free(t->file); if (t->name) free(t->name); free(t); return 1; } #ifdef HAVE_PTHREAD_SPIN_LOCK void thread_spin_create (spin_t *spin) { int x = pthread_spin_init (&spin->lock, PTHREAD_PROCESS_PRIVATE); if (x) abort(); } void thread_spin_destroy (spin_t *spin) { pthread_spin_destroy (&spin->lock); } void thread_spin_lock (spin_t *spin) { int x = pthread_spin_lock (&spin->lock); if (x != 0) abort(); } void thread_spin_unlock (spin_t *spin) { pthread_spin_unlock (&spin->lock); } #endif icecast-2.4.2/src/thread/COPYING0000664000175000017500000006127312511160565013161 00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! icecast-2.4.2/src/auth.c0000664000175000017500000005232112511160565011756 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /** * Client authentication functions */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "auth.h" #include "auth_htpasswd.h" #include "auth_url.h" #include "source.h" #include "client.h" #include "cfgfile.h" #include "stats.h" #include "httpp/httpp.h" #include "fserve.h" #include "admin.h" #include "logging.h" #define CATMODULE "auth" static void auth_postprocess_source (auth_client *auth_user); static auth_client *auth_client_setup (const char *mount, client_t *client) { /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */ const char *header = httpp_getvar(client->parser, "authorization"); char *userpass, *tmp; char *username, *password; auth_client *auth_user; do { if (header == NULL) break; if (strncmp(header, "Basic ", 6) == 0) { userpass = util_base64_decode (header+6); if (userpass == NULL) { ICECAST_LOG_WARN("Base64 decode of Authorization header \"%s\" failed", header+6); break; } tmp = strchr(userpass, ':'); if (tmp == NULL) { free (userpass); break; } *tmp = 0; username = userpass; password = tmp+1; client->username = strdup (username); client->password = strdup (password); free (userpass); break; } ICECAST_LOG_INFO("unhandled authorization header: %s", header); } while (0); auth_user = calloc (1, sizeof(auth_client)); auth_user->mount = strdup (mount); auth_user->client = client; return auth_user; } static void queue_auth_client (auth_client *auth_user, mount_proxy *mountinfo) { auth_t *auth; if (auth_user == NULL) return; auth_user->next = NULL; if (mountinfo) { auth = mountinfo->auth; thread_mutex_lock (&auth->lock); if (auth_user->client) auth_user->client->auth = auth; auth->refcount++; } else { if (auth_user->client == NULL || auth_user->client->auth == NULL) { ICECAST_LOG_WARN("internal state is incorrect for %p", auth_user->client); return; } auth = auth_user->client->auth; thread_mutex_lock (&auth->lock); } ICECAST_LOG_DEBUG("...refcount on auth_t %s is now %d", auth->mount, auth->refcount); *auth->tailp = auth_user; auth->tailp = &auth_user->next; auth->pending_count++; ICECAST_LOG_INFO("auth on %s has %d pending", auth->mount, auth->pending_count); thread_mutex_unlock (&auth->lock); } /* release the auth. It is referred to by multiple structures so this is * refcounted and only actual freed after the last use */ void auth_release (auth_t *authenticator) { if (authenticator == NULL) return; thread_mutex_lock (&authenticator->lock); authenticator->refcount--; ICECAST_LOG_DEBUG("...refcount on auth_t %s is now %d", authenticator->mount, authenticator->refcount); if (authenticator->refcount) { thread_mutex_unlock (&authenticator->lock); return; } /* cleanup auth thread attached to this auth */ authenticator->running = 0; thread_join (authenticator->thread); if (authenticator->free) authenticator->free (authenticator); xmlFree (authenticator->type); thread_mutex_unlock (&authenticator->lock); thread_mutex_destroy (&authenticator->lock); if (authenticator->mount) free (authenticator->mount); free (authenticator); } static void auth_client_free (auth_client *auth_user) { if (auth_user == NULL) return; if (auth_user->client) { client_t *client = auth_user->client; if (client->respcode) client_destroy (client); else client_send_401 (client); auth_user->client = NULL; } free (auth_user->mount); free (auth_user); } /* verify that the listener is still connected. */ static int is_listener_connected (client_t *client) { int ret = 1; if (client) { if (sock_active (client->con->sock) == 0) ret = 0; } return ret; } /* wrapper function for auth thread to authenticate new listener * connection details */ static void auth_new_listener (auth_t *auth, auth_client *auth_user) { client_t *client = auth_user->client; /* make sure there is still a client at this point, a slow backend request * can be avoided if client has disconnected */ if (is_listener_connected (client) == 0) { ICECAST_LOG_DEBUG("listener is no longer connected"); client->respcode = 400; auth_release (client->auth); client->auth = NULL; return; } if (auth->authenticate) { if (auth->authenticate (auth_user) != AUTH_OK) { auth_release (client->auth); client->auth = NULL; return; } } if (auth_postprocess_listener (auth_user) < 0) { auth_release (client->auth); client->auth = NULL; ICECAST_LOG_INFO("client %lu failed", client->con->id); } } /* wrapper function for auth thread to drop listener connections */ static void auth_remove_listener (auth_t *auth, auth_client *auth_user) { client_t *client = auth_user->client; if (client->auth->release_listener) client->auth->release_listener (auth_user); auth_release (client->auth); client->auth = NULL; /* client is going, so auth is not an issue at this point */ client->authenticated = 0; } /* Called from auth thread to process any request for source client * authentication. Only applies to source clients, not relays. */ static void stream_auth_callback (auth_t *auth, auth_client *auth_user) { client_t *client = auth_user->client; if (auth->stream_auth) auth->stream_auth (auth_user); auth_release (auth); client->auth = NULL; if (client->authenticated) auth_postprocess_source (auth_user); else ICECAST_LOG_WARN("Failed auth for source \"%s\"", auth_user->mount); } /* Callback from auth thread to handle a stream start event, this applies * to both source clients and relays. */ static void stream_start_callback (auth_t *auth, auth_client *auth_user) { if (auth->stream_start) auth->stream_start (auth_user); auth_release (auth); } /* Callback from auth thread to handle a stream start event, this applies * to both source clients and relays. */ static void stream_end_callback (auth_t *auth, auth_client *auth_user) { if (auth->stream_end) auth->stream_end (auth_user); auth_release (auth); } /* The auth thread main loop. */ static void *auth_run_thread (void *arg) { auth_t *auth = arg; ICECAST_LOG_INFO("Authentication thread started"); while (auth->running) { /* usually no clients are waiting, so don't bother taking locks */ if (auth->head) { auth_client *auth_user; /* may become NULL before lock taken */ thread_mutex_lock (&auth->lock); auth_user = (auth_client*)auth->head; if (auth_user == NULL) { thread_mutex_unlock (&auth->lock); continue; } ICECAST_LOG_DEBUG("%d client(s) pending on %s", auth->pending_count, auth->mount); auth->head = auth_user->next; if (auth->head == NULL) auth->tailp = &auth->head; auth->pending_count--; thread_mutex_unlock (&auth->lock); auth_user->next = NULL; if (auth_user->process) auth_user->process (auth, auth_user); else ICECAST_LOG_ERROR("client auth process not set"); auth_client_free (auth_user); continue; } thread_sleep (150000); } ICECAST_LOG_INFO("Authenication thread shutting down"); return NULL; } /* Check whether this client is currently on this mount, the client may be * on either the active or pending lists. * return 1 if ok to add or 0 to prevent */ static int check_duplicate_logins (source_t *source, client_t *client, auth_t *auth) { /* allow multiple authenticated relays */ if (client->username == NULL) return 1; if (auth && auth->allow_duplicate_users == 0) { avl_node *node; avl_tree_rlock (source->client_tree); node = avl_get_first (source->client_tree); while (node) { client_t *existing_client = (client_t *)node->key; if (existing_client->username && strcmp (existing_client->username, client->username) == 0) { avl_tree_unlock (source->client_tree); return 0; } node = avl_get_next (node); } avl_tree_unlock (source->client_tree); avl_tree_rlock (source->pending_tree); node = avl_get_first (source->pending_tree); while (node) { client_t *existing_client = (client_t *)node->key; if (existing_client->username && strcmp (existing_client->username, client->username) == 0) { avl_tree_unlock (source->pending_tree); return 0; } node = avl_get_next (node); } avl_tree_unlock (source->pending_tree); } return 1; } /* if 0 is returned then the client should not be touched, however if -1 * is returned then the caller is responsible for handling the client */ static int add_listener_to_source (source_t *source, client_t *client) { int loop = 10; do { ICECAST_LOG_DEBUG("max on %s is %ld (cur %lu)", source->mount, source->max_listeners, source->listeners); if (source->max_listeners == -1) break; if (source->listeners < (unsigned long)source->max_listeners) break; if (loop && source->fallback_when_full && source->fallback_mount) { source_t *next = source_find_mount (source->fallback_mount); if (!next) { ICECAST_LOG_ERROR("Fallback '%s' for full source '%s' not found", source->mount, source->fallback_mount); return -1; } ICECAST_LOG_INFO("stream full trying %s", next->mount); source = next; loop--; continue; } /* now we fail the client */ return -1; } while (1); client->write_to_client = format_generic_write_to_client; client->check_buffer = format_check_http_buffer; client->refbuf->len = PER_CLIENT_REFBUF_SIZE; memset (client->refbuf->data, 0, PER_CLIENT_REFBUF_SIZE); /* lets add the client to the active list */ avl_tree_wlock (source->pending_tree); avl_insert (source->pending_tree, client); avl_tree_unlock (source->pending_tree); if (source->running == 0 && source->on_demand) { /* enable on-demand relay to start, wake up the slave thread */ ICECAST_LOG_DEBUG("kicking off on-demand relay"); source->on_demand_req = 1; } ICECAST_LOG_DEBUG("Added client to %s", source->mount); return 0; } /* Add listener to the pending lists of either the source or fserve thread. * This can be run from the connection or auth thread context */ static int add_authenticated_listener (const char *mount, mount_proxy *mountinfo, client_t *client) { int ret = 0; source_t *source = NULL; client->authenticated = 1; /* Here we are parsing the URI request to see if the extension is .xsl, if * so, then process this request as an XSLT request */ if (util_check_valid_extension (mount) == XSLT_CONTENT) { /* If the file exists, then transform it, otherwise, write a 404 */ ICECAST_LOG_DEBUG("Stats request, sending XSL transformed stats"); stats_transform_xslt (client, mount); return 0; } avl_tree_rlock (global.source_tree); source = source_find_mount (mount); if (source) { if (mountinfo) { if (check_duplicate_logins (source, client, mountinfo->auth) == 0) { avl_tree_unlock (global.source_tree); return -1; } /* set a per-mount disconnect time if auth hasn't set one already */ if (mountinfo->max_listener_duration && client->con->discon_time == 0) client->con->discon_time = time(NULL) + mountinfo->max_listener_duration; } ret = add_listener_to_source (source, client); avl_tree_unlock (global.source_tree); if (ret == 0) ICECAST_LOG_DEBUG("client authenticated, passed to source"); } else { avl_tree_unlock (global.source_tree); fserve_client_create (client, mount); } return ret; } int auth_postprocess_listener (auth_client *auth_user) { int ret; client_t *client = auth_user->client; ice_config_t *config = config_get_config(); mount_proxy *mountinfo = config_find_mount (config, auth_user->mount, MOUNT_TYPE_NORMAL); ret = add_authenticated_listener (auth_user->mount, mountinfo, client); config_release_config(); if (ret < 0) client_send_401 (auth_user->client); auth_user->client = NULL; return ret; } /* Decide whether we need to start a source or just process a source * admin request. */ void auth_postprocess_source (auth_client *auth_user) { client_t *client = auth_user->client; const char *mount = auth_user->mount; const char *req = httpp_getvar (client->parser, HTTPP_VAR_URI); auth_user->client = NULL; client->authenticated = 1; if (strcmp (req, "/admin.cgi") == 0 || strncmp ("/admin/metadata", req, 15) == 0) { ICECAST_LOG_DEBUG("metadata request (%s, %s)", req, mount); admin_handle_request (client, "/admin/metadata"); } else { ICECAST_LOG_DEBUG("on mountpoint %s", mount); source_startup (client, mount, 0); } } /* Add a listener. Check for any mount information that states any * authentication to be used. */ void auth_add_listener (const char *mount, client_t *client) { mount_proxy *mountinfo; ice_config_t *config = config_get_config(); mountinfo = config_find_mount (config, mount, MOUNT_TYPE_NORMAL); if (mountinfo && mountinfo->no_mount) { config_release_config (); client_send_403 (client, "mountpoint unavailable"); return; } if (mountinfo && mountinfo->auth) { auth_client *auth_user; if (mountinfo->auth->pending_count > 100) { config_release_config (); ICECAST_LOG_WARN("too many clients awaiting authentication"); client_send_403 (client, "busy, please try again later"); return; } auth_user = auth_client_setup (mount, client); auth_user->process = auth_new_listener; ICECAST_LOG_INFO("adding client for authentication"); queue_auth_client (auth_user, mountinfo); config_release_config (); } else { int ret = add_authenticated_listener (mount, mountinfo, client); config_release_config (); if (ret < 0) client_send_403 (client, "max listeners reached"); } } /* determine whether we need to process this client further. This * involves any auth exit, typically for external auth servers. */ int auth_release_listener (client_t *client) { if (client->authenticated) { const char *mount = httpp_getvar (client->parser, HTTPP_VAR_URI); /* drop any queue reference here, we do not want a race between the source thread * and the auth/fserve thread */ client_set_queue (client, NULL); if (mount && client->auth && client->auth->release_listener) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = auth_remove_listener; queue_auth_client (auth_user, NULL); return 1; } client->authenticated = 0; } return 0; } static int get_authenticator (auth_t *auth, config_options_t *options) { if (auth->type == NULL) { ICECAST_LOG_WARN("no authentication type defined"); return -1; } do { ICECAST_LOG_DEBUG("type is %s", auth->type); if (strcmp (auth->type, "url") == 0) { #ifdef HAVE_AUTH_URL if (auth_get_url_auth (auth, options) < 0) return -1; break; #else ICECAST_LOG_ERROR("Auth URL disabled"); return -1; #endif } if (strcmp (auth->type, "htpasswd") == 0) { if (auth_get_htpasswd_auth (auth, options) < 0) return -1; break; } ICECAST_LOG_ERROR("Unrecognised authenticator type: \"%s\"", auth->type); return -1; } while (0); while (options) { if (strcmp (options->name, "allow_duplicate_users") == 0) auth->allow_duplicate_users = atoi ((char*)options->value); options = options->next; } return 0; } auth_t *auth_get_authenticator (xmlNodePtr node) { auth_t *auth = calloc (1, sizeof (auth_t)); config_options_t *options = NULL, **next_option = &options; xmlNodePtr option; if (auth == NULL) return NULL; option = node->xmlChildrenNode; while (option) { xmlNodePtr current = option; option = option->next; if (xmlStrcmp (current->name, XMLSTR("option")) == 0) { config_options_t *opt = calloc (1, sizeof (config_options_t)); opt->name = (char *)xmlGetProp (current, XMLSTR("name")); if (opt->name == NULL) { free(opt); continue; } opt->value = (char *)xmlGetProp (current, XMLSTR("value")); if (opt->value == NULL) { xmlFree (opt->name); free (opt); continue; } *next_option = opt; next_option = &opt->next; } else if (xmlStrcmp (current->name, XMLSTR("text")) != 0) ICECAST_LOG_WARN("unknown auth setting (%s)", current->name); } auth->type = (char*)xmlGetProp (node, XMLSTR("type")); if (get_authenticator (auth, options) < 0) { xmlFree (auth->type); free (auth); auth = NULL; } else { auth->tailp = &auth->head; thread_mutex_create (&auth->lock); auth->refcount = 1; auth->running = 1; auth->thread = thread_create ("auth thread", auth_run_thread, auth, THREAD_ATTACHED); } while (options) { config_options_t *opt = options; options = opt->next; xmlFree (opt->name); xmlFree (opt->value); free (opt); } return auth; } /* Called when a source client connects and requires authentication via the * authenticator. This is called for both source clients and admin requests * that work on a specified mountpoint. */ int auth_stream_authenticate (client_t *client, const char *mount, mount_proxy *mountinfo) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_auth) { auth_client *auth_user = auth_client_setup (mount, client); auth_user->process = stream_auth_callback; ICECAST_LOG_INFO("request source auth for \"%s\"", mount); queue_auth_client (auth_user, mountinfo); return 1; } return 0; } /* called when the stream starts, so that authentication engine can do any * cleanup/initialisation. */ void auth_stream_start (mount_proxy *mountinfo, const char *mount) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_start) { auth_client *auth_user = calloc (1, sizeof (auth_client)); if (auth_user) { auth_user->mount = strdup (mount); auth_user->process = stream_start_callback; queue_auth_client (auth_user, mountinfo); } } } /* Called when the stream ends so that the authentication engine can do * any authentication cleanup */ void auth_stream_end (mount_proxy *mountinfo, const char *mount) { if (mountinfo && mountinfo->auth && mountinfo->auth->stream_end) { auth_client *auth_user = calloc (1, sizeof (auth_client)); if (auth_user) { auth_user->mount = strdup (mount); auth_user->process = stream_end_callback; queue_auth_client (auth_user, mountinfo); } } } /* these are called at server start and termination */ void auth_initialise (void) { } void auth_shutdown (void) { ICECAST_LOG_INFO("Auth shutdown"); } icecast-2.4.2/src/format_flac.c0000664000175000017500000000621712511160565013275 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for FLAC logical streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct source_tag source_t; #include "refbuf.h" #include "format_ogg.h" #include "client.h" #include "stats.h" #define CATMODULE "format-flac" #include "logging.h" static void flac_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ICECAST_LOG_DEBUG("freeing FLAC codec"); stats_event (ogg_info->mount, "FLAC_version", NULL); ogg_stream_clear (&codec->os); free (codec); } /* Here, we just verify the page is ok and then add it to the queue */ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { refbuf_t * refbuf; if (codec->headers) { ogg_packet packet; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } while (ogg_stream_packetout (&codec->os, &packet)) { int type = packet.packet[0]; if (type == 0xFF) { codec->headers = 0; break; } if (type >= 1 && type <= 0x7E) continue; if (type >= 0x81 && type <= 0xFE) continue; ogg_info->error = 1; return NULL; } if (codec->headers) { format_ogg_attach_header (ogg_info, page); return NULL; } } refbuf = make_refbuf_with_page (page); return refbuf; } /* Check for flac header in logical stream */ ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for FLAC codec"); do { unsigned char *parse = packet.packet; if (page->header_len + page->body_len != 79) break; if (*parse != 0x7F) break; parse++; if (memcmp (parse, "FLAC", 4) != 0) break; ICECAST_LOG_INFO("seen initial FLAC header"); parse += 4; stats_event_args (ogg_info->mount, "FLAC_version", "%d.%d", parse[0], parse[1]); codec->process_page = process_flac_page; codec->codec_free = flac_codec_free; codec->headers = 1; codec->name = "FLAC"; format_ogg_attach_header (ogg_info, page); return codec; } while (0); ogg_stream_clear (&codec->os); free (codec); return NULL; } icecast-2.4.2/src/source.h0000664000175000017500000000537112511160565012325 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __SOURCE_H__ #define __SOURCE_H__ #include "cfgfile.h" #include "yp.h" #include "util.h" #include "format.h" #include "thread/thread.h" #include typedef struct source_tag { mutex_t lock; client_t *client; connection_t *con; http_parser_t *parser; time_t client_stats_update; char *mount; /* If this source drops, try to move all clients to this fallback */ char *fallback_mount; /* set to zero to request the source to shutdown without causing a global * shutdown */ int running; struct _format_plugin_tag *format; avl_tree *client_tree; avl_tree *pending_tree; rwlock_t *shutdown_rwlock; util_dict *audio_info; FILE *intro_file; char *dumpfilename; /* Name of a file to dump incoming stream to */ FILE *dumpfile; unsigned long peak_listeners; unsigned long listeners; unsigned long prev_listeners; long max_listeners; int yp_public; int fallback_override; int fallback_when_full; int shoutcast_compat; /* per source burst handling for connecting clients */ unsigned int burst_size; /* trigger level for burst on connect */ unsigned int burst_offset; refbuf_t *burst_point; unsigned int queue_size; unsigned int queue_size_limit; unsigned timeout; /* source timeout in seconds */ int on_demand; int on_demand_req; int hidden; time_t last_read; int short_delay; refbuf_t *stream_data; refbuf_t *stream_data_tail; } source_t; source_t *source_reserve (const char *mount); void *source_client_thread (void *arg); void source_startup (client_t *client, const char *uri, int auth_style); void source_client_callback (client_t *client, void *source); void source_update_settings (ice_config_t *config, source_t *source, mount_proxy *mountinfo); void source_clear_source (source_t *source); source_t *source_find_mount(const char *mount); source_t *source_find_mount_raw(const char *mount); client_t *source_find_client(source_t *source, int id); int source_compare_sources(void *arg, void *a, void *b); void source_free_source(source_t *source); void source_move_clients (source_t *source, source_t *dest); int source_remove_client(void *key); void source_main(source_t *source); void source_recheck_mounts (int update_all); extern mutex_t move_clients_mutex; #endif icecast-2.4.2/src/global.h0000664000175000017500000000233312511160565012260 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __GLOBAL_H__ #define __GLOBAL_H__ #define ICECAST_LISTEN_QUEUE 5 #define ICECAST_RUNNING 1 #define ICECAST_HALTING 2 #define ICECAST_VERSION_STRING "Icecast " PACKAGE_VERSION #include "thread/thread.h" #include "slave.h" #include "net/sock.h" typedef struct ice_global_tag { sock_t *serversock; int server_sockets; int running; int sources; int clients; int schedule_config_reread; avl_tree *source_tree; /* for locally defined relays */ struct _relay_server *relays; /* relays retrieved from master */ struct _relay_server *master_relays; cond_t shutdown_cond; } ice_global_t; extern ice_global_t global; void global_initialize(void); void global_shutdown(void); void global_lock(void); void global_unlock(void); #endif /* __GLOBAL_H__ */ icecast-2.4.2/src/cfgfile.c0000664000175000017500000016640112511160565012421 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011, Dave 'justdave' Miller . * Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker , * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifndef _WIN32 #include #endif #include #include #include "thread/thread.h" #include "cfgfile.h" #include "refbuf.h" #include "client.h" #include "logging.h" #define CATMODULE "CONFIG" #define CONFIG_DEFAULT_LOCATION "Earth" #define CONFIG_DEFAULT_ADMIN "icemaster@localhost" #define CONFIG_DEFAULT_CLIENT_LIMIT 256 #define CONFIG_DEFAULT_SOURCE_LIMIT 16 #define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024) #define CONFIG_DEFAULT_BURST_SIZE (64*1024) #define CONFIG_DEFAULT_THREADPOOL_SIZE 4 #define CONFIG_DEFAULT_CLIENT_TIMEOUT 30 #define CONFIG_DEFAULT_HEADER_TIMEOUT 15 #define CONFIG_DEFAULT_SOURCE_TIMEOUT 10 #define CONFIG_DEFAULT_MASTER_USERNAME "relay" #define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream" #define CONFIG_DEFAULT_ICE_LOGIN 0 #define CONFIG_DEFAULT_FILESERVE 1 #define CONFIG_DEFAULT_TOUCH_FREQ 5 #define CONFIG_DEFAULT_HOSTNAME "localhost" #define CONFIG_DEFAULT_PLAYLIST_LOG NULL #define CONFIG_DEFAULT_ACCESS_LOG "access.log" #define CONFIG_DEFAULT_ERROR_LOG "error.log" #define CONFIG_DEFAULT_LOG_LEVEL 3 #define CONFIG_DEFAULT_CHROOT 0 #define CONFIG_DEFAULT_CHUID 0 #define CONFIG_DEFAULT_USER NULL #define CONFIG_DEFAULT_GROUP NULL #define CONFIG_MASTER_UPDATE_INTERVAL 120 #define CONFIG_YP_URL_TIMEOUT 10 #define CONFIG_DEFAULT_CIPHER_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA" #ifndef _WIN32 #define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast" #define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs" #define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot" #define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin" #define MIMETYPESFILE "/etc/mime.types" #else #define CONFIG_DEFAULT_BASE_DIR ".\\" #define CONFIG_DEFAULT_LOG_DIR ".\\logs" #define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot" #define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin" #define MIMETYPESFILE ".\\mime.types" #endif static ice_config_t _current_configuration; static ice_config_locks _locks; static void _set_defaults(ice_config_t *c); static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers); static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void merge_mounts(mount_proxy * dst, mount_proxy * src); static inline void _merge_mounts_all(ice_config_t *c); static void create_locks(void) { thread_mutex_create(&_locks.relay_lock); thread_rwlock_create(&_locks.config_lock); } static void release_locks(void) { thread_mutex_destroy(&_locks.relay_lock); thread_rwlock_destroy(&_locks.config_lock); } void config_initialize(void) { create_locks(); } void config_shutdown(void) { config_get_config(); config_clear(&_current_configuration); config_release_config(); release_locks(); } void config_init_configuration(ice_config_t *configuration) { memset(configuration, 0, sizeof(ice_config_t)); _set_defaults(configuration); } static void config_clear_http_header(ice_config_http_header_t *header) { ice_config_http_header_t *old; while (header) { xmlFree(header->name); xmlFree(header->value); old = header; header = header->next; free(old); } } static inline ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) { ice_config_http_header_t *ret = NULL; ice_config_http_header_t *cur = NULL; ice_config_http_header_t *old = NULL; while (header) { if (cur) { cur->next = calloc(1, sizeof(ice_config_http_header_t)); old = cur; cur = cur->next; } else { ret = calloc(1, sizeof(ice_config_http_header_t)); cur = ret; } if (!cur) return ret; /* TODO: do better error handling */ cur->type = header->type; cur->name = (char *)xmlCharStrdup(header->name); cur->value = (char *)xmlCharStrdup(header->value); cur->status = header->status; if (!cur->name || !cur->value) { if (cur->name) xmlFree(cur->name); if (cur->value) xmlFree(cur->value); if (old) { old->next = NULL; } else { ret = NULL; } free(cur); return ret; } header = header->next; } return ret; } static void config_clear_mount (mount_proxy *mount) { config_options_t *option; if (mount->mountname) xmlFree (mount->mountname); if (mount->username) xmlFree (mount->username); if (mount->password) xmlFree (mount->password); if (mount->dumpfile) xmlFree (mount->dumpfile); if (mount->intro_filename) xmlFree (mount->intro_filename); if (mount->on_connect) xmlFree (mount->on_connect); if (mount->on_disconnect) xmlFree (mount->on_disconnect); if (mount->fallback_mount) xmlFree (mount->fallback_mount); if (mount->stream_name) xmlFree (mount->stream_name); if (mount->stream_description) xmlFree (mount->stream_description); if (mount->stream_url) xmlFree (mount->stream_url); if (mount->stream_genre) xmlFree (mount->stream_genre); if (mount->bitrate) xmlFree (mount->bitrate); if (mount->type) xmlFree (mount->type); if (mount->charset) xmlFree (mount->charset); if (mount->cluster_password) xmlFree (mount->cluster_password); if (mount->auth_type) xmlFree (mount->auth_type); option = mount->auth_options; while (option) { config_options_t *nextopt = option->next; if (option->name) xmlFree (option->name); if (option->value) xmlFree (option->value); free (option); option = nextopt; } auth_release (mount->auth); config_clear_http_header(mount->http_headers); free (mount); } listener_t *config_clear_listener (listener_t *listener) { listener_t *next = NULL; if (listener) { next = listener->next; if (listener->bind_address) xmlFree (listener->bind_address); if (listener->shoutcast_mount) xmlFree (listener->shoutcast_mount); free (listener); } return next; } void config_clear(ice_config_t *c) { ice_config_dir_t *dirnode, *nextdirnode; relay_server *relay, *nextrelay; mount_proxy *mount, *nextmount; aliases *alias, *nextalias; #ifdef USE_YP int i; #endif free(c->config_filename); xmlFree (c->server_id); if (c->location) xmlFree(c->location); if (c->admin) xmlFree(c->admin); if (c->source_password) xmlFree(c->source_password); if (c->admin_username) xmlFree(c->admin_username); if (c->admin_password) xmlFree(c->admin_password); if (c->relay_username) xmlFree(c->relay_username); if (c->relay_password) xmlFree(c->relay_password); if (c->hostname) xmlFree(c->hostname); if (c->base_dir) xmlFree(c->base_dir); if (c->log_dir) xmlFree(c->log_dir); if (c->webroot_dir) xmlFree(c->webroot_dir); if (c->adminroot_dir) xmlFree(c->adminroot_dir); if (c->cert_file) xmlFree(c->cert_file); if (c->cipher_list) xmlFree(c->cipher_list); if (c->pidfile) xmlFree(c->pidfile); if (c->banfile) xmlFree(c->banfile); if (c->allowfile) xmlFree(c->allowfile); if (c->playlist_log) xmlFree(c->playlist_log); if (c->access_log) xmlFree(c->access_log); if (c->error_log) xmlFree(c->error_log); if (c->shoutcast_mount) xmlFree(c->shoutcast_mount); if (c->master_server) xmlFree(c->master_server); if (c->master_username) xmlFree(c->master_username); if (c->master_password) xmlFree(c->master_password); if (c->user) xmlFree(c->user); if (c->group) xmlFree(c->group); if (c->mimetypes_fn) xmlFree (c->mimetypes_fn); while ((c->listen_sock = config_clear_listener (c->listen_sock))) ; thread_mutex_lock(&(_locks.relay_lock)); relay = c->relay; while(relay) { nextrelay = relay->next; xmlFree(relay->server); xmlFree(relay->mount); xmlFree(relay->localmount); free(relay); relay = nextrelay; } thread_mutex_unlock(&(_locks.relay_lock)); mount = c->mounts; while(mount) { nextmount = mount->next; config_clear_mount (mount); mount = nextmount; } alias = c->aliases; while(alias) { nextalias = alias->next; xmlFree(alias->source); xmlFree(alias->destination); xmlFree(alias->bind_address); free(alias); alias = nextalias; } dirnode = c->dir_list; while(dirnode) { nextdirnode = dirnode->next; xmlFree(dirnode->host); free(dirnode); dirnode = nextdirnode; } #ifdef USE_YP i = 0; while (i < c->num_yp_directories) { xmlFree (c->yp_url[i]); i++; } #endif config_clear_http_header(c->http_headers); memset(c, 0, sizeof(ice_config_t)); } int config_initial_parse_file(const char *filename) { /* Since we're already pointing at it, we don't need to copy it in place */ return config_parse_file(filename, &_current_configuration); } int config_parse_file(const char *filename, ice_config_t *configuration) { xmlDocPtr doc; xmlNodePtr node; if (filename == NULL || strcmp(filename, "") == 0) return CONFIG_EINSANE; doc = xmlParseFile(filename); if (doc == NULL) { return CONFIG_EPARSE; } node = xmlDocGetRootElement(doc); if (node == NULL) { xmlFreeDoc(doc); return CONFIG_ENOROOT; } if (xmlStrcmp (node->name, XMLSTR("icecast")) != 0) { xmlFreeDoc(doc); return CONFIG_EBADROOT; } config_init_configuration(configuration); configuration->config_filename = strdup (filename); _parse_root(doc, node->xmlChildrenNode, configuration); xmlFreeDoc(doc); _merge_mounts_all(configuration); return 0; } int config_parse_cmdline(int arg, char **argv) { return 0; } ice_config_locks *config_locks(void) { return &_locks; } void config_release_config(void) { thread_rwlock_unlock(&(_locks.config_lock)); } ice_config_t *config_get_config(void) { thread_rwlock_rlock(&(_locks.config_lock)); return &_current_configuration; } ice_config_t *config_grab_config(void) { thread_rwlock_wlock(&(_locks.config_lock)); return &_current_configuration; } /* MUST be called with the lock held! */ void config_set_config(ice_config_t *config) { memcpy(&_current_configuration, config, sizeof(ice_config_t)); } ice_config_t *config_get_config_unlocked(void) { return &_current_configuration; } static void _set_defaults(ice_config_t *configuration) { configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION); configuration->server_id = (char *)xmlCharStrdup (ICECAST_VERSION_STRING); configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN); configuration->client_limit = CONFIG_DEFAULT_CLIENT_LIMIT; configuration->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT; configuration->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT; configuration->threadpool_size = CONFIG_DEFAULT_THREADPOOL_SIZE; configuration->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT; configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT; configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT; configuration->source_password = NULL; configuration->shoutcast_mount = (char *)xmlCharStrdup (CONFIG_DEFAULT_SHOUTCAST_MOUNT); configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN; configuration->fileserve = CONFIG_DEFAULT_FILESERVE; configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ; configuration->on_demand = 0; configuration->dir_list = NULL; configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME); configuration->mimetypes_fn = (char *)xmlCharStrdup (MIMETYPESFILE); configuration->master_server = NULL; configuration->master_server_port = 0; configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL; configuration->master_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME); configuration->master_password = NULL; configuration->base_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_BASE_DIR); configuration->log_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOG_DIR); configuration->cipher_list = (char *)xmlCharStrdup (CONFIG_DEFAULT_CIPHER_LIST); configuration->webroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_WEBROOT_DIR); configuration->adminroot_dir = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMINROOT_DIR); configuration->playlist_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_PLAYLIST_LOG); configuration->access_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ACCESS_LOG); configuration->error_log = (char *)xmlCharStrdup (CONFIG_DEFAULT_ERROR_LOG); configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL; configuration->chroot = CONFIG_DEFAULT_CHROOT; configuration->chuid = CONFIG_DEFAULT_CHUID; configuration->user = NULL; configuration->group = NULL; configuration->num_yp_directories = 0; configuration->relay_username = (char *)xmlCharStrdup (CONFIG_DEFAULT_MASTER_USERNAME); configuration->relay_password = NULL; /* default to a typical prebuffer size used by clients */ configuration->burst_size = CONFIG_DEFAULT_BURST_SIZE; } static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; configuration->listen_sock = calloc (1, sizeof (*configuration->listen_sock)); configuration->listen_sock->port = 8000; configuration->listen_sock_count = 1; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("location")) == 0) { if (configuration->location) xmlFree(configuration->location); configuration->location = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("admin")) == 0) { if (configuration->admin) xmlFree(configuration->admin); configuration->admin = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("server-id")) == 0) { xmlFree (configuration->server_id); configuration->server_id = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); ICECAST_LOG_WARN("Warning, server version string override detected. This may lead to unexpected client software behavior."); } else if(xmlStrcmp (node->name, XMLSTR("authentication")) == 0) { _parse_authentication(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) { /* TODO: This is the backwards-compatibility location */ ICECAST_LOG_WARN(" defined outside . This is deprecated."); if (configuration->source_password) xmlFree(configuration->source_password); configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("icelogin")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->ice_login = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("fileserve")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->fileserve = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("relays-on-demand")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->on_demand = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("hostname")) == 0) { if (configuration->hostname) xmlFree(configuration->hostname); configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("mime-types")) == 0) { if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn); configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("listen-socket")) == 0) { _parse_listen_socket(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (tmp) { configuration->port = atoi(tmp); configuration->listen_sock->port = atoi(tmp); xmlFree(tmp); } else { ICECAST_LOG_WARN(" must not be empty."); } } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) { if (configuration->listen_sock->bind_address) xmlFree(configuration->listen_sock->bind_address); configuration->listen_sock->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("master-server")) == 0) { if (configuration->master_server) xmlFree(configuration->master_server); configuration->master_server = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("master-username")) == 0) { if (configuration->master_username) xmlFree(configuration->master_username); configuration->master_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("master-password")) == 0) { if (configuration->master_password) xmlFree(configuration->master_password); configuration->master_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("master-server-port")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->master_server_port = atoi(tmp); xmlFree (tmp); } else if (xmlStrcmp (node->name, XMLSTR("master-update-interval")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->master_update_interval = atoi(tmp); xmlFree (tmp); } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) { if (configuration->shoutcast_mount) xmlFree(configuration->shoutcast_mount); configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) { _parse_limits(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) { _parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers)); } else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) { _parse_relay(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) { _parse_mount(doc, node, configuration); } else if (xmlStrcmp (node->name, XMLSTR("directory")) == 0) { _parse_directory(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("paths")) == 0) { _parse_paths(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("logging")) == 0) { _parse_logging(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("security")) == 0) { _parse_security(doc, node->xmlChildrenNode, configuration); } } while ((node = node->next)); /* drop the first listening socket details if more than one is defined, as we only * have port or listen-socket not both */ if (configuration->listen_sock_count > 1) { configuration->listen_sock = config_clear_listener (configuration->listen_sock); configuration->listen_sock_count--; } if (configuration->port == 0) configuration->port = 8000; /* issue some warnings on bad configurations */ if (!configuration->fileserve) ICECAST_LOG_WARN("Warning, serving of static files has been disabled in the config, this will also affect files used by the web interface (stylesheets, images)."); if (!configuration->hostname || strcmp(configuration->hostname, CONFIG_DEFAULT_HOSTNAME) == 0) { ICECAST_LOG_WARN("Warning, not configured, using default value \"%s\". This will cause problems, e.g. with YP directory listings.", CONFIG_DEFAULT_HOSTNAME); if (!configuration->hostname) configuration->hostname = (char *)xmlCharStrdup (CONFIG_DEFAULT_HOSTNAME); } if (!configuration->location || strcmp(configuration->location, CONFIG_DEFAULT_LOCATION) == 0) { ICECAST_LOG_WARN("Warning, not configured, using default value \"%s\".", CONFIG_DEFAULT_LOCATION); if (!configuration->location) configuration->location = (char *)xmlCharStrdup (CONFIG_DEFAULT_LOCATION); } if (!configuration->admin || strcmp(configuration->admin, CONFIG_DEFAULT_ADMIN) == 0) { ICECAST_LOG_WARN("Warning, contact not configured, using default value \"%s\".", CONFIG_DEFAULT_ADMIN); if (!configuration->admin) configuration->admin = (char *)xmlCharStrdup (CONFIG_DEFAULT_ADMIN); } } static void _parse_limits(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("clients")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->client_limit = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("sources")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->source_limit = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->queue_size_limit = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("threadpool")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->threadpool_size = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("client-timeout")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->client_timeout = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("header-timeout")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->header_timeout = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->source_timeout = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("burst-on-connect")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (atoi(tmp) == 0) configuration->burst_size = 0; if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->burst_size = atoi(tmp); if (tmp) xmlFree(tmp); } } while ((node = node->next)); } static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; mount_proxy *mount = calloc(1, sizeof(mount_proxy)); mount_proxy *current = configuration->mounts; mount_proxy *last=NULL; /* default settings */ mount->mounttype = MOUNT_TYPE_NORMAL; mount->max_listeners = -1; mount->burst_size = -1; mount->mp3_meta_interval = -1; mount->yp_public = -1; mount->next = NULL; tmp = (char *)xmlGetProp(node, XMLSTR("type")); if (tmp) { if (strcmp(tmp, "normal") == 0) { mount->mounttype = MOUNT_TYPE_NORMAL; } else if (strcmp(tmp, "default") == 0) { mount->mounttype = MOUNT_TYPE_DEFAULT; } else { ICECAST_LOG_WARN("Unknown mountpoint type: %s", tmp); config_clear_mount (mount); return; } xmlFree(tmp); } node = node->xmlChildrenNode; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("mount-name")) == 0) { mount->mountname = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) { mount->username = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) { mount->password = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("dump-file")) == 0) { mount->dumpfile = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("intro")) == 0) { mount->intro_filename = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("fallback-mount")) == 0) { mount->fallback_mount = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("fallback-when-full")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->fallback_when_full = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("max-listeners")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->max_listeners = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("charset")) == 0) { mount->charset = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("mp3-metadata-interval")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->mp3_meta_interval = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("fallback-override")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->fallback_override = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("no-mount")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->no_mount = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("no-yp")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->yp_public = atoi(tmp) == 0 ? -1 : 0; if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("hidden")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->hidden = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("authentication")) == 0) { mount->auth = auth_get_authenticator (node); } else if (xmlStrcmp (node->name, XMLSTR("on-connect")) == 0) { mount->on_connect = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("on-disconnect")) == 0) { mount->on_disconnect = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("max-listener-duration")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->max_listener_duration = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("queue-size")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->queue_size_limit = atoi (tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("source-timeout")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (tmp) { mount->source_timeout = atoi (tmp); xmlFree(tmp); } } else if (xmlStrcmp (node->name, XMLSTR("burst-size")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->burst_size = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("cluster-password")) == 0) { mount->cluster_password = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("stream-name")) == 0) { mount->stream_name = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("stream-description")) == 0) { mount->stream_description = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("stream-url")) == 0) { mount->stream_url = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("genre")) == 0) { mount->stream_genre = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("bitrate")) == 0) { mount->bitrate = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("public")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); mount->yp_public = atoi (tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("type")) == 0) { mount->type = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) { mount->subtype = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) { _parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers)); } } while ((node = node->next)); /* make sure we have at least the mountpoint name */ if (mount->mountname == NULL && mount->mounttype != MOUNT_TYPE_DEFAULT) { config_clear_mount (mount); return; } else if (mount->mountname != NULL && mount->mounttype == MOUNT_TYPE_DEFAULT) { ICECAST_LOG_WARN("Default mount %s has mount-name set. This is not supported. Behavior may not be consistent.", mount->mountname); } if (mount->auth && mount->mountname) { mount->auth->mount = strdup ((char *)mount->mountname); } else if (mount->auth && mount->mounttype == MOUNT_TYPE_DEFAULT ) { mount->auth->mount = strdup ("(default mount)"); } while(current) { last = current; current = current->next; } if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override)) { ICECAST_LOG_WARN("Config for mount %s contains fallback options but no fallback mount.", mount->mountname); } if(last) last->next = mount; else configuration->mounts = mount; } static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) { ice_config_http_header_t *header; ice_config_http_header_t *next; char *name = NULL; char *value = NULL; char *tmp; int status; http_header_type type; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("header")) != 0) break; if (!(name = (char *)xmlGetProp(node, XMLSTR("name")))) break; if (!(value = (char *)xmlGetProp(node, XMLSTR("value")))) break; type = HTTP_HEADER_TYPE_STATIC; /* default */ if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) { if (strcmp(tmp, "static") == 0) { type = HTTP_HEADER_TYPE_STATIC; } else { ICECAST_LOG_WARN("Unknown type %s for HTTP Header %s", tmp, name); xmlFree(tmp); break; } xmlFree(tmp); } status = 0; /* default: any */ if ((tmp = (char *)xmlGetProp(node, XMLSTR("status")))) { status = atoi(tmp); xmlFree(tmp); } header = calloc(1, sizeof(ice_config_http_header_t)); if (!header) break; header->type = type; header->name = name; header->value = value; header->status = status; name = NULL; value = NULL; if (!*http_headers) { *http_headers = header; continue; } next = *http_headers; while (next->next) next = next->next; next->next = header; } while ((node = node->next)); /* in case we used break we may need to clean those up */ if (name) xmlFree(name); if (value) xmlFree(value); } static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; relay_server *relay = calloc(1, sizeof(relay_server)); relay_server *current = configuration->relay; relay_server *last=NULL; while(current) { last = current; current = current->next; } if(last) last->next = relay; else configuration->relay = relay; relay->next = NULL; relay->mp3metadata = 1; relay->on_demand = configuration->on_demand; relay->server = (char *)xmlCharStrdup ("127.0.0.1"); relay->mount = (char *)xmlCharStrdup ("/"); do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("server")) == 0) { if (relay->server) xmlFree (relay->server); relay->server = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (tmp) { relay->port = atoi(tmp); xmlFree(tmp); } else { ICECAST_LOG_WARN(" must not be empty."); } } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) { if (relay->mount) xmlFree (relay->mount); relay->mount = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("local-mount")) == 0) { if (relay->localmount) xmlFree (relay->localmount); relay->localmount = (char *)xmlNodeListGetString( doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("relay-shoutcast-metadata")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); relay->mp3metadata = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("username")) == 0) { if (relay->username) xmlFree (relay->username); relay->username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("password")) == 0) { if (relay->password) xmlFree (relay->password); relay->password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("on-demand")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); relay->on_demand = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("bind")) == 0) { if (relay->bind) xmlFree (relay->bind); relay->bind = (char *)xmlNodeListGetString (doc, node->xmlChildrenNode, 1); } } while ((node = node->next)); if (relay->localmount == NULL) relay->localmount = (char *)xmlStrdup (XMLSTR(relay->mount)); } static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; listener_t *listener = calloc (1, sizeof(listener_t)); if (listener == NULL) return; listener->port = 8000; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("port")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (tmp) { if(configuration->port == 0) configuration->port = atoi(tmp); listener->port = atoi(tmp); xmlFree(tmp); } else { ICECAST_LOG_WARN(" must not be empty."); } } else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); listener->ssl = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-compat")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); listener->shoutcast_compat = atoi(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("shoutcast-mount")) == 0) { if (listener->shoutcast_mount) xmlFree (listener->shoutcast_mount); listener->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) { if (listener->bind_address) xmlFree (listener->bind_address); listener->bind_address = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("so-sndbuf")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); listener->so_sndbuf = atoi(tmp); if(tmp) xmlFree(tmp); } } while ((node = node->next)); /* we know there's at least one of these, so add this new one after the first * that way it can be removed easily later on */ listener->next = configuration->listen_sock->next; configuration->listen_sock->next = listener; configuration->listen_sock_count++; if (listener->shoutcast_mount) { listener_t *sc_port = calloc (1, sizeof (listener_t)); sc_port->port = listener->port+1; sc_port->shoutcast_compat = 1; sc_port->shoutcast_mount = (char*)xmlStrdup (XMLSTR(listener->shoutcast_mount)); if (listener->bind_address) sc_port->bind_address = (char*)xmlStrdup (XMLSTR(listener->bind_address)); sc_port->next = listener->next; listener->next = sc_port; configuration->listen_sock_count++; } } static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("source-password")) == 0) { if (xmlGetProp(node, XMLSTR("mount"))) { ICECAST_LOG_ERROR("Mount level source password defined within global section."); } else { if (configuration->source_password) xmlFree(configuration->source_password); configuration->source_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } else if (xmlStrcmp (node->name, XMLSTR("admin-password")) == 0) { if(configuration->admin_password) xmlFree(configuration->admin_password); configuration->admin_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("admin-user")) == 0) { if(configuration->admin_username) xmlFree(configuration->admin_username); configuration->admin_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("relay-password")) == 0) { if(configuration->relay_password) xmlFree(configuration->relay_password); configuration->relay_password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("relay-user")) == 0) { if(configuration->relay_username) xmlFree(configuration->relay_username); configuration->relay_username = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } while ((node = node->next)); } static void _parse_directory(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; if (configuration->num_yp_directories >= MAX_YP_DIRECTORIES) { ICECAST_LOG_ERROR("Maximum number of yp directories exceeded!"); return; } do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("yp-url")) == 0) { if (configuration->yp_url[configuration->num_yp_directories]) xmlFree(configuration->yp_url[configuration->num_yp_directories]); configuration->yp_url[configuration->num_yp_directories] = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("yp-url-timeout")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->yp_url_timeout[configuration->num_yp_directories] = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("server")) == 0) { _add_server(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->yp_touch_interval[configuration->num_yp_directories] = atoi(tmp); if (tmp) xmlFree(tmp); } } while ((node = node->next)); if (configuration->yp_url [configuration->num_yp_directories] == NULL) return; configuration->num_yp_directories++; } static void _parse_paths(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *temp; aliases *alias, *current, *last; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("basedir")) == 0) { if (configuration->base_dir) xmlFree(configuration->base_dir); configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("logdir")) == 0) { if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) { ICECAST_LOG_WARN(" must not be empty."); continue; } if (configuration->log_dir) xmlFree(configuration->log_dir); configuration->log_dir = temp; } else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) { if (configuration->pidfile) xmlFree(configuration->pidfile); configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("deny-ip")) == 0) { if (configuration->banfile) xmlFree(configuration->banfile); configuration->banfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("allow-ip")) == 0) { if (configuration->allowfile) xmlFree(configuration->allowfile); configuration->allowfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) { if (configuration->cert_file) xmlFree(configuration->cert_file); configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("ssl-allowed-ciphers")) == 0) { if (configuration->cipher_list) xmlFree(configuration->cipher_list); configuration->cipher_list = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("webroot")) == 0) { if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) { ICECAST_LOG_WARN(" must not be empty."); continue; } if (configuration->webroot_dir) xmlFree(configuration->webroot_dir); configuration->webroot_dir = temp; if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/') configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0; } else if (xmlStrcmp (node->name, XMLSTR("adminroot")) == 0) { if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) { ICECAST_LOG_WARN(" must not be empty."); continue; } if (configuration->adminroot_dir) xmlFree(configuration->adminroot_dir); configuration->adminroot_dir = (char *)temp; if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/') configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0; } else if (xmlStrcmp (node->name, XMLSTR("alias")) == 0) { alias = malloc(sizeof(aliases)); alias->next = NULL; alias->source = (char *)xmlGetProp(node, XMLSTR("source")); if(alias->source == NULL) { free(alias); continue; } alias->destination = (char *)xmlGetProp(node, XMLSTR("destination")); if (!alias->destination) alias->destination = (char *)xmlGetProp(node, XMLSTR("dest")); if(alias->destination == NULL) { xmlFree(alias->source); free(alias); continue; } temp = NULL; temp = (char *)xmlGetProp(node, XMLSTR("port")); if(temp != NULL) { alias->port = atoi(temp); xmlFree(temp); } else alias->port = -1; alias->bind_address = (char *)xmlGetProp(node, XMLSTR("bind-address")); current = configuration->aliases; last = NULL; while(current) { last = current; current = current->next; } if(last) last->next = alias; else configuration->aliases = alias; } } while ((node = node->next)); } static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("accesslog")) == 0) { if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) { ICECAST_LOG_WARN(" must not be empty."); continue; } if (configuration->access_log) xmlFree(configuration->access_log); configuration->access_log = tmp; } else if (xmlStrcmp (node->name, XMLSTR("errorlog")) == 0) { if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) { ICECAST_LOG_WARN(" must not be empty."); continue; } if (configuration->error_log) xmlFree(configuration->error_log); configuration->error_log = tmp; } else if (xmlStrcmp (node->name, XMLSTR("playlistlog")) == 0) { if (configuration->playlist_log) xmlFree(configuration->playlist_log); configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp (node->name, XMLSTR("logsize")) == 0) { char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->logsize = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("loglevel")) == 0) { char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->loglevel = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("logarchive")) == 0) { char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->logarchive = atoi(tmp); if (tmp) xmlFree(tmp); } } while ((node = node->next)); } static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { char *tmp; xmlNodePtr oldnode; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("chroot")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); configuration->chroot = atoi(tmp); if (tmp) xmlFree(tmp); } else if (xmlStrcmp (node->name, XMLSTR("changeowner")) == 0) { configuration->chuid = 1; oldnode = node; node = node->xmlChildrenNode; do { if(node == NULL) break; if(xmlIsBlankNode(node)) continue; if(xmlStrcmp (node->name, XMLSTR("user")) == 0) { if(configuration->user) xmlFree(configuration->user); configuration->user = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if(xmlStrcmp (node->name, XMLSTR("group")) == 0) { if(configuration->group) xmlFree(configuration->group); configuration->group = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } while((node = node->next)); node = oldnode; } } while ((node = node->next)); } static void _add_server(xmlDocPtr doc, xmlNodePtr node, ice_config_t *configuration) { ice_config_dir_t *dirnode, *server; int addnode; char *tmp; server = (ice_config_dir_t *)malloc(sizeof(ice_config_dir_t)); server->touch_interval = configuration->touch_interval; server->host = NULL; addnode = 0; do { if (node == NULL) break; if (xmlIsBlankNode(node)) continue; if (xmlStrcmp (node->name, XMLSTR("host")) == 0) { server->host = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); addnode = 1; } else if (xmlStrcmp (node->name, XMLSTR("touch-interval")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); server->touch_interval = atoi(tmp); if (tmp) xmlFree(tmp); } server->next = NULL; } while ((node = node->next)); if (addnode) { dirnode = configuration->dir_list; if (dirnode == NULL) { configuration->dir_list = server; } else { while (dirnode->next) dirnode = dirnode->next; dirnode->next = server; } server = NULL; addnode = 0; } else { free (server); } } static void merge_mounts(mount_proxy * dst, mount_proxy * src) { ice_config_http_header_t *http_header_next; ice_config_http_header_t **http_header_tail; if (!dst || !src) return; if (!dst->username) dst->username = (char*)xmlStrdup((xmlChar*)src->username); if (!dst->password) dst->password = (char*)xmlStrdup((xmlChar*)src->password); if (!dst->dumpfile) dst->dumpfile = (char*)xmlStrdup((xmlChar*)src->dumpfile); if (!dst->intro_filename) dst->intro_filename = (char*)xmlStrdup((xmlChar*)src->intro_filename); if (!dst->fallback_when_full) dst->fallback_when_full = src->fallback_when_full; if (dst->max_listeners == -1) dst->max_listeners = src->max_listeners; if (!dst->fallback_mount) dst->fallback_mount = (char*)xmlStrdup((xmlChar*)src->fallback_mount); if (!dst->fallback_override) dst->fallback_override = src->fallback_override; if (!dst->no_mount) dst->no_mount = src->no_mount; if (dst->burst_size == -1) dst->burst_size = src->burst_size; if (!dst->queue_size_limit) dst->queue_size_limit = src->queue_size_limit; if (!dst->hidden) dst->hidden = src->hidden; if (!dst->source_timeout) dst->source_timeout = src->source_timeout; if (!dst->charset) dst->charset = (char*)xmlStrdup((xmlChar*)src->charset); if (dst->mp3_meta_interval == -1) dst->mp3_meta_interval = src->mp3_meta_interval; if (!dst->auth_type) dst->auth_type = (char*)xmlStrdup((xmlChar*)src->auth_type); // TODO: dst->auth if (!dst->cluster_password) dst->cluster_password = (char*)xmlStrdup((xmlChar*)src->cluster_password); // TODO: dst->auth_options if (!dst->on_connect) dst->on_connect = (char*)xmlStrdup((xmlChar*)src->on_connect); if (!dst->on_disconnect) dst->on_disconnect = (char*)xmlStrdup((xmlChar*)src->on_disconnect); if (!dst->max_listener_duration) dst->max_listener_duration = src->max_listener_duration; if (!dst->stream_name) dst->stream_name = (char*)xmlStrdup((xmlChar*)src->stream_name); if (!dst->stream_description) dst->stream_description = (char*)xmlStrdup((xmlChar*)src->stream_description); if (!dst->stream_url) dst->stream_url = (char*)xmlStrdup((xmlChar*)src->stream_url); if (!dst->stream_genre) dst->stream_genre = (char*)xmlStrdup((xmlChar*)src->stream_genre); if (!dst->bitrate) dst->bitrate = (char*)xmlStrdup((xmlChar*)src->bitrate); if (!dst->type) dst->type = (char*)xmlStrdup((xmlChar*)src->type); if (!dst->subtype) dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype); if (dst->yp_public == -1) dst->yp_public = src->yp_public; if (dst->http_headers) { http_header_next = dst->http_headers; while (http_header_next->next) http_header_next = http_header_next->next; http_header_tail = &(http_header_next->next); } else { http_header_tail = &(dst->http_headers); } *http_header_tail = config_copy_http_header(src->http_headers); } static inline void _merge_mounts_all(ice_config_t *c) { mount_proxy *mountinfo = c->mounts; mount_proxy *default_mount; for (; mountinfo; mountinfo = mountinfo->next) { if (mountinfo->mounttype != MOUNT_TYPE_NORMAL) continue; default_mount = config_find_mount(c, mountinfo->mountname, MOUNT_TYPE_DEFAULT); merge_mounts(mountinfo, default_mount); } } /* return the mount details that match the supplied mountpoint */ mount_proxy *config_find_mount (ice_config_t *config, const char *mount, mount_type type) { mount_proxy *mountinfo = config->mounts; for (; mountinfo; mountinfo = mountinfo->next) { if (mountinfo->mounttype != type) continue; if (mount == NULL || mountinfo->mountname == NULL) break; if (mountinfo->mounttype == MOUNT_TYPE_NORMAL && strcmp (mountinfo->mountname, mount) == 0) break; #ifndef _WIN32 if (fnmatch(mountinfo->mountname, mount, FNM_PATHNAME) == 0) break; #else if (strcmp(mountinfo->mountname, mount) == 0) break; #endif } /* retry with default mount */ if (!mountinfo && type == MOUNT_TYPE_NORMAL) mountinfo = config_find_mount(config, mount, MOUNT_TYPE_DEFAULT); return mountinfo; } /* Helper function to locate the configuration details of the listening * socket */ listener_t *config_get_listen_sock (ice_config_t *config, connection_t *con) { listener_t *listener; int i = 0; listener = config->listen_sock; while (listener) { if (i >= global.server_sockets) listener = NULL; else { if (global.serversock[i] == con->serversock) break; listener = listener->next; i++; } } return listener; } icecast-2.4.2/src/stats.h0000664000175000017500000000517512511160565012165 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __STATS_H__ #define __STATS_H__ #include "cfgfile.h" #include "connection.h" #include "httpp/httpp.h" #include "client.h" #include #include #include typedef struct _stats_node_tag { char *name; char *value; int hidden; } stats_node_t; typedef struct _stats_event_tag { char *source; char *name; char *value; int hidden; int action; struct _stats_event_tag *next; } stats_event_t; typedef struct _stats_source_tag { char *source; int hidden; avl_tree *stats_tree; } stats_source_t; typedef struct _stats_tag { avl_tree *global_tree; /* global stats start_time total_users max_users total_sources max_sources total_user_connections total_source_connections */ avl_tree *source_tree; /* stats by source, and for stats start_time total_users max_users */ } stats_t; void stats_initialize(void); void stats_shutdown(void); void stats_global(ice_config_t *config); stats_t *stats_get_stats(void); refbuf_t *stats_get_streams (void); void stats_clear_virtual_mounts (void); void stats_event(const char *source, const char *name, const char *value); void stats_event_conv(const char *mount, const char *name, const char *value, const char *charset); void stats_event_args(const char *source, char *name, char *format, ...); void stats_event_inc(const char *source, const char *name); void stats_event_add(const char *source, const char *name, unsigned long value); void stats_event_sub(const char *source, const char *name, unsigned long value); void stats_event_dec(const char *source, const char *name); void stats_event_hidden (const char *source, const char *name, int hidden); void stats_event_time (const char *mount, const char *name); void stats_event_time_iso8601 (const char *mount, const char *name); void *stats_connection(void *arg); void stats_callback (client_t *client, void *notused); void stats_transform_xslt(client_t *client, const char *uri); void stats_sendxml(client_t *client); xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount); char *stats_get_value(const char *source, const char *name); #endif /* __STATS_H__ */ icecast-2.4.2/src/format_midi.c0000664000175000017500000000443412511160565013311 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* Ogg codec handler for MIDI logical streams */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct source_tag source_t; #include "refbuf.h" #include "format_ogg.h" #include "client.h" #include "stats.h" #define CATMODULE "format-midi" #include "logging.h" static void midi_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ICECAST_LOG_DEBUG("freeing MIDI codec"); ogg_stream_clear (&codec->os); free (codec); } /* Here, we just verify the page is ok and then add it to the queue */ static refbuf_t *process_midi_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { refbuf_t * refbuf; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } refbuf = make_refbuf_with_page (page); return refbuf; } /* Check for midi header in logical stream */ ogg_codec_t *initial_midi_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); ogg_packet packet; ogg_stream_init (&codec->os, ogg_page_serialno (page)); ogg_stream_pagein (&codec->os, page); ogg_stream_packetout (&codec->os, &packet); ICECAST_LOG_DEBUG("checking for MIDI codec"); do { if (packet.bytes < 9) break; if (memcmp (packet.packet, "OggMIDI\000", 8) != 0) break; if (packet.bytes != 12) break; ICECAST_LOG_INFO("seen initial MIDI header"); codec->process_page = process_midi_page; codec->codec_free = midi_codec_free; codec->headers = 1; codec->name = "MIDI"; format_ogg_attach_header (ogg_info, page); return codec; } while (0); ogg_stream_clear (&codec->os); free (codec); return NULL; } icecast-2.4.2/src/md5.c0000664000175000017500000002103412511160565011477 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* * md5.c * * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ /* Modified for icecast by Mike Smith , mostly changing header * and type definitions */ #ifdef HAVE_CONFIG_H #include #endif #include "compat.h" #include "md5.h" #include #include #include static void MD5Transform(uint32_t buf[4], uint32_t const in[HASH_LEN]); /* * Note: this code is harmless on little-endian machines. */ static void byteReverse(unsigned char *buf, unsigned longs) { uint32_t t; do { t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32_t *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) { uint32_t t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, HASH_LEN); MD5Transform(ctx->buf, (uint32_t *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, HASH_LEN); MD5Transform(ctx->buf, (uint32_t *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[HASH_LEN], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, HASH_LEN); MD5Transform(ctx->buf, (uint32_t *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32_t *) ctx->in)[14] = ctx->bits[0]; ((uint32_t *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32_t *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, HASH_LEN); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ # define F1(x, y, z) (z ^ (x & (y ^ z))) # define F2(x, y, z) F1(z, x, y) # define F3(x, y, z) (x ^ y ^ z) # define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ # define MD5STEP(f, w, x, y, z, data, s) do { w += f(x, y, z) + data; w = (w<>(32-s)); w += x; }while(0) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(uint32_t buf[4], uint32_t const in[HASH_LEN]) { register uint32_t a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } icecast-2.4.2/src/compat.h0000664000175000017500000000262012510726173012304 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ #ifndef __COMPAT_H__ #define __COMPAT_H__ /* compat.h * * This file contains most of the ugliness for header portability * and common types across various systems like Win32, Linux and * Solaris. */ #ifdef HAVE_UNISTD_H #include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* Make sure we define 64 bit types */ #ifdef _WIN32 # define PATH_SEPARATOR "\\" # define size_t unsigned int # define ssize_t int # define int64_t __int64 # define uint64_t unsigned __int64 # define uint32_t unsigned int # define PRIu64 "I64u" # define PRId64 "I64d" #else # define PATH_SEPARATOR "/" # if defined(HAVE_INTTYPES_H) # include # elif defined(HAVE_STDINT_H) # include # endif #endif /* some defaults if not provided above */ #ifndef SCNdMAX # define SCNdMAX "lld" #endif #endif /* __COMPAT_H__ */ icecast-2.4.2/src/format_ogg.h0000664000175000017500000000345012511160565013145 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). */ /* format_ogg.h ** ** vorbis format plugin header ** */ #ifndef __FORMAT_OGG_H__ #define __FORMAT_OGG_H__ #include #include "refbuf.h" #include "format.h" typedef struct ogg_state_tag { char *mount; ogg_sync_state oy; int error; int codec_count; struct ogg_codec_tag *codecs; char *artist; char *title; int log_metadata; refbuf_t *file_headers; refbuf_t *header_pages; refbuf_t *header_pages_tail; refbuf_t **bos_end; int bos_completed; long bitrate; struct ogg_codec_tag *current; struct ogg_codec_tag *codec_sync; } ogg_state_t; /* per codec/logical structure */ typedef struct ogg_codec_tag { struct ogg_codec_tag *next; ogg_stream_state os; unsigned headers; const char *name; void *specific; refbuf_t *possible_start; refbuf_t *page; refbuf_t *(*process)(ogg_state_t *ogg_info, struct ogg_codec_tag *codec); refbuf_t *(*process_page)(ogg_state_t *ogg_info, struct ogg_codec_tag *codec, ogg_page *page); void (*codec_free)(ogg_state_t *ogg_info, struct ogg_codec_tag *codec); } ogg_codec_t; refbuf_t *make_refbuf_with_page (ogg_page *page); void format_ogg_attach_header (ogg_state_t *ogg_info, ogg_page *page); void format_ogg_free_headers (ogg_state_t *ogg_info); int format_ogg_get_plugin (source_t *source); #endif /* __FORMAT_OGG_H__ */ icecast-2.4.2/src/client.h0000664000175000017500000000477512511160565012312 00000000000000/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2000-2004, Jack Moffitt , * oddsock , * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft , */ /* client.h ** ** client data structions and function definitions ** */ #ifndef __CLIENT_H__ #define __CLIENT_H__ #include "connection.h" #include "refbuf.h" #include "httpp/httpp.h" typedef struct _client_tag { /* the client's connection */ connection_t *con; /* the client's http headers */ http_parser_t *parser; /* http response code for this client */ int respcode; /* auth completed, 0 not yet, 1 passed */ int authenticated; /* is client getting intro data */ long intro_offset; /* where in the queue the client is */ refbuf_t *refbuf; /* position in first buffer */ unsigned int pos; /* auth used for this client */ struct auth_tag *auth; /* Client username, if authenticated */ char *username; /* Client password, if authenticated */ char *password; /* Format-handler-specific data for this client */ void *format_data; /* function to call to release format specific resources */ void (*free_client_data)(struct _client_tag *client); /* write out data associated with client */ int (*write_to_client)(struct _client_tag *client); /* function to check if refbuf needs updating */ int (*check_buffer)(struct source_tag *source, struct _client_tag *client); } client_t; int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser); void client_destroy(client_t *client); void client_send_100(client_t *client); void client_send_404(client_t *client, const char *message); void client_send_401(client_t *client); void client_send_403(client_t *client, const char *message); void client_send_400(client_t *client, const char *message); void client_send_500(client_t *client, const char *message); int client_send_bytes (client_t *client, const void *buf, unsigned len); int client_read_bytes (client_t *client, void *buf, unsigned len); void client_set_queue (client_t *client, refbuf_t *refbuf); int client_check_source_auth (client_t *client, const char *mount); #endif /* __CLIENT_H__ */ icecast-2.4.2/depcomp0000755000175000017500000005601612261335263011443 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: icecast-2.4.2/ChangeLog0000664000175000017500000052762312511176717011656 000000000000002015-04-08 10:07:42 dm8tbr * apply fix for documentation (needed by distro packaging) 2015-04-08 09:09:26 ph3-der-loewe * Fix: Do not crash URL Auth is used with stream_auth and no credentials are given. This fixes a crash (NULL reference) in case URL Auth is used and stream_auth is trigged with no credentials passed by the client. Username and password is now set to empty strings and transmited to the backend server this way. See #2191 for more details and to keep track of the problem. Closes: #2191, DEB#782120 2015-04-08 09:02:20 ph3-der-loewe * Fix: Let util_url_escape() handle NULL parameter. This lets util_url_escape() handle NULL passed as parameter. In case the parameter is NULL it will also return NULL. This patch also does some cleanup of the code such as migration away from int and thus avoiding future failures. 2015-04-08 08:32:23 dm8tbr * update version number to 2.4.2 in preparation for release this will be a strict security release 2015-04-08 08:18:40 dm8tbr * applying curl fix for win32 from master 2014-11-19 13:42:23 dm8tbr * This is Spaaarrr^w Icecast 2.4.1! 2014-11-19 13:41:09 dm8tbr * Makefile.am and configure.in for new docs 2014-11-19 12:18:49 dm8tbr * Removing unmaintained RPM spec file 2014-11-19 11:30:58 ePirat * Set PATH_MAX to 4096 if not defined (patch by Svante Signell ) See: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=767542 2014-11-18 19:57:21 ePirat * Docs: 2.4.1 docs added 2014-11-18 10:17:16 ePirat * fix for memory errors when using a lot of headers 2014-11-18 08:51:03 dm8tbr * Comments in break things ATM. Moved the comment out to avoid this bug. Needs to be checked. 2014-11-17 19:20:57 ph3-der-loewe * subset of earlier patch so it can go into 2.4.1: disconnects stdio of scripts from server owned filehandles. * This is considered a security fix: if on-connect/on-disconnect scripts are used, file descriptors of the server process remain open and could be written to or read from. Most pressing STDIN, STDOUT, STDERR are handled. Further all file descriptors up to 1024 are closed. There is a remaining (much lower) risk in combination of either a malicious or susceptible script and FDs above 1024. 2014-11-10 10:46:55 ph3-der-loewe * patch to fix regression on header size with large headers introduced by support of and . This should ensure we have at least space for 2kB of extra headers. Depending on function and call we may have much more space. 2014-11-10 08:23:34 dm8tbr * Update minimal config to also contain ACAO * header 2014-11-10 06:25:15 dm8tbr * Update default config: SSL, headers, default-mount 2014-11-09 10:55:29 dm8tbr * Updated default openSSL cipher string * https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 * same Qualys result 2014-11-09 09:13:59 dm8tbr * Clean up default config 2014-11-08 16:23:26 dm8tbr * Applying patch by ph3-der-loewe, HTTP PUT requires content-type * In case of SOURCE we are lenient and thus quite some source clients don't send a proper content-type, especially if they only support mp3. * This was meant to be introduced in 2.4.0 already, sadly we missed it. * All source clients MUST send proper content-type after migrating to Icecast HTTP PUT protocol. 2014-11-08 13:34:45 ph3-der-loewe * Fixed regression introduced in r18356 (CVE-2011-4612): client duration time is now correctly logged. PRIu64 MUST NOT be used with log_write_direct() as depending on platform PRIu64 may be using something not supported by __vsnprintf() of log/log.c. 2014-11-08 12:28:17 ph3-der-loewe * make use of sizeof() not explicit magic numbers 2014-11-07 23:10:43 ph3-der-loewe * fixing some compiler warnings 2014-11-07 22:06:06 ph3-der-loewe * updated some copyright headers 2014-11-07 20:56:04 ph3-der-loewe * fix for %z on win*. hope it doesn't breaky anything else. 2014-11-07 19:14:28 ph3-der-loewe * added warnings on empty and default values of , , , and 2014-11-07 11:18:54 ph3-der-loewe * send errorlog (loglevel WARN) to stderr prior to opening the real logfiles. 2014-11-07 10:12:24 ph3-der-loewe * added support for type="" and status="" in
(subelement of ). 2014-11-07 02:55:57 ph3-der-loewe * Added support for within . Also support merging of headers (normal mount + default mount). 2014-11-07 01:40:28 ph3-der-loewe * handle empty strings in config file better. Now empty strings are handled in: accesslog, errorlog, logdir, webroot, adminroot and hopefully all kinds of port. 2014-11-07 00:56:02 ph3-der-loewe * initial patch to allow adding user defined headers 2014-11-06 23:55:58 ph3-der-loewe * coding style and typo correcion 2014-11-06 12:02:00 dm8tbr * Be more verbose in case of fileserve off 2014-11-05 10:09:07 dm8tbr * applied patch to update the default ciphers to be more secure * tested this successfully against https://www.ssllabs.com/ssltest/ 2014-11-03 19:34:10 ph3-der-loewe * applied patch to disable SSLv3 and SSL compression explicitly 2014-11-02 20:19:29 dm8tbr * fix JSON status API problems * Put the last item check into every filtered tag. * This way we shouldn't run into problems of this type anymore. * Also it should be easier to customize this way, if someone wants to filter differently. 2014-10-31 09:00:45 ph3-der-loewe * rename ICE_LISTEN_QUEUE, ICE_RUNNING and ICE_HALTING so they have a prefix of ICECAST_ 2014-10-31 08:46:58 ph3-der-loewe * LOG_{ERROR|WARN|INFO|DEBUG}() -> ICECAST_LOG_{ERROR|WARN|INFO|DEBUG}() * avoid collision with LOG_INFO that is defined as part of syslog. 2014-10-26 14:03:57 ph3-der-loewe * make in work if no is given. 2014-10-23 20:41:38 epirat * More detailed logging * Add source IP adress to startup and source exit logging * Add mountpoint to some log lines 2014-10-18 16:25:29 ph3-der-loewe * fix warnings, mostly related to win*-builds 2014-10-09 10:39:13 ph3-der-loewe * Replace the old logging macros with variadic argument macros. (patch by ePirat) 2014-07-23 16:55:57 dm8tbr * removed threadpool from example config it is long gone and unused 2014-07-23 10:20:47 dm8tbr * Fix autogen.sh to work properly on Mac OS * Applying patch by ePirat 2014-05-06 05:23:42 dm8tbr * This is Icecast 2.4.0! 2014-05-06 04:53:24 dm8tbr * SECURITY FIX - Override supplementary groups if 2014-05-05 05:16:44 dm8tbr * Added