Merge branch 'spwebapi2'

This commit is contained in:
ejurgensen
2016-11-27 22:54:06 +01:00
15 changed files with 1260 additions and 385 deletions

View File

@@ -1129,8 +1129,8 @@ source_item_stream_get(struct artwork_ctx *ctx)
memset(&client, 0, sizeof(struct http_client_ctx));
client.url = url;
client.headers = kv;
client.body = ctx->evbuf;
client.input_headers = kv;
client.input_body = ctx->evbuf;
if (http_client_request(&client) < 0)
goto out_kv;

View File

@@ -3906,7 +3906,7 @@ db_spotify_purge(void)
ret = db_query_run(queries[i], 0, 1);
if (ret == 0)
DPRINTF(E_DBG, L_DB, "Purged %d rows\n", sqlite3_changes(hdl));
DPRINTF(E_DBG, L_DB, "Processed %d rows\n", sqlite3_changes(hdl));
}
// Disable the spotify directory by setting 'disabled' to INOTIFY_FAKE_COOKIE value
@@ -3950,7 +3950,7 @@ db_spotify_pl_delete(int id)
/* Spotify */
void
db_spotify_files_delete()
db_spotify_files_delete(void)
{
#define Q_TMPL "DELETE FROM files WHERE path LIKE 'spotify:%%' AND NOT path IN (SELECT filepath FROM playlistitems);"
char *query;

View File

@@ -620,7 +620,7 @@ void
db_spotify_pl_delete(int id);
void
db_spotify_files_delete();
db_spotify_files_delete(void);
#endif
/* Admin */

View File

@@ -1222,11 +1222,8 @@ bulk_scan(int flags)
else
{
/* Protect spotify from the imminent purge if rescanning */
if (flags & F_SCAN_RESCAN)
{
db_file_ping_bymatch("spotify:", 0);
db_pl_ping_bymatch("spotify:", 0);
}
db_file_ping_bymatch("spotify:", 0);
db_pl_ping_bymatch("spotify:", 0);
DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
db_purge_cruft(start);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Espen Jürgensen <espenjurgensen@gmail.com>
* Copyright (C) 2016 Espen Jürgensen <espenjurgensen@gmail.com>
*
* 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
@@ -36,6 +36,10 @@
#include <event2/event.h>
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
#endif
#include "http.h"
#include "logger.h"
#include "misc.h"
@@ -128,10 +132,10 @@ request_cb(struct evhttp_request *req, void *arg)
ctx->ret = 0;
if (ctx->headers)
headers_save(ctx->headers, evhttp_request_get_input_headers(req));
if (ctx->body)
evbuffer_add_buffer(ctx->body, evhttp_request_get_input_buffer(req));
if (ctx->input_headers)
headers_save(ctx->input_headers, evhttp_request_get_input_headers(req));
if (ctx->input_body)
evbuffer_add_buffer(ctx->input_body, evhttp_request_get_input_buffer(req));
event_base_loopbreak(ctx->evbase);
@@ -171,8 +175,8 @@ request_header_cb(struct evhttp_request *req, void *arg)
}
#endif
int
http_client_request(struct http_client_ctx *ctx)
static int
http_client_request_impl(struct http_client_ctx *ctx)
{
struct evhttp_connection *evcon;
struct evhttp_request *req;
@@ -269,6 +273,144 @@ http_client_request(struct http_client_ctx *ctx)
return ctx->ret;
}
#ifdef HAVE_LIBCURL
static size_t
curl_request_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
size_t realsize;
struct http_client_ctx *ctx;
int ret;
realsize = size * nmemb;
ctx = (struct http_client_ctx *)userdata;
if (!ctx->input_body)
return realsize;
ret = evbuffer_add(ctx->input_body, ptr, realsize);
if (ret < 0)
{
DPRINTF(E_LOG, L_HTTP, "Error adding reply from %s to input buffer\n", ctx->url);
return 0;
}
return realsize;
}
static int
https_client_request_impl(struct http_client_ctx *ctx)
{
CURL *curl;
CURLcode res;
struct curl_slist *headers;
struct onekeyval *okv;
char header[1024];
curl = curl_easy_init();
if (!curl)
{
DPRINTF(E_LOG, L_HTTP, "Error: Could not get curl handle\n");
return -1;
}
curl_easy_setopt(curl, CURLOPT_URL, ctx->url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "forked-daapd/" VERSION);
if (ctx->output_headers)
{
headers = NULL;
for (okv = ctx->output_headers->head; okv; okv = okv->next)
{
snprintf(header, sizeof(header), "%s: %s", okv->name, okv->value);
headers = curl_slist_append(headers, header);
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
}
if (ctx->output_body)
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ctx->output_body);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_CLIENT_TIMEOUT);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_request_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx);
/* Make request */
DPRINTF(E_INFO, L_HTTP, "Making request for %s\n", ctx->url);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
DPRINTF(E_LOG, L_HTTP, "Request to %s failed: %s\n", ctx->url, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return -1;
}
curl_easy_cleanup(curl);
return 0;
}
#endif /* HAVE_LIBCURL */
int
http_client_request(struct http_client_ctx *ctx)
{
if (strncmp(ctx->url, "http:", strlen("http:")) == 0)
return http_client_request_impl(ctx);
#ifdef HAVE_LIBCURL
if (strncmp(ctx->url, "https:", strlen("https:")) == 0)
return https_client_request_impl(ctx);
#endif
DPRINTF(E_LOG, L_HTTP, "Request for %s is not supported (not built with libcurl?)\n", ctx->url);
return -1;
}
char *
http_form_urlencode(struct keyval *kv)
{
struct evbuffer *evbuf;
struct onekeyval *okv;
char *body;
char *k;
char *v;
evbuf = evbuffer_new();
for (okv = kv->head; okv; okv = okv->next)
{
k = evhttp_encode_uri(okv->name);
if (!k)
continue;
v = evhttp_encode_uri(okv->value);
if (!v)
{
free(k);
continue;
}
evbuffer_add_printf(evbuf, "%s=%s", k, v);
if (okv->next)
evbuffer_add_printf(evbuf, "&");
free(k);
free(v);
}
evbuffer_add(evbuf, "\n", 1);
body = evbuffer_readln(evbuf, NULL, EVBUFFER_EOL_ANY);
evbuffer_free(evbuf);
DPRINTF(E_DBG, L_HTTP, "Parameters in request are: %s\n", body);
return body;
}
int
http_stream_setup(char **stream, const char *url)
{
@@ -296,7 +438,7 @@ http_stream_setup(char **stream, const char *url)
return -1;
ctx.url = url;
ctx.body = evbuf;
ctx.input_body = evbuf;
ret = http_client_request(&ctx);
if (ret < 0)
@@ -308,13 +450,13 @@ http_stream_setup(char **stream, const char *url)
}
// Pad with CRLF because evbuffer_readln() might not read the last line otherwise
evbuffer_add(ctx.body, "\r\n", 2);
evbuffer_add(ctx.input_body, "\r\n", 2);
/* Read the playlist until the first stream link is found, but give up if
* nothing is found in the first 10 lines
*/
n = 0;
while ((line = evbuffer_readln(ctx.body, NULL, EVBUFFER_EOL_ANY)) && (n < 10))
while ((line = evbuffer_readln(ctx.input_body, NULL, EVBUFFER_EOL_ANY)) && (n < 10))
{
n++;
if (strncasecmp(line, "http://", strlen("http://")) == 0)
@@ -328,7 +470,7 @@ http_stream_setup(char **stream, const char *url)
free(line);
}
evbuffer_free(ctx.body);
evbuffer_free(ctx.input_body);
if (n != -1)
{

View File

@@ -10,13 +10,18 @@
struct http_client_ctx
{
/* Destination URL, header and body of outgoing request body (headers and
* body is currently only supported for https)
*/
const char *url;
struct keyval *output_headers;
char *output_body;
/* A keyval/evbuf to store response headers and body.
* Can be set to NULL to ignore that part of the response.
*/
struct keyval *headers;
struct evbuffer *body;
struct keyval *input_headers;
struct evbuffer *input_body;
/* Cut the connection after the headers have been received
* Used for getting Shoutcast/ICY headers for old versions of libav/ffmpeg
@@ -47,15 +52,27 @@ struct http_icy_metadata
};
/* Generic HTTP client. No support for https.
/* Make a http(s) request. We use libcurl to make https requests. We could use
* libevent and avoid the dependency, but for SSL, libevent needs to be v2.1
* or better, which is still a bit too new to be in the major distros.
*
* @param ctx HTTP request params, see above
* @return 0 if successful, -1 if an error occurred
* @return 0 if successful, -1 if an error occurred (e.g. no libcurl)
*/
int
http_client_request(struct http_client_ctx *ctx);
/* Converts the keyval dictionary to a application/x-www-form-urlencoded string.
* The values will be uri_encoded. Example output: "key1=foo%20bar&key2=123".
*
* @param kv is the struct containing the parameters
* @return encoded string if succesful, NULL if an error occurred
*/
char *
http_form_urlencode(struct keyval *kv);
/* Returns a newly allocated string with the first stream in the m3u given in
* url. If url is not a m3u, the string will be a copy of url.
*

View File

@@ -64,6 +64,9 @@
#ifdef LASTFM
# include "lastfm.h"
#endif
#ifdef HAVE_SPOTIFY_H
# include "spotify.h"
#endif
/*
* HTTP client quirks by User-Agent, from mt-daapd
@@ -140,6 +143,7 @@ static struct evhttp *evhttpd;
static pthread_t tid_httpd;
static char *allow_origin;
static int httpd_port;
#ifdef HAVE_LIBEVENT2_OLD
struct stream_ctx *g_st;
@@ -198,6 +202,61 @@ scrobble_cb(void *arg)
}
#endif
static void
oauth_interface(struct evhttp_request *req, const char *uri)
{
struct evbuffer *evbuf;
struct evkeyvalq query;
const char *req_uri;
const char *ptr;
char redirect_uri[256];
int ret;
req_uri = evhttp_request_get_uri(req);
evbuf = evbuffer_new();
if (!evbuf)
{
DPRINTF(E_LOG, L_HTTPD, "Could not alloc evbuf for oauth\n");
return;
}
evbuffer_add_printf(evbuf, "<H1>forked-daapd oauth</H1>\n\n");
memset(&query, 0, sizeof(struct evkeyvalq));
ptr = strchr(req_uri, '?');
if (ptr)
{
ret = evhttp_parse_query_str(ptr + 1, &query);
if (ret < 0)
{
evbuffer_add_printf(evbuf, "OAuth error: Could not parse parameters in callback (%s)\n", req_uri);
httpd_send_reply(req, HTTP_OK, "OK", evbuf, 0);
evbuffer_free(evbuf);
return;
}
}
#ifdef HAVE_SPOTIFY_H
snprintf(redirect_uri, sizeof(redirect_uri), "http://forked-daapd.local:%d/oauth/spotify", httpd_port);
if (strncmp(uri, "/oauth/spotify", strlen("/oauth/spotify")) == 0)
spotify_oauth_callback(evbuf, &query, redirect_uri);
else
spotify_oauth_interface(evbuf, redirect_uri);
#endif
evbuffer_add_printf(evbuf, "<p><i>(sorry about this ugly interface)</i></p>\n");
evhttp_clear_headers(&query);
httpd_send_reply(req, HTTP_OK, "OK", evbuf, 0);
evbuffer_free(evbuf);
}
static void
stream_end_register(struct stream_ctx *st)
{
@@ -912,6 +971,12 @@ serve_file(struct evhttp_request *req, char *uri)
}
}
if (strncmp(uri, "/oauth", strlen("/oauth")) == 0)
{
oauth_interface(req, uri);
return;
}
ret = snprintf(path, sizeof(path), "%s%s", WEBFACE_ROOT, uri + 1); /* skip starting '/' */
if ((ret < 0) || (ret >= sizeof(path)))
{
@@ -1347,7 +1412,6 @@ int
httpd_init(void)
{
int v6enabled;
unsigned short port;
int ret;
httpd_exit = 0;
@@ -1428,7 +1492,7 @@ httpd_init(void)
}
v6enabled = cfg_getbool(cfg_getsec(cfg, "general"), "ipv6");
port = cfg_getint(cfg_getsec(cfg, "library"), "port");
httpd_port = cfg_getint(cfg_getsec(cfg, "library"), "port");
// For CORS headers
allow_origin = cfg_getstr(cfg_getsec(cfg, "general"), "allow_origin");
@@ -1442,20 +1506,20 @@ httpd_init(void)
if (v6enabled)
{
ret = evhttp_bind_socket(evhttpd, "::", port);
ret = evhttp_bind_socket(evhttpd, "::", httpd_port);
if (ret < 0)
{
DPRINTF(E_LOG, L_HTTPD, "Could not bind to port %d with IPv6, falling back to IPv4\n", port);
DPRINTF(E_LOG, L_HTTPD, "Could not bind to port %d with IPv6, falling back to IPv4\n", httpd_port);
v6enabled = 0;
}
}
if (!v6enabled)
{
ret = evhttp_bind_socket(evhttpd, "0.0.0.0", port);
ret = evhttp_bind_socket(evhttpd, "0.0.0.0", httpd_port);
if (ret < 0)
{
DPRINTF(E_FATAL, L_HTTPD, "Could not bind to port %d (forked-daapd already running?)\n", port);
DPRINTF(E_FATAL, L_HTTPD, "Could not bind to port %d (forked-daapd already running?)\n", httpd_port);
goto bind_fail;
}
}

View File

@@ -39,14 +39,7 @@
#include "lastfm.h"
#include "logger.h"
#include "misc.h"
struct https_client_ctx
{
const char *url;
const char *body;
struct evbuffer *data;
};
#include "http.h"
// LastFM becomes disabled if we get a scrobble, try initialising session,
// but can't (probably no session key in db because user does not use LastFM)
@@ -172,51 +165,6 @@ credentials_read(char *path, char **username, char **password)
return 0;
}
/* Converts parameters to a string in application/x-www-form-urlencoded format */
static int
body_print(char **body, struct keyval *kv)
{
struct evbuffer *evbuf;
struct onekeyval *okv;
char *k;
char *v;
evbuf = evbuffer_new();
for (okv = kv->head; okv; okv = okv->next)
{
k = evhttp_encode_uri(okv->name);
if (!k)
continue;
v = evhttp_encode_uri(okv->value);
if (!v)
{
free(k);
continue;
}
evbuffer_add(evbuf, k, strlen(k));
evbuffer_add(evbuf, "=", 1);
evbuffer_add(evbuf, v, strlen(v));
if (okv->next)
evbuffer_add(evbuf, "&", 1);
free(k);
free(v);
}
evbuffer_add(evbuf, "\n", 1);
*body = evbuffer_readln(evbuf, NULL, EVBUFFER_EOL_ANY);
evbuffer_free(evbuf);
DPRINTF(E_DBG, L_LASTFM, "Parameters in request are: %s\n", *body);
return 0;
}
/* Creates an md5 signature of the concatenated parameters and adds it to keyval */
static int
param_sign(struct keyval *kv)
@@ -288,28 +236,8 @@ mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */
/* --------------------------------- MAIN --------------------------------- */
static size_t
request_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
size_t realsize;
struct https_client_ctx *ctx;
int ret;
realsize = size * nmemb;
ctx = (struct https_client_ctx *)userdata;
ret = evbuffer_add(ctx->data, ptr, realsize);
if (ret < 0)
{
DPRINTF(E_LOG, L_LASTFM, "Error adding reply from LastFM to data buffer\n");
return 0;
}
return realsize;
}
static void
response_proces(struct https_client_ctx *ctx)
response_proces(struct http_client_ctx *ctx)
{
mxml_node_t *tree;
mxml_node_t *s_node;
@@ -319,9 +247,9 @@ response_proces(struct https_client_ctx *ctx)
char *sk;
// NULL-terminate the buffer
evbuffer_add(ctx->data, "", 1);
evbuffer_add(ctx->input_body, "", 1);
body = (char *)evbuffer_pullup(ctx->data, -1);
body = (char *)evbuffer_pullup(ctx->input_body, -1);
if (!body || (strlen(body) == 0))
{
DPRINTF(E_LOG, L_LASTFM, "Empty response\n");
@@ -380,59 +308,10 @@ response_proces(struct https_client_ctx *ctx)
mxmlDelete(tree);
}
// We use libcurl to make the request. We could use libevent and avoid the
// dependency, but for SSL, libevent needs to be v2.1 or better, which is still
// a bit too new to be in the major distros
static int
https_client_request(struct https_client_ctx *ctx)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (!curl)
{
DPRINTF(E_LOG, L_LASTFM, "Error: Could not get curl handle\n");
return -1;
}
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ctx->body);
curl_easy_setopt(curl, CURLOPT_URL, ctx->url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, request_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx);
ctx->data = evbuffer_new();
if (!ctx->data)
{
DPRINTF(E_LOG, L_LASTFM, "Could not create evbuffer for LastFM response\n");
curl_easy_cleanup(curl);
return -1;
}
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
DPRINTF(E_LOG, L_LASTFM, "Request to %s failed: %s\n", ctx->url, curl_easy_strerror(res));
curl_easy_cleanup(curl);
return -1;
}
response_proces(ctx);
evbuffer_free(ctx->data);
curl_easy_cleanup(curl);
return 0;
}
static int
request_post(char *method, struct keyval *kv, int auth)
{
struct https_client_ctx ctx;
char *body;
struct http_client_ctx ctx;
int ret;
ret = keyval_add(kv, "method", method);
@@ -453,18 +332,27 @@ request_post(char *method, struct keyval *kv, int auth)
return -1;
}
ret = body_print(&body, kv);
memset(&ctx, 0, sizeof(struct http_client_ctx));
ctx.output_body = http_form_urlencode(kv);
if (ret < 0)
{
DPRINTF(E_LOG, L_LASTFM, "Aborting request, body_print failed\n");
DPRINTF(E_LOG, L_LASTFM, "Aborting request, http_form_urlencode failed\n");
return -1;
}
memset(&ctx, 0, sizeof(struct https_client_ctx));
ctx.url = auth ? auth_url : api_url;
ctx.body = body;
ctx.input_body = evbuffer_new();
ret = https_client_request(&ctx);
ret = http_client_request(&ctx);
if (ret < 0)
goto out_free_ctx;
response_proces(&ctx);
out_free_ctx:
free(ctx.output_body);
evbuffer_free(ctx.input_body);
return ret;
}

View File

@@ -68,7 +68,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
#include "player.h"
#include "worker.h"
#ifdef LASTFM
#ifdef HAVE_LIBCURL
# include <curl/curl.h>
#endif
#ifdef HAVE_SPOTIFY_H
@@ -632,7 +632,7 @@ main(int argc, char **argv)
#endif
av_log_set_callback(logger_ffmpeg);
#ifdef LASTFM
#ifdef HAVE_LIBCURL
/* Initialize libcurl */
curl_global_init(CURL_GLOBAL_DEFAULT);
#endif
@@ -810,6 +810,9 @@ main(int argc, char **argv)
goto mdns_reg_fail;
}
/* Register this CNAME with mDNS for OAuth */
mdns_cname("forked-daapd.local");
#if defined(__linux__)
/* Set up signal fd */
sigfd = signalfd(-1, &sigs, SFD_NONBLOCK | SFD_CLOEXEC);
@@ -936,7 +939,7 @@ main(int argc, char **argv)
signal_block_fail:
gcrypt_init_fail:
#ifdef LASTFM
#ifdef HAVE_LIBCURL
curl_global_cleanup();
#endif
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13)

View File

@@ -37,6 +37,16 @@ mdns_deinit(void);
int
mdns_register(char *name, char *type, int port, char **txt);
/*
* Register a CNAME record, it will be an alias for hostname
* Call only from the main thread!
*
* @in name The CNAME alias, e.g. "forked-daapd.local"
* @return 0 on success, -1 on error
*/
int
mdns_cname(char *name);
/*
* Start a service browser, a callback will be made when the service changes state
* Call only from the main thread!

View File

@@ -33,6 +33,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <unistd.h>
#include <event2/event.h>
@@ -351,8 +352,15 @@ struct mdns_record_browser {
int port;
};
enum publish
{
MDNS_PUBLISH_SERVICE,
MDNS_PUBLISH_CNAME,
};
struct mdns_group_entry
{
enum publish publish;
char *name;
char *type;
int port;
@@ -622,13 +630,100 @@ entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_U
}
}
static void
_create_services(void)
static int
create_group_entry(struct mdns_group_entry *ge, int commit)
{
struct mdns_group_entry *pentry;
char hostname[HOST_NAME_MAX + 1];
char rdata[HOST_NAME_MAX + 6 + 1]; // Includes room for ".local" and 0-terminator
int count;
int i;
int ret;
DPRINTF(E_DBG, L_MDNS, "Creating service group\n");
if (!mdns_group)
{
mdns_group = avahi_entry_group_new(mdns_client, entry_group_callback, NULL);
if (!mdns_group)
{
DPRINTF(E_WARN, L_MDNS, "Could not create Avahi EntryGroup: %s\n", MDNSERR);
return -1;
}
}
if (ge->publish == MDNS_PUBLISH_SERVICE)
{
DPRINTF(E_DBG, L_MDNS, "Adding service %s/%s\n", ge->name, ge->type);
ret = avahi_entry_group_add_service_strlst(mdns_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0,
ge->name, ge->type,
NULL, NULL, ge->port, ge->txt);
if (ret < 0)
{
DPRINTF(E_LOG, L_MDNS, "Could not add mDNS service %s/%s: %s\n", ge->name, ge->type, avahi_strerror(ret));
return -1;
}
}
else if (ge->publish == MDNS_PUBLISH_CNAME)
{
DPRINTF(E_DBG, L_MDNS, "Adding CNAME record %s\n", ge->name);
ret = gethostname(hostname, HOST_NAME_MAX);
if (ret < 0)
{
DPRINTF(E_LOG, L_MDNS, "Could not add CNAME %s, gethostname failed\n", ge->name);
return -1;
}
// Note, gethostname does not guarantee 0-termination
ret = snprintf(rdata, sizeof(rdata), ".%s.local", hostname);
if (!(ret > 0 && ret < sizeof(rdata)))
{
DPRINTF(E_LOG, L_MDNS, "Could not add CNAME %s, hostname is invalid\n", ge->name);
return -1;
}
// Convert to dns string: .forked-daapd.local -> \12forked-daapd\6local
count = 0;
for (i = ret - 1; i >= 0; i--)
{
if (rdata[i] == '.')
{
rdata[i] = count;
count = 0;
}
else
count++;
}
// ret + 1 should be the string length of rdata incl. 0-terminator
ret = avahi_entry_group_add_record(mdns_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
AVAHI_PUBLISH_USE_MULTICAST | AVAHI_PUBLISH_ALLOW_MULTIPLE,
ge->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_CNAME,
AVAHI_DEFAULT_TTL, rdata, ret + 1);
if (ret < 0)
{
DPRINTF(E_LOG, L_MDNS, "Could not add CNAME record %s: %s\n", ge->name, avahi_strerror(ret));
return -1;
}
}
if (!commit)
return 0;
ret = avahi_entry_group_commit(mdns_group);
if (ret < 0)
{
DPRINTF(E_LOG, L_MDNS, "Could not commit mDNS services: %s\n", MDNSERR);
return -1;
}
return 0;
}
static void
create_all_group_entries(void)
{
struct mdns_group_entry *ge;
int ret;
if (!group_entries)
{
@@ -636,36 +731,21 @@ _create_services(void)
return;
}
if (mdns_group == NULL)
{
mdns_group = avahi_entry_group_new(mdns_client, entry_group_callback, NULL);
if (!mdns_group)
{
DPRINTF(E_WARN, L_MDNS, "Could not create Avahi EntryGroup: %s\n", MDNSERR);
return;
}
}
if (mdns_group)
avahi_entry_group_reset(mdns_group);
pentry = group_entries;
while (pentry)
{
DPRINTF(E_DBG, L_MDNS, "Re-registering %s/%s\n", pentry->name, pentry->type);
DPRINTF(E_INFO, L_MDNS, "Re-registering mDNS groups (services and records)\n");
ret = avahi_entry_group_add_service_strlst(mdns_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0,
pentry->name, pentry->type,
NULL, NULL, pentry->port, pentry->txt);
if (ret < 0)
{
DPRINTF(E_WARN, L_MDNS, "Could not add mDNS services: %s\n", avahi_strerror(ret));
return;
}
for (ge = group_entries; ge; ge = ge->next)
{
create_group_entry(ge, 0);
if (!mdns_group)
return;
}
pentry = pentry->next;
}
ret = avahi_entry_group_commit(mdns_group);
if (ret < 0)
DPRINTF(E_WARN, L_MDNS, "Could not commit mDNS services: %s\n", MDNSERR);
ret = avahi_entry_group_commit(mdns_group);
if (ret < 0)
DPRINTF(E_WARN, L_MDNS, "Could not commit mDNS services: %s\n", MDNSERR);
}
static void
@@ -680,7 +760,7 @@ client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void *
case AVAHI_CLIENT_S_RUNNING:
DPRINTF(E_LOG, L_MDNS, "Avahi state change: Client running\n");
if (!mdns_group)
_create_services();
create_all_group_entries();
for (mb = browser_list; mb; mb = mb->next)
{
@@ -808,8 +888,6 @@ mdns_register(char *name, char *type, int port, char **txt)
AvahiStringList *txt_sl;
int i;
DPRINTF(E_DBG, L_MDNS, "Adding mDNS service %s/%s\n", name, type);
ge = calloc(1, sizeof(struct mdns_group_entry));
if (!ge)
{
@@ -817,6 +895,7 @@ mdns_register(char *name, char *type, int port, char **txt)
return -1;
}
ge->publish = MDNS_PUBLISH_SERVICE;
ge->name = strdup(name);
ge->type = strdup(type);
ge->port = port;
@@ -837,14 +916,30 @@ mdns_register(char *name, char *type, int port, char **txt)
ge->next = group_entries;
group_entries = ge;
if (mdns_group)
create_all_group_entries(); // TODO why is this required?
return 0;
}
int
mdns_cname(char *name)
{
struct mdns_group_entry *ge;
ge = calloc(1, sizeof(struct mdns_group_entry));
if (!ge)
{
DPRINTF(E_DBG, L_MDNS, "Resetting mDNS group\n");
avahi_entry_group_reset(mdns_group);
DPRINTF(E_LOG, L_MDNS, "Out of memory for mDNS CNAME\n");
return -1;
}
DPRINTF(E_DBG, L_MDNS, "Creating service group\n");
_create_services();
ge->publish = MDNS_PUBLISH_CNAME;
ge->name = strdup(name);
ge->next = group_entries;
group_entries = ge;
create_all_group_entries();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/http.h>
int
spotify_playback_setup(const char *path);
@@ -32,6 +33,12 @@ spotify_audio_get(struct evbuffer *evbuf, int wanted);
int
spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h);
void
spotify_oauth_interface(struct evbuffer *evbuf, const char *redirect_uri);
void
spotify_oauth_callback(struct evbuffer *evbuf, struct evkeyvalq *param, const char *redirect_uri);
void
spotify_login(char *path);