diff --git a/src/Makefile.am b/src/Makefile.am index 38f7407f..83f391df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,16 +8,16 @@ bin_PROGRAMS = icecast noinst_HEADERS = config.h os.h logging.h sighandler.h connection.h global.h\ util.h slave.h source.h stats.h refbuf.h client.h format.h format_vorbis.h\ - compat.h format_mp3.h fserve.h xslt.h + compat.h format_mp3.h fserve.h xslt.h geturl.h yp.h icecast_SOURCES = config.c main.c logging.c sighandler.c connection.c global.c\ util.c slave.c source.c stats.c refbuf.c client.c format.c format_vorbis.c\ - format_mp3.c xslt.c fserve.c + format_mp3.c xslt.c fserve.c geturl.c yp.c icecast_LDADD = net/libicenet.la thread/libicethread.la httpp/libicehttpp.la\ log/libicelog.la avl/libiceavl.la timing/libicetiming.la -LIBS = @LIBS@ @XSLT_LIBS@ @SOCKET_LIBS@ @XML_LIBS@ @OGG_LIBS@ @VORBIS_LIBS@ -CFLAGS = -g @CFLAGS@ @XML_CFLAGS@ @XSLT_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ +LIBS = @LIBS@ @XSLT_LIBS@ @SOCKET_LIBS@ @XML_LIBS@ @OGG_LIBS@ @VORBIS_LIBS@ @CURL_LIBS@ @PTHREAD_LIBS@ +CFLAGS = -g @CFLAGS@ @XML_CFLAGS@ @XSLT_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ @CURL_CFLAGS@ @PTHREAD_CFLAGS@ INCLUDES = -I$(srcdir)/net -I$(srcdir)/thread -I$(srcdir)/avl -I$(srcdir)/httpp \ -I$(srcdir)/log -I$(srcdir)/timing diff --git a/src/geturl.c b/src/geturl.c new file mode 100644 index 00000000..054beb18 --- /dev/null +++ b/src/geturl.c @@ -0,0 +1,178 @@ +#include +#include + +#include + +#include "connection.h" +#include "refbuf.h" +#include "client.h" +#include "logging.h" +#include "format.h" +#include "geturl.h" +#include "source.h" +#include "config.h" + +#include +#include +#include + + +#define CATMODULE "CURL" + +static CurlConnection curlConnections[NUM_CONNECTIONS]; +static int nunConnections = NUM_CONNECTIONS; +mutex_t _curl_mutex; + +size_t +WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +{ + register int realsize = size * nmemb; + + struct MemoryStruct *mem = (struct MemoryStruct *)data; + + if ((realsize + mem->size) < YP_RESPONSE_SIZE-1) { + strncat(mem->memory, ptr, realsize); + } + + return realsize; +} +size_t +HeaderMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +{ + char *p1 = 0; + char *p2 = 0; + int copylen = 0; + register int realsize = size * nmemb; + struct MemoryStruct2 *mem = (struct MemoryStruct2 *)data; + + if (!strncmp(ptr, "SID: ", strlen("SID: "))) { + p1 = (char *)ptr + strlen("SID: "); + p2 = strchr((const char *)p1, '\r'); + memset(mem->sid, '\000', sizeof(mem->sid)); + if (p2) { + if (p2-p1 > sizeof(mem->sid)-1) { + copylen = sizeof(mem->sid)-1; + } + else { + copylen = p2-p1; + } + strncpy(mem->sid, p1, copylen); + } + else { + strncpy(mem->sid, p1, sizeof(mem->sid)-1); + strcpy(mem->sid, p1); + } + } + if (!strncmp(ptr, "YPMessage: ", strlen("YPMessage: "))) { + p1 = (char *)ptr + strlen("YPMessage: "); + p2 = strchr((const char *)p1, '\r'); + memset(mem->message, '\000', sizeof(mem->message)); + if (p2) { + if (p2-p1 > sizeof(mem->message)-1) { + copylen = sizeof(mem->message)-1; + } + else { + copylen = p2-p1; + } + strncpy(mem->message, p1, copylen); + } + else { + strncpy(mem->message, p1, sizeof(mem->message)-1); + strcpy(mem->message, p1); + } + } + if (!strncmp(ptr, "TouchFreq: ", strlen("TouchFreq: "))) { + p1 = (char *)ptr + strlen("TouchFreq: "); + mem->touchFreq = atoi(p1); + } + if (!strncmp(ptr, "YPResponse: ", strlen("YPResponse: "))) { + p1 = (char *)ptr + strlen("YPResponse: "); + mem->response = atoi(p1); + } + return realsize; +} + +int curl_initialize() +{ + int i = 0; + thread_mutex_create(&_curl_mutex); + + memset(&curlConnections, '\000', sizeof(curlConnections)); + for (i=0;i (%s)", mem->sid); + DEBUG1("Message -> (%s)", mem->message); + DEBUG1("Touch Freq -> (%d)", mem->touchFreq); + DEBUG1("Response -> (%d)", mem->response); +} + + +CURL *getCurlHandle(int which) +{ + return curlConnections[which].curl_handle; +} +struct MemoryStruct *getCurlResult(int which) +{ + return &(curlConnections[which].result); +} + +struct MemoryStruct2 *getCurlHeaderResult(int which) +{ + return &(curlConnections[which].headerresult); +} diff --git a/src/geturl.h b/src/geturl.h new file mode 100644 index 00000000..ca742a7e --- /dev/null +++ b/src/geturl.h @@ -0,0 +1,45 @@ +#ifndef __GETURL_H__ +#define __GETURL_H__ + +#include + +#include +#include +#include + +#define NUM_CONNECTIONS 10 +#define NAK 0 +#define ACK 1 +#define YP_RESPONSE_SIZE 2046 +#define YP_SID_SIZE 255 + +struct MemoryStruct { + char memory[YP_RESPONSE_SIZE]; + size_t size; +}; +struct MemoryStruct2 { + char sid[YP_SID_SIZE]; + char message[YP_RESPONSE_SIZE]; + int touchFreq; + int response; + size_t size; +}; + +typedef struct tag_CurlConnection { + struct MemoryStruct result; + struct MemoryStruct2 headerresult; + CURL *curl_handle; + int inUse; +} CurlConnection; + + +int curl_initialize(); +void curl_shutdown(); +CURL *getCurlHandle(int which); +struct MemoryStruct *getCurlResult(int which); +struct MemoryStruct2 *getCurlHeaderResult(int which); +void printHeaderResult(struct MemoryStruct2 *mem); +int getCurlConnection(); +int releaseCurlConnection(int which); +#endif + diff --git a/src/yp.c b/src/yp.c new file mode 100644 index 00000000..33d996ff --- /dev/null +++ b/src/yp.c @@ -0,0 +1,375 @@ +#include +#include + +#include + +#include "connection.h" +#include "refbuf.h" +#include "client.h" +#include "logging.h" +#include "format.h" +#include "geturl.h" +#include "source.h" +#include "config.h" + +#define CATMODULE "YP" + +int yp_submit_url(int curlCon, char *yp_url, char *pURL, char *type) +{ + int ret = 0; + + curl_easy_setopt(getCurlHandle(curlCon), CURLOPT_URL, yp_url); + curl_easy_setopt(getCurlHandle(curlCon), CURLOPT_POSTFIELDS, pURL); + curl_easy_setopt(getCurlHandle(curlCon), CURLOPT_TIMEOUT, config_get_config()->yp_url_timeout); + + /* get it! */ + memset(getCurlResult(curlCon), '\000', sizeof(struct MemoryStruct)); + memset(getCurlHeaderResult(curlCon), '\000', sizeof(struct MemoryStruct2)); + + curl_easy_perform(getCurlHandle(curlCon)); + + printHeaderResult(getCurlHeaderResult(curlCon)); + + if (getCurlHeaderResult(curlCon)->response == ACK) { + INFO2("Successfull ACK from %s (%s)", type, yp_url); + ret = 1; + } + else { + if (strlen(getCurlHeaderResult(curlCon)->message) > 0) { + ERROR3("Got a NAK from %s(%s) (%s)", type,getCurlHeaderResult(curlCon)->message, yp_url); + } + else { + ERROR2("Got a NAK from %s(Unknown) (%s)", type, yp_url); + } + ret = 0; + } + return ret; +} + +void *yp_touch_thread(void *arg) +{ + yp_touch((source_t *)arg); + thread_exit(0); + return NULL; +} +int yp_remove(void *psource) +{ + char *pURL = NULL; + int pURLsize = 0; + int ret = 0; + int curlCon = 0; + char *p1 = NULL; + int i = 0; + + int regenSID = 0; + long currentTime = 0; + source_t *source = (source_t *)psource; + + currentTime = time(¤tTime); + + for (i=0;inum_yp_directories;i++) { + source->ypdata[i]->yp_last_touch = currentTime; + + if (source->ypdata[i]->sid == 0) { + return 0; + } + else { + if (strlen(source->ypdata[i]->sid) == 0) { + return 0; + } + } + + if (source->ypdata) { + pURLsize = strlen("action=remove&sid=") + 1; + pURLsize += strlen(source->ypdata[i]->sid); + pURLsize += 1024; + + pURL = (char *)malloc(pURLsize); + memset(pURL, '\000', pURLsize); + sprintf(pURL, "action=remove&sid=%s", + source->ypdata[i]->sid); + + curlCon = getCurlConnection(); + if (curlCon < 0) { + ERROR0("Unable to get auth connection"); + } + else { + + /* specify URL to get */ + ret = yp_submit_url(curlCon, source->ypdata[i]->yp_url, pURL, "yp_remove"); + } + + if (pURL) { + free(pURL); + } + + releaseCurlConnection(curlCon); + } + } + + return 1; +} +int yp_touch(void *psource) +{ + char *pURL = NULL; + int pURLsize = 0; + int ret = 0; + int curlCon = 0; + char *p1 = NULL; + int i = 0; + + int regenSID = 0; + long currentTime = 0; + source_t *source = (source_t *)psource; + + currentTime = time(¤tTime); + + for (i=0;inum_yp_directories;i++) { + + source->ypdata[i]->yp_last_touch = currentTime; + + if (source->ypdata[i]->sid == 0) { + regenSID = 1; + } + else { + if (strlen(source->ypdata[i]->sid) == 0) { + regenSID = 1; + } + } + + if (regenSID) { + if (!yp_add(source, i)) { + return 0; + } + } + + if (source->ypdata) { + pURLsize = strlen("action=touch&sid=&st=&listeners=") + 1; + if (source->ypdata[i]->current_song) { + pURLsize += strlen(source->ypdata[i]->current_song); + } + else { + source->ypdata[i]->current_song = (char *)malloc(1); + memset(source->ypdata[i]->current_song, '\000', 1); + } + if (source->ypdata[i]->sid) { + pURLsize += strlen(source->ypdata[i]->sid); + } + else { + source->ypdata[i]->sid = (char *)malloc(1); + memset(source->ypdata[i]->sid, '\000', 1); + } + pURLsize += 1024; + pURL = (char *)malloc(pURLsize); + memset(pURL, '\000', pURLsize); + sprintf(pURL, "action=touch&sid=%s&st=%s&listeners=%d", + source->ypdata[i]->sid, + source->ypdata[i]->current_song, + source->listeners); + + curlCon = getCurlConnection(); + if (curlCon < 0) { + ERROR0("Unable to get auth connection"); + } + else { + + /* specify URL to get */ + ret = yp_submit_url(curlCon, source->ypdata[i]->yp_url, pURL, "yp_touch"); + } + + if (pURL) { + free(pURL); + } + + releaseCurlConnection(curlCon); + } + } + + return 1; +} +int yp_add(void *psource, int which) +{ + char *pURL = NULL; + int pURLsize = 0; + int ret = 0; + int curlCon = 0; + char *p1 = NULL; + int i = 0; + + int ok = 0; + source_t *source = (source_t *)psource; + + for (i=0;inum_yp_directories;i++) { + if (which != -1) { + if (i == which) { + ok = 1; + } + else { + ok = 0; + } + } + else { + ok = 1; + } + + if (ok) { + if (source->ypdata[i]) { + pURLsize = strlen("action=add&sn=&genre=&cpswd=&desc=&url=&listenurl=&type=&b=") + 1; + if (source->ypdata[i]->server_name) { + pURLsize += strlen(source->ypdata[i]->server_name); + } + else { + source->ypdata[i]->server_name = (char *)malloc(1); + memset(source->ypdata[i]->server_name, '\000', 1); + } + if (source->ypdata[i]->server_desc) { + pURLsize += strlen(source->ypdata[i]->server_desc); + } + else { + source->ypdata[i]->server_desc = (char *)malloc(1); + memset(source->ypdata[i]->server_desc, '\000', 1); + } + if (source->ypdata[i]->server_genre) { + pURLsize += strlen(source->ypdata[i]->server_genre); + } + else { + source->ypdata[i]->server_genre = (char *)malloc(1); + memset(source->ypdata[i]->server_genre, '\000', 1); + } + if (source->ypdata[i]->cluster_password) { + pURLsize += strlen(source->ypdata[i]->cluster_password); + } + else { + source->ypdata[i]->cluster_password = (char *)malloc(1); + memset(source->ypdata[i]->cluster_password, '\000', 1); + } + if (source->ypdata[i]->server_url) { + pURLsize += strlen(source->ypdata[i]->server_url); + } + else { + source->ypdata[i]->server_url = (char *)malloc(1); + memset(source->ypdata[i]->server_url, '\000', 1); + } + if (source->ypdata[i]->listen_url) { + pURLsize += strlen(source->ypdata[i]->listen_url); + } + else { + source->ypdata[i]->listen_url = (char *)malloc(1); + memset(source->ypdata[i]->listen_url, '\000', 1); + } + if (source->ypdata[i]->server_type) { + pURLsize += strlen(source->ypdata[i]->server_type); + } + else { + source->ypdata[i]->server_type = (char *)malloc(1); + memset(source->ypdata[i]->server_type, '\000', 1); + } + if (source->ypdata[i]->bitrate) { + pURLsize += strlen(source->ypdata[i]->bitrate); + } + else { + source->ypdata[i]->bitrate = (char *)malloc(1); + memset(source->ypdata[i]->bitrate, '\000', 1); + } + if (source->ypdata[i]->current_song) { + pURLsize += strlen(source->ypdata[i]->current_song); + } + else { + source->ypdata[i]->current_song = (char *)malloc(1); + memset(source->ypdata[i]->current_song, '\000', 1); + } + pURLsize += 1024; + pURL = (char *)malloc(pURLsize); + memset(pURL, '\000', pURLsize); + sprintf(pURL, "action=add&sn=%s&genre=%s&cpswd=%s&desc=%s&url=%s&listenurl=%s&type=%s&b=%s", + source->ypdata[i]->server_name, + source->ypdata[i]->server_genre, + source->ypdata[i]->cluster_password, + source->ypdata[i]->server_desc, + source->ypdata[i]->server_url, + source->ypdata[i]->listen_url, + source->ypdata[i]->server_type, + source->ypdata[i]->bitrate); + + curlCon = getCurlConnection(); + if (curlCon < 0) { + ERROR0("Unable to get auth connection"); + } + else { + + /* specify URL to get */ + ret = yp_submit_url(curlCon, source->ypdata[i]->yp_url, pURL, "yp_add"); + + if (ret) { + if (strlen(getCurlHeaderResult(curlCon)->sid) > 0) { + if (source->ypdata) { + if (source->ypdata[i]->sid) { + free(source->ypdata[i]->sid); + source->ypdata[i]->sid = NULL; + } + source->ypdata[i]->sid = (char *)malloc(strlen(getCurlHeaderResult(curlCon)->sid) +1); + memset(source->ypdata[i]->sid, '\000', strlen(getCurlHeaderResult(curlCon)->sid) +1); + strcpy(source->ypdata[i]->sid, getCurlHeaderResult(curlCon)->sid); + source->ypdata[i]->yp_touch_freq = getCurlHeaderResult(curlCon)->touchFreq; + } + } + } + } + + if (pURL) { + free(pURL); + } + + releaseCurlConnection(curlCon); + } + } + } + + return 1; +} + +ypdata_t *create_ypdata() +{ + ypdata_t *tmp; + + tmp = (ypdata_t *)malloc(sizeof(ypdata_t)); + memset(tmp, '\000', sizeof(ypdata_t)); + return(tmp); + +} +void destroy_ypdata(ypdata_t *ypdata) +{ + if (ypdata) { + 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->server_url) { + free(ypdata->server_url); + } + 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); + } + free(ypdata); + } +} diff --git a/src/yp.h b/src/yp.h new file mode 100644 index 00000000..37aee6fc --- /dev/null +++ b/src/yp.h @@ -0,0 +1,33 @@ +#ifndef __YP_H__ +#define __YP_H__ + +#include +#define YP_ADD_ALL -1 +typedef struct ypdata_tag +{ + char *sid; + char *server_name; + char *server_desc; + char *server_genre; + char *cluster_password; + char *server_url; + char *listen_url; + char *bitrate; + char *server_type; + char *current_song; + char *yp_url; + int yp_url_timeout; + long yp_last_touch; + int yp_touch_freq; +} ypdata_t; + +void *yp_touch_thread(void *arg); +int yp_add(void *psource, int which); +int yp_touch(void *psource); +int yp_remove(void *psource); +ypdata_t *create_ypdata(); +void destroy_ypdata(ypdata_t *ypdata); + +#endif + +