static unsigned do_yp_touch (ypdata_t *yp, char *s, unsigned len) { unsigned listeners = 0; 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, "yp_currently_playing", song, YP_CURRENT_SONG); free (song); } } free (artist); free (title); val = (char *)stats_get_value (yp->mount, "listeners"); if (val) { listeners = atoi (val); free (val); } ret = snprintf (s, len, "action=touch&sid=%s&st=%s&listeners=%u\r\n", yp->sid, yp->current_song, listeners); if (ret >= (signed)len) return ret+1; /* space required for above text and nul*/ send_to_yp ("touch", yp, s); return 0; }
static unsigned 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"); 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; if (send_to_yp ("add", yp, s) == 0) { yp->process = do_yp_touch; /* force first touch in 5 secs */ yp->next_update = time(NULL) + 5; } return 0; }
/* the incoming rate can vary a fair bit so to get the expected value I add about 10% * (to handle lower figures) and then refer to the most significant 3 bits using shift * ops. This should give us a resoanble estimation for YP */ static void set_bitrate_from_inrate (ypdata_t *yp) { char *value = stats_get_value (yp->mount, "incoming_bitrate"); if (value) { long v = atol (value), c = 0; char buf [12]; v = (long)(v*1.1) + 5; for (; v > 7; c++) v >>= 1; v <<= c; v /= 1024; snprintf (buf, sizeof buf, "%ld", v); add_yp_info (yp, buf, YP_BITRATE); free (value); } }
static auth_result url_add_listener (auth_client *auth_user) { client_t *client = auth_user->client; auth_t *auth = auth_user->auth; auth_url *url = auth->state; auth_thread_data *atd = auth_user->thread_data; int res = 0, ret = AUTH_FAILED, poffset = 0; struct build_intro_contents *x; char *userpwd = NULL, post [8192]; if (url->addurl == NULL || client == NULL) return AUTH_OK; if (url->stop_req_until) { time_t now = time(NULL); if (url->stop_req_until <= now) { INFO1 ("restarting url after timeout on %s", auth_user->mount); url->stop_req_until = 0; } else { if (auth->flags & AUTH_SKIP_IF_SLOW) { client->flags |= CLIENT_AUTHENTICATED; return AUTH_OK; } return AUTH_FAILED; } } do { ice_config_t *config = config_get_config (); char *user_agent, *username, *password, *mount, *ipaddr, *referer, *current_listeners, *server = util_url_escape (config->hostname); int port = config->port; config_release_config (); const char *tmp = httpp_getvar (client->parser, "user-agent"); if (tmp == NULL) tmp = "-"; user_agent = util_url_escape (tmp); 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) */ tmp = httpp_getvar (client->parser, HTTPP_VAR_QUERYARGS); snprintf (post, sizeof post, "%s%s", auth_user->mount, tmp ? tmp : ""); mount = util_url_escape (post); ipaddr = util_url_escape (client->connection.ip); tmp = httpp_getvar (client->parser, "referer"); referer = tmp ? util_url_escape (tmp) : strdup (""); current_listeners = stats_get_value(auth->mount, "listeners"); if (current_listeners == NULL) current_listeners = strdup(""); poffset = snprintf (post, sizeof (post), "action=listener_add&server=%s&port=%d&client=%" PRIu64 "&mount=%s" "&user=%s&pass=%s&ip=%s&agent=%s&referer=%s&listeners=%s", server, port, client->connection.id, mount, username, password, ipaddr, user_agent, referer, current_listeners); free (current_listeners); free (server); free (mount); free (referer); free (user_agent); free (username); free (password); free (ipaddr); if (poffset < 0 || poffset >= sizeof (post)) { WARN2 ("client from %s (on %s), rejected with headers problem", &client->connection.ip[0], auth_user->mount); return AUTH_FAILED; } } while (0); if (url->header_chk_list) { int c = url->header_chk_count, remaining = sizeof(post) - poffset; char *cur_header = url->header_chk_list; const char *prefix = (url->header_chk_prefix && isalnum (url->header_chk_prefix[0])) ? url->header_chk_prefix : "ClientHeader-"; for (; c ; c--) { int len = strlen (cur_header); const char *val = httpp_getvar (client->parser, cur_header); if (val) { char *valesc = util_url_escape (val); int r = remaining > 0 ? snprintf (post+poffset, remaining, "&%s%s=%s", prefix, cur_header, valesc) : -1; free (valesc); if (r < 0 || r > remaining) { WARN2 ("client from %s (on %s), rejected with too much in headers", &client->connection.ip[0], auth_user->mount); return AUTH_FAILED; } poffset += r; remaining -= r; } cur_header += (len + 1); // get past next nul } } if (strchr (url->addurl, '@') == NULL) { if (url->userpwd) curl_easy_setopt (atd->curl, CURLOPT_USERPWD, url->userpwd); else { /* auth'd requests may not have a user/pass, but may use query args */ if (client->username && client->password) { int len = strlen (client->username) + strlen (client->password) + 2; userpwd = malloc (len); snprintf (userpwd, len, "%s:%s", client->username, client->password); curl_easy_setopt (atd->curl, CURLOPT_USERPWD, userpwd); } else curl_easy_setopt (atd->curl, CURLOPT_USERPWD, ""); } } else { /* url has user/pass but libcurl may need to clear any existing settings */ curl_easy_setopt (atd->curl, CURLOPT_USERPWD, ""); } curl_easy_setopt (atd->curl, CURLOPT_URL, url->addurl); curl_easy_setopt (atd->curl, CURLOPT_POSTFIELDS, post); curl_easy_setopt (atd->curl, CURLOPT_WRITEHEADER, auth_user); curl_easy_setopt (atd->curl, CURLOPT_WRITEDATA, auth_user); atd->errormsg[0] = '\0'; free (atd->location); atd->location = NULL; /* setup in case intro data is returned */ x = (void *)client->refbuf->data; x->type = 0; x->head = NULL; x->intro_len = 0; x->tailp = &x->head; DEBUG2 ("handler %d (%s) sending request", auth_user->handler, auth_user->mount); res = curl_easy_perform (atd->curl); DEBUG2 ("handler %d (%s) request finished", auth_user->handler, auth_user->mount); free (userpwd); if (client->flags & CLIENT_AUTHENTICATED) { if (client->flags & CLIENT_HAS_INTRO_CONTENT) { client->refbuf->next = x->head; DEBUG3 ("intro (%d) received %lu for %s", x->type, (unsigned long)x->intro_len, client->connection.ip); } if (x->head == NULL) client->flags &= ~CLIENT_HAS_INTRO_CONTENT; x->head = NULL; ret = AUTH_OK; } if (res) { url->stop_req_until = time (NULL) + url->stop_req_duration; /* prevent further attempts for a while */ WARN3 ("auth to server %s (%s) failed with %s", url->addurl, auth_user->mount, atd->errormsg); INFO1 ("will not auth new listeners for %d seconds", url->stop_req_duration); if (auth->flags & AUTH_SKIP_IF_SLOW) { client->flags |= CLIENT_AUTHENTICATED; ret = AUTH_OK; } } /* better cleanup memory */ while (x->head) { refbuf_t *n = x->head; x->head = n->next; n->next = NULL; refbuf_release (n); } if (x->type) mpeg_cleanup (&x->sync); if (atd->location) { client_send_302 (client, atd->location); auth_user->client = NULL; free (atd->location); atd->location = NULL; } else if (atd->errormsg[0]) { INFO3 ("listener %s (%s) returned \"%s\"", client->connection.ip, url->addurl, atd->errormsg); if (atoi (atd->errormsg) == 403) { auth_user->client = NULL; client_send_403 (client, atd->errormsg+4); } } 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_flags (yp->mount, "yp_currently_playing", song, STATS_COUNTERS); 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_schedule (yp, yp->touch_interval); return 0; } return -1; }
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) { add_yp_info (yp, value, YP_BITRATE); free (value); } else set_bitrate_from_inrate (yp); 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); if (yp->server_name[0] == 0 || yp->server_genre[0] == 0 || yp->server_type[0] == 0 || yp->bitrate[0] == 0) { INFO1 ("mount %s requires stats (sn, genre, type, bitrate)", yp->mount); yp_schedule (yp, 600); return -1; } 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_schedule (yp, 5); } return ret; }