mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
added parsing of new icy-audio-info header which will be used to
communicate things like samplerate/quality/number of channels to icecast2. This info will be then forwarded to the yp servers for better stream info. also factored out some logic in source_main into common functions added a few new routines into util.c (taken from Brendan's updates to libshout) svn path=/trunk/icecast/; revision=4379
This commit is contained in:
parent
680e56bf7b
commit
1658f1717e
213
src/source.c
213
src/source.c
@ -34,12 +34,28 @@
|
||||
#undef CATMODULE
|
||||
#define CATMODULE "source"
|
||||
|
||||
#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_URL_TIMEOUT 9
|
||||
#define YP_TOUCH_INTERVAL 10
|
||||
#define YP_LAST_TOUCH 11
|
||||
|
||||
/* avl tree helper */
|
||||
static int _compare_clients(void *compare_arg, void *a, void *b);
|
||||
static int _remove_client(void *key);
|
||||
static int _free_client(void *key);
|
||||
static int _parse_audio_info(source_t *source, char *s);
|
||||
static void _add_yp_info(source_t *source, char *stat_name,
|
||||
void *info, int type);
|
||||
|
||||
source_t *source_create(client_t *client, connection_t *con, http_parser_t *parser, const char *mount, format_type_t type)
|
||||
source_t *source_create(client_t *client, connection_t *con,
|
||||
http_parser_t *parser, const char *mount, format_type_t type)
|
||||
{
|
||||
int i = 0;
|
||||
source_t *src;
|
||||
@ -57,6 +73,7 @@ source_t *source_create(client_t *client, connection_t *con, http_parser_t *pars
|
||||
src->num_yp_directories = 0;
|
||||
src->listeners = 0;
|
||||
src->send_return = 0;
|
||||
src->audio_info = util_dict_new();
|
||||
for (i=0;i<config_get_config()->num_yp_directories;i++) {
|
||||
if (config_get_config()->yp_url[i]) {
|
||||
src->ypdata[src->num_yp_directories] = yp_create_ypdata();
|
||||
@ -124,6 +141,7 @@ int source_free_source(void *key)
|
||||
for (i=0; i<source->num_yp_directories; i++) {
|
||||
yp_destroy_ypdata(source->ypdata[i]);
|
||||
}
|
||||
util_dict_free(source->audio_info);
|
||||
free(source);
|
||||
|
||||
return 1;
|
||||
@ -149,9 +167,11 @@ void *source_main(void *arg)
|
||||
refbuf_t *refbuf, *abuf;
|
||||
int data_done;
|
||||
|
||||
int listeners = 0;
|
||||
int i=0;
|
||||
int suppress_yp = 0;
|
||||
int listeners = 0;
|
||||
int i=0;
|
||||
int suppress_yp = 0;
|
||||
util_dict *audio_info;
|
||||
char *ai;
|
||||
|
||||
long queue_limit = config_get_config()->queue_size_limit;
|
||||
|
||||
@ -191,59 +211,32 @@ void *source_main(void *arg)
|
||||
stats_event(source->mount, "listeners", "0");
|
||||
source->listeners = 0;
|
||||
if ((s = httpp_getvar(source->parser, "ice-name"))) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_name) {
|
||||
free(source->ypdata[i]->server_name);
|
||||
}
|
||||
source->ypdata[i]->server_name = malloc(strlen(s) +1);
|
||||
strcpy(source->ypdata[i]->server_name, s);
|
||||
}
|
||||
stats_event(source->mount, "name", s);
|
||||
_add_yp_info(source, "server name", s, YP_SERVER_NAME);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-url"))) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_url) {
|
||||
free(source->ypdata[i]->server_url);
|
||||
}
|
||||
source->ypdata[i]->server_url = malloc(strlen(s) +1);
|
||||
strcpy(source->ypdata[i]->server_url, s);
|
||||
}
|
||||
stats_event(source->mount, "url", s);
|
||||
_add_yp_info(source, "server url", s, YP_SERVER_URL);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-genre"))) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_genre) {
|
||||
free(source->ypdata[i]->server_genre);
|
||||
}
|
||||
source->ypdata[i]->server_genre = malloc(strlen(s) +1);
|
||||
strcpy(source->ypdata[i]->server_genre, s);
|
||||
}
|
||||
stats_event(source->mount, "genre", s);
|
||||
_add_yp_info(source, "genre", s, YP_SERVER_GENRE);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-bitrate"))) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->bitrate) {
|
||||
free(source->ypdata[i]->bitrate);
|
||||
}
|
||||
source->ypdata[i]->bitrate = malloc(strlen(s) +1);
|
||||
strcpy(source->ypdata[i]->bitrate, s);
|
||||
}
|
||||
stats_event(source->mount, "bitrate", s);
|
||||
_add_yp_info(source, "bitrate", s, YP_BITRATE);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-description"))) {
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_desc) {
|
||||
free(source->ypdata[i]->server_desc);
|
||||
}
|
||||
source->ypdata[i]->server_desc = malloc(strlen(s) +1);
|
||||
strcpy(source->ypdata[i]->server_desc, s);
|
||||
}
|
||||
stats_event(source->mount, "description", s);
|
||||
_add_yp_info(source, "server description", s, YP_SERVER_DESC);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-private"))) {
|
||||
stats_event(source->mount, "public", s);
|
||||
suppress_yp = atoi(s);
|
||||
}
|
||||
if ((s = httpp_getvar(source->parser, "ice-audio-info"))) {
|
||||
if (_parse_audio_info(source, s)) {
|
||||
ai = util_dict_urlencode(source->audio_info, '&');
|
||||
_add_yp_info(source, "audio info",
|
||||
ai,
|
||||
YP_AUDIO_INFO);
|
||||
}
|
||||
}
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
if (source->ypdata[i]->server_type) {
|
||||
free(source->ypdata[i]->server_type);
|
||||
@ -275,8 +268,14 @@ void *source_main(void *arg)
|
||||
|
||||
current_time = time(NULL);
|
||||
|
||||
_add_yp_info(source, "last_touch", (void *)current_time,
|
||||
YP_LAST_TOUCH);
|
||||
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
source->ypdata[i]->yp_last_touch = current_time;
|
||||
/* Give the source 5 seconds to update the metadata
|
||||
before we do our first touch */
|
||||
source->ypdata[i]->yp_last_touch = current_time -
|
||||
source->ypdata[i]->yp_touch_interval + 5;
|
||||
/* Don't permit touch intervals of less than 30 seconds */
|
||||
if (source->ypdata[i]->yp_touch_interval <= 30) {
|
||||
source->ypdata[i]->yp_touch_interval = 30;
|
||||
@ -622,3 +621,127 @@ static int _free_client(void *key)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_audio_info(source_t *source, char *s)
|
||||
{
|
||||
char *token;
|
||||
char *pvar;
|
||||
char *variable;
|
||||
char *value;
|
||||
|
||||
while ((token = strtok(s,";")) != NULL) {
|
||||
pvar = strchr(token, '=');
|
||||
if (pvar) {
|
||||
variable = (char *)malloc(pvar-token+1);
|
||||
memset(variable, '\000', pvar-token+1);
|
||||
strncpy(variable, token, pvar-token);
|
||||
pvar++;
|
||||
if (strlen(pvar)) {
|
||||
value = (char *)malloc(strlen(pvar)+1);
|
||||
memset(value, '\000', strlen(pvar)+1);
|
||||
strncpy(value, pvar, strlen(pvar));
|
||||
util_dict_set(source->audio_info, variable, value);
|
||||
stats_event(source->mount, variable, value);
|
||||
}
|
||||
if (variable) {
|
||||
free(variable);
|
||||
}
|
||||
if (value) {
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
s = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _add_yp_info(source_t *source, char *stat_name,
|
||||
void *info, int type)
|
||||
{
|
||||
int i;
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
for (i=0;i<source->num_yp_directories;i++) {
|
||||
switch (type) {
|
||||
case YP_SERVER_NAME:
|
||||
if (source->ypdata[i]->server_name) {
|
||||
free(source->ypdata[i]->server_name);
|
||||
}
|
||||
source->ypdata[i]->server_name =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->server_name, (char *)info);
|
||||
stats_event(source->mount, stat_name, (char *)info);
|
||||
break;
|
||||
case YP_SERVER_DESC:
|
||||
if (source->ypdata[i]->server_desc) {
|
||||
free(source->ypdata[i]->server_desc);
|
||||
}
|
||||
source->ypdata[i]->server_desc =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->server_desc, (char *)info);
|
||||
stats_event(source->mount, stat_name, (char *)info);
|
||||
break;
|
||||
case YP_SERVER_GENRE:
|
||||
if (source->ypdata[i]->server_genre) {
|
||||
free(source->ypdata[i]->server_genre);
|
||||
}
|
||||
source->ypdata[i]->server_genre =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->server_genre, (char *)info);
|
||||
stats_event(source->mount, stat_name, (char *)info);
|
||||
break;
|
||||
case YP_SERVER_URL:
|
||||
if (source->ypdata[i]->server_url) {
|
||||
free(source->ypdata[i]->server_url);
|
||||
}
|
||||
source->ypdata[i]->server_url =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->server_url, (char *)info);
|
||||
stats_event(source->mount, stat_name, (char *)info);
|
||||
break;
|
||||
case YP_BITRATE:
|
||||
if (source->ypdata[i]->bitrate) {
|
||||
free(source->ypdata[i]->bitrate);
|
||||
}
|
||||
source->ypdata[i]->bitrate =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->bitrate, (char *)info);
|
||||
stats_event(source->mount, stat_name, (char *)info);
|
||||
break;
|
||||
case YP_AUDIO_INFO:
|
||||
if (source->ypdata[i]->audio_info) {
|
||||
free(source->ypdata[i]->audio_info);
|
||||
}
|
||||
source->ypdata[i]->audio_info =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->audio_info, (char *)info);
|
||||
break;
|
||||
case YP_SERVER_TYPE:
|
||||
if (source->ypdata[i]->server_type) {
|
||||
free(source->ypdata[i]->server_type);
|
||||
}
|
||||
source->ypdata[i]->server_type =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->server_type, (char *)info);
|
||||
break;
|
||||
case YP_CURRENT_SONG:
|
||||
if (source->ypdata[i]->current_song) {
|
||||
free(source->ypdata[i]->current_song);
|
||||
}
|
||||
source->ypdata[i]->current_song =
|
||||
malloc(strlen((char *)info) +1);
|
||||
strcpy(source->ypdata[i]->current_song, (char *)info);
|
||||
stats_event(source->mount, stat_name, (char *)info);
|
||||
break;
|
||||
case YP_URL_TIMEOUT:
|
||||
source->ypdata[i]->yp_url_timeout = (int)info;
|
||||
break;
|
||||
case YP_LAST_TOUCH:
|
||||
source->ypdata[i]->yp_last_touch = (int)info;
|
||||
break;
|
||||
case YP_TOUCH_INTERVAL:
|
||||
source->ypdata[i]->yp_touch_interval = (int)info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "yp.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
|
||||
typedef struct source_tag
|
||||
@ -27,6 +28,7 @@ typedef struct source_tag
|
||||
|
||||
rwlock_t *shutdown_rwlock;
|
||||
ypdata_t *ypdata[MAX_YP_DIRECTORIES];
|
||||
util_dict *audio_info;
|
||||
int num_yp_directories;
|
||||
long listeners;
|
||||
long max_listeners;
|
||||
|
136
src/util.c
136
src/util.c
@ -385,3 +385,139 @@ char *util_base64_decode(unsigned char *input)
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int util_dict_set(util_dict *dict, const char *key, const char *val)
|
||||
{
|
||||
util_dict *prev;
|
||||
|
||||
if (!dict || !key) {
|
||||
ERROR0("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) {
|
||||
ERROR0("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);
|
||||
|
||||
ERROR0("unable to allocate new dictionary key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dict->val = strdup(val);
|
||||
if (!dict->val) {
|
||||
ERROR0("unable to allocate new dictionary value");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* given a dictionary, URL-encode each key and val and
|
||||
stringify them 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 (!(enc = util_url_escape(dict->key))) {
|
||||
if (res)
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
if (start) {
|
||||
if (!(res = malloc(strlen(enc) + 1))) {
|
||||
free(enc);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(res, "%s", enc);
|
||||
free(enc);
|
||||
start = 0;
|
||||
} else {
|
||||
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
||||
free(enc);
|
||||
free(res);
|
||||
return NULL;
|
||||
} else
|
||||
res = tmp;
|
||||
sprintf(res + strlen(res), "%c%s", delim, enc);
|
||||
free(enc);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
14
src/util.h
14
src/util.h
@ -16,4 +16,18 @@ char *util_base64_decode(unsigned char *input);
|
||||
|
||||
char *util_url_escape(char *src);
|
||||
|
||||
/* 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);
|
||||
#endif /* __UTIL_H__ */
|
||||
|
23
src/yp.c
23
src/yp.c
@ -196,8 +196,9 @@ int yp_add(source_t *source, int which)
|
||||
|
||||
if (ok) {
|
||||
if (source->ypdata[i]) {
|
||||
url_size = strlen("action=add&sn=&genre=&cpswd=&desc=&url="
|
||||
"&listenurl=&type=&b=") + 1;
|
||||
url_size = strlen("action=add&sn=&genre=&cpswd="
|
||||
"&desc=&url=&listenurl=&type=&b=&")
|
||||
+ 1;
|
||||
if (source->ypdata[i]->server_name) {
|
||||
url_size += strlen(source->ypdata[i]->server_name);
|
||||
}
|
||||
@ -261,10 +262,18 @@ int yp_add(source_t *source, int which)
|
||||
source->ypdata[i]->current_song = (char *)malloc(1);
|
||||
source->ypdata[i]->current_song[0] = 0;
|
||||
}
|
||||
if (source->ypdata[i]->audio_info) {
|
||||
url_size += strlen(source->ypdata[i]->audio_info);
|
||||
}
|
||||
else {
|
||||
source->ypdata[i]->audio_info = (char *)malloc(1);
|
||||
source->ypdata[i]->audio_info[0] = 0;
|
||||
}
|
||||
|
||||
url_size += 1024;
|
||||
url = malloc(url_size);
|
||||
sprintf(url, "action=add&sn=%s&genre=%s&cpswd=%s&desc=%s&url=%s"
|
||||
"&listenurl=%s&type=%s&b=%s",
|
||||
sprintf(url, "action=add&sn=%s&genre=%s&cpswd=%s&desc="
|
||||
"%s&url=%s&listenurl=%s&type=%s&b=%s&%s",
|
||||
source->ypdata[i]->server_name,
|
||||
source->ypdata[i]->server_genre,
|
||||
source->ypdata[i]->cluster_password,
|
||||
@ -272,7 +281,8 @@ int yp_add(source_t *source, int which)
|
||||
source->ypdata[i]->server_url,
|
||||
source->ypdata[i]->listen_url,
|
||||
source->ypdata[i]->server_type,
|
||||
source->ypdata[i]->bitrate);
|
||||
source->ypdata[i]->bitrate,
|
||||
source->ypdata[i]->audio_info);
|
||||
|
||||
curl_con = curl_get_connection();
|
||||
if (curl_con < 0) {
|
||||
@ -350,6 +360,9 @@ void yp_destroy_ypdata(ypdata_t *ypdata)
|
||||
if (ypdata->server_type) {
|
||||
free(ypdata->server_type);
|
||||
}
|
||||
if (ypdata->audio_info) {
|
||||
free(ypdata->audio_info);
|
||||
}
|
||||
free(ypdata);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user