Merge branch: libevent compability improvements

This commit is contained in:
ejurgensen 2014-06-02 21:59:50 +02:00
commit 30aa93479d
22 changed files with 2346 additions and 161 deletions

12
INSTALL
View File

@ -24,14 +24,16 @@ sudo apt-get install \
antlr3 libantlr3c-dev libconfuse-dev libunistring-dev libsqlite3-dev \
libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libasound2-dev \
libmxml-dev libgcrypt11-dev libavahi-client-dev libavl-dev zlib1g-dev \
libevent1-dev
libevent-dev
Depending on the version of libav/ffmpeg in your distribution you may also need
libavresample-dev.
Note that libevent1-dev is not in the Debian repository, but you can get the
packages in the Ubuntu repository. You can also use libevent 2, but it must be
version 2.1.4 or newer.
Note that while forked-daapd will work with versions of libevent between 2.0.0
and 2.1.3, it is recommended to use either libevent 1 or 2.1.4+. Otherwise you
will not have support for Shoutcast metadata and simultaneous streaming to
multiple clients. Libevent 1 is not in the Debian repository, but you can get
the packages in the Ubuntu repository.
Then run the following:
@ -86,7 +88,7 @@ Libraries:
from <http://libav.org/releases/>
- libconfuse
from <http://www.nongnu.org/confuse/>
- libevent 1.4 or 2.1.4+
- libevent 1.4+ (best with version 1.4 or 2.1.4+)
from <http://libevent.org/>
- libavl 0.3.5
from <http://ftp.debian.org/debian/pool/main/liba/libavl>

View File

@ -160,19 +160,28 @@ fi
PKG_CHECK_MODULES(MINIXML, [ mxml ])
PKG_CHECK_MODULES(LIBEVENT, [ libevent >= 2.1.4 ],
AC_DEFINE(HAVE_LIBEVENT2, 1, [Define to 1 if you have libevent >= 2.1.4]),
PKG_CHECK_MODULES(LIBEVENT, [ libevent >= 2 ],
AC_DEFINE(HAVE_LIBEVENT2, 1, [Define to 1 if you have libevent 2]),
try_libevent1=true;
)
AM_CONDITIONAL(COND_LIBEVENT1, false)
AM_CONDITIONAL(COND_LIBEVENT20, false)
AM_CONDITIONAL(COND_LIBEVENT21, false)
if test x$try_libevent1 = xtrue; then
AC_CHECK_HEADER(event.h, , AC_MSG_ERROR([event.h not found]))
AC_CHECK_LIB([event_core], [event_init], [LIBEVENT_LIBS="-levent_core"], AC_MSG_ERROR([libevent not found]))
AC_CHECK_LIB([event_core], [event_new], AC_MSG_ERROR([found libevent 2 but version should be at least 2.1.4]))
AC_SUBST(LIBEVENT_LIBS)
AM_CONDITIONAL(COND_LIBEVENT2, false)
AM_CONDITIONAL(COND_LIBEVENT1, true)
else
AM_CONDITIONAL(COND_LIBEVENT2, true)
PKG_CHECK_EXISTS([ libevent >= 2.1 ],
AM_CONDITIONAL(COND_LIBEVENT21, true),
AM_CONDITIONAL(COND_LIBEVENT20, true)
)
PKG_CHECK_EXISTS([ libevent >= 2.1.4 ], ,
AC_DEFINE(HAVE_LIBEVENT2_OLD, 1, [Define to 1 if you have libevent 2 (<2.1.4)])
)
fi
AC_CHECK_HEADER(avl.h, , AC_MSG_ERROR([avl.h not found]))

View File

@ -31,13 +31,21 @@ else
FFURL_SRC=ffmpeg_url_evbuffer.c ffmpeg_url_evbuffer.h
endif
if COND_LIBEVENT2
RTSP_SRC=evrtsp/rtsp.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
else
EVHTTP_SRC=evhttp/http.c evhttp/evhttp.h evhttp/http-internal.h evhttp/log.h
if COND_LIBEVENT1
EVHTTP_SRC=evhttp/http.c evhttp/evhttp.h evhttp/evhttp_compat.c evhttp/evhttp_compat.h evhttp/http-internal.h evhttp/log.h
RTSP_SRC=evrtsp/rtsp-libevent1.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
endif
if COND_LIBEVENT20
EVHTTP_SRC=
RTSP_SRC=evrtsp/rtsp-libevent20.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
endif
if COND_LIBEVENT21
EVHTTP_SRC=
RTSP_SRC=evrtsp/rtsp.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
endif
GPERF_FILES = \
daap_query.gperf \
rsp_query.gperf \

View File

@ -1580,7 +1580,7 @@ db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi)
ret = db_blocking_step(qp->stmt);
if (ret == SQLITE_DONE)
{
DPRINTF(E_INFO, L_DB, "End of query results\n");
DPRINTF(E_DBG, L_DB, "End of query results\n");
dbmfi->id = NULL;
return 0;
}
@ -1636,7 +1636,7 @@ db_query_fetch_pl(struct query_params *qp, struct db_playlist_info *dbpli)
ret = db_blocking_step(qp->stmt);
if (ret == SQLITE_DONE)
{
DPRINTF(E_INFO, L_DB, "End of query results\n");
DPRINTF(E_DBG, L_DB, "End of query results\n");
dbpli->id = NULL;
return 0;
}
@ -1716,7 +1716,7 @@ db_query_fetch_group(struct query_params *qp, struct db_group_info *dbgri)
ret = db_blocking_step(qp->stmt);
if (ret == SQLITE_DONE)
{
DPRINTF(E_INFO, L_DB, "End of query results\n");
DPRINTF(E_DBG, L_DB, "End of query results\n");
return 1;
}
else if (ret != SQLITE_ROW)
@ -1765,7 +1765,7 @@ db_query_fetch_string(struct query_params *qp, char **string)
ret = db_blocking_step(qp->stmt);
if (ret == SQLITE_DONE)
{
DPRINTF(E_INFO, L_DB, "End of query results\n");
DPRINTF(E_DBG, L_DB, "End of query results\n");
*string = NULL;
return 0;
}
@ -1802,7 +1802,7 @@ db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortst
ret = db_blocking_step(qp->stmt);
if (ret == SQLITE_DONE)
{
DPRINTF(E_INFO, L_DB, "End of query results\n");
DPRINTF(E_DBG, L_DB, "End of query results\n");
*string = NULL;
return 0;
}
@ -1997,7 +1997,7 @@ db_file_path_byid(int id)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
@ -2046,7 +2046,7 @@ db_file_id_byquery(char *query)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
@ -2219,7 +2219,7 @@ db_file_stamp_bypath(char *path, time_t *stamp, int *id)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
@ -2283,7 +2283,7 @@ db_file_fetch_byquery(char *query)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
@ -2815,7 +2815,7 @@ db_pl_id_bypath(char *path, int *id)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
@ -2878,7 +2878,7 @@ db_pl_fetch_byquery(char *query)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
@ -3432,7 +3432,7 @@ db_group_type_byid(int id)
if (ret != SQLITE_ROW)
{
if (ret == SQLITE_DONE)
DPRINTF(E_INFO, L_DB, "No results\n");
DPRINTF(E_DBG, L_DB, "No results\n");
else
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));

View File

@ -4,7 +4,7 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
#endif

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
*
* 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
*/
#include <stdio.h>
#include "evhttp_compat.h"
struct evhttp_connection *
evhttp_connection_base_new(struct event_base *base, void *ignore, const char *address, unsigned short port)
{
struct evhttp_connection *evcon;
if (!base || !address || !port)
return NULL;
evcon = evhttp_connection_new(address, port);
if (evcon)
evhttp_connection_set_base(evcon, base);
return evcon;
}
void
evhttp_request_set_header_cb(struct evhttp_request *req, int (*cb)(struct evhttp_request *, void *))
{
req->header_cb = cb;
}

View File

@ -0,0 +1,27 @@
#include "evhttp.h"
/* This file should only be included if using libevent 1
*
* The following adds libevent 2 evhttp functions to libevent 1, so we avoid
* the need of having many HAVE_LIBEVENT2 conditions inside the code
*/
#define evhttp_request_get_response_code(x) x->response_code
#define evhttp_request_get_input_headers(x) x->input_headers
#define evhttp_request_get_output_headers(x) x->output_headers
#define evhttp_request_get_input_buffer(x) x->input_buffer
#define evhttp_request_get_output_buffer(x) x->output_buffer
#define evhttp_request_get_host(x) x->remote_host
#define evhttp_request_get_uri evhttp_request_uri
struct evhttp_connection *
evhttp_connection_base_new(struct event_base *base, void *ignore, const char *address, unsigned short port);
void
evhttp_request_set_header_cb(struct evhttp_request *req, int (*cb)(struct evhttp_request *, void *));

1808
src/evrtsp/rtsp-libevent20.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -525,7 +525,11 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
else if (type & F_SCAN_TYPE_URL)
{
mfi->data_kind = 1; /* url/stream */
#if LIBAVFORMAT_VERSION_MAJOR >= 56 || (LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 13)
ret = scan_metadata_ffmpeg(path, mfi);
#else
ret = scan_metadata_icy(path, mfi);
#endif
}
else if (type & F_SCAN_TYPE_SPOTIFY)
{

View File

@ -32,6 +32,7 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include "logger.h"
#include "filescanner.h"
@ -313,10 +314,85 @@ extract_metadata(struct media_file_info *mfi, AVFormatContext *ctx, AVStream *au
return mdcount;
}
/* Extracts ICY metadata (requires libav 10: libavformat 55.13) */
static void
extract_metadata_icy(struct media_file_info *mfi, AVFormatContext *ctx)
{
uint8_t *icy_meta;
char *icy_token;
char *icy_str;
char *ptr;
icy_meta = NULL;
// TODO Also get icy_metadata_packet to show current track
av_opt_get(ctx, "icy_metadata_headers", AV_OPT_SEARCH_CHILDREN, &icy_meta);
if (!icy_meta)
return;
icy_str = strdup((char *)icy_meta);
icy_token = strtok(icy_str, "\r\n");
while (icy_token != NULL)
{
ptr = strchr(icy_token, ':');
if (!ptr || (strlen(ptr) < 4))
{
icy_token = strtok(NULL, "\r\n");
continue;
}
ptr++;
if (ptr[0] == ' ')
ptr++;
if (strstr(icy_token, "icy-name"))
{
DPRINTF(E_DBG, L_SCAN, "Libav/ffmpeg found ICY metadata, name is '%s'\n", ptr);
if (mfi->title)
free(mfi->title);
if (mfi->artist)
free(mfi->artist);
if (mfi->album_artist)
free(mfi->album_artist);
mfi->title = strdup(ptr);
mfi->artist = strdup(ptr);
mfi->album_artist = strdup(ptr);
}
if (strstr(icy_token, "icy-description"))
{
DPRINTF(E_DBG, L_SCAN, "Libav/ffmpeg found ICY metadata, description is '%s'\n", ptr);
if (mfi->album)
free(mfi->album);
mfi->album = strdup(ptr);
}
if (strstr(icy_token, "icy-genre"))
{
DPRINTF(E_DBG, L_SCAN, "Libav/ffmpeg found ICY metadata, genre is '%s'\n", ptr);
if (mfi->genre)
free(mfi->genre);
mfi->genre = strdup(ptr);
}
icy_token = strtok(NULL, "\r\n");
}
av_free(icy_meta);
free(icy_str);
}
int
scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
{
AVFormatContext *ctx;
AVDictionary *options;
const struct metadata_map *extra_md_map;
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
enum AVCodecID codec_id;
@ -334,9 +410,13 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
int ret;
ctx = NULL;
options = NULL;
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3)
ret = avformat_open_input(&ctx, file, NULL, NULL);
if (mfi->data_kind == 1)
av_dict_set(&options, "icy", "1", 0);
ret = avformat_open_input(&ctx, file, NULL, &options);
#else
ret = av_open_input_file(&ctx, file, NULL, 0, NULL);
#endif
@ -462,6 +542,10 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
DPRINTF(E_DBG, L_SCAN, "Duration %d ms, bitrate %d kbps\n", mfi->song_length, mfi->bitrate);
/* Try to extract ICY metadata if url/stream */
if (mfi->data_kind == 1)
extract_metadata_icy(mfi, ctx);
/* Get some more information on the audio stream */
if (audio_stream)
{

View File

@ -1,9 +1,6 @@
/*
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
*
* Rewritten from mt-daapd code:
* Copyright (C) 2003 Ron Pedde (ron@pedde.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
* the Free Software Foundation; either version 2 of the License, or
@ -37,16 +34,17 @@
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <netinet/in.h>
#endif
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
#if defined HAVE_LIBEVENT2
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
# include "evhttp/evhttp_compat.h"
#endif
#include <libavformat/avformat.h>
@ -71,15 +69,16 @@ struct icy_ctx
char hostname[PATH_MAX];
char path[PATH_MAX];
int port;
char *icy_name;
char *icy_description;
char *icy_genre;
pthread_mutex_t lck;
pthread_cond_t cond;
};
static void
free_icy(struct icy_ctx *ctx)
{
if (ctx)
free(ctx);
}
#ifndef HAVE_LIBEVENT2
static int
resolve_address(char *hostname, char *s, size_t maxlen)
{
@ -102,62 +101,81 @@ resolve_address(char *hostname, char *s, size_t maxlen)
default:
strncpy(s, "Unknown AF", maxlen);
freeaddrinfo(result);
return -1;
}
freeaddrinfo(result);
return 0;
}
#endif
#ifndef HAVE_LIBEVENT2_OLD
static void
scan_icy_request_cb(struct evhttp_request *req, void *arg)
{
DPRINTF(E_DBG, L_SCAN, "ICY metadata request completed\n");
struct icy_ctx *ctx;
ctx = (struct icy_ctx *)arg;
pthread_mutex_lock(&ctx->lck);
DPRINTF(E_DBG, L_SCAN, "ICY metadata request: Signal callback\n");
status = ICY_DONE;
return;
pthread_cond_signal(&ctx->cond);
pthread_mutex_unlock(&ctx->lck);
}
/* Will always return -1 to make evhttp close the connection - we only need the http headers */
static int
scan_icy_header_cb(struct evhttp_request *req, void *arg)
{
struct media_file_info *mfi;
struct icy_ctx *ctx;
struct evkeyvalq *headers;
const char *ptr;
mfi = (struct media_file_info *)arg;
ctx = (struct icy_ctx *)arg;
if ( (ptr = evhttp_find_header(req->input_headers, "icy-name")) )
DPRINTF(E_DBG, L_SCAN, "ICY metadata request: Headers received\n");
headers = evhttp_request_get_input_headers(req);
if ( (ptr = evhttp_find_header(headers, "icy-name")) )
{
mfi->title = strdup(ptr);
mfi->artist = strdup(ptr);
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, name (title/artist) is %s\n", mfi->title);
ctx->icy_name = strdup(ptr);
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, name is %s\n", ctx->icy_name);
}
if ( (ptr = evhttp_find_header(req->input_headers, "icy-description")) )
if ( (ptr = evhttp_find_header(headers, "icy-description")) )
{
mfi->album = strdup(ptr);
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, description (album) is %s\n", mfi->album);
ctx->icy_description = strdup(ptr);
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, description is %s\n", ctx->icy_description);
}
if ( (ptr = evhttp_find_header(req->input_headers, "icy-genre")) )
if ( (ptr = evhttp_find_header(headers, "icy-genre")) )
{
mfi->genre = strdup(ptr);
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, genre is %s\n", mfi->genre);
ctx->icy_genre = strdup(ptr);
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, genre is %s\n", ctx->icy_genre);
}
status = ICY_DONE;
return -1;
}
#endif
int
scan_metadata_icy(char *url, struct media_file_info *mfi)
{
struct evhttp_connection *evcon;
struct evhttp_request *req;
struct icy_ctx *ctx;
struct evhttp_connection *evcon;
#ifndef HAVE_LIBEVENT2_OLD
struct evhttp_request *req;
struct evkeyvalq *headers;
char s[PATH_MAX];
#endif
time_t start;
time_t end;
int ret;
int i;
status = ICY_INIT;
start = time(NULL);
/* We can set this straight away */
mfi->url = strdup(url);
@ -167,10 +185,13 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
{
DPRINTF(E_LOG, L_SCAN, "Out of memory for ICY metadata context\n");
goto no_icy;
return -1;
}
memset(ctx, 0, sizeof(struct icy_ctx));
pthread_mutex_init(&ctx->lck, NULL);
pthread_cond_init(&ctx->cond, NULL);
ctx->url = url;
/* TODO https */
@ -185,6 +206,21 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
if (ctx->port < 0)
ctx->port = 80;
if (strlen(ctx->path) == 0)
{
ctx->path[0] = '/';
ctx->path[1] = '\0';
}
#ifdef HAVE_LIBEVENT2
evcon = evhttp_connection_base_new(evbase_main, NULL, ctx->hostname, (unsigned short)ctx->port);
if (!evcon)
{
DPRINTF(E_LOG, L_SCAN, "Could not create connection to %s\n", ctx->hostname);
goto no_icy;
}
#else
/* Resolve IP address */
ret = resolve_address(ctx->hostname, ctx->address, sizeof(ctx->address));
if (ret < 0)
@ -205,37 +241,45 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
goto no_icy;
}
evhttp_connection_set_base(evcon, evbase_main);
#endif
#ifdef HAVE_LIBEVENT2_OLD
DPRINTF(E_LOG, L_SCAN, "Skipping Shoutcast metadata request for %s (requires libevent>=2.1.4 or libav 10)\n", ctx->hostname);
#else
evhttp_connection_set_timeout(evcon, ICY_TIMEOUT);
/* Set up request */
req = evhttp_request_new(scan_icy_request_cb, mfi);
req = evhttp_request_new(scan_icy_request_cb, ctx);
if (!req)
{
DPRINTF(E_LOG, L_SCAN, "Could not create request to %s\n", ctx->hostname);
evhttp_connection_free(evcon);
goto no_icy;
}
req->header_cb = scan_icy_header_cb;
evhttp_add_header(req->output_headers, "Host", ctx->hostname);
evhttp_add_header(req->output_headers, "Icy-MetaData", "1");
evhttp_request_set_header_cb(req, scan_icy_header_cb);
headers = evhttp_request_get_output_headers(req);
snprintf(s, PATH_MAX, "%s:%d", ctx->hostname, ctx->port);
evhttp_add_header(headers, "Host", s);
evhttp_add_header(headers, "Icy-MetaData", "1");
/* Make request */
DPRINTF(E_INFO, L_SCAN, "Making request to %s asking for ICY (Shoutcast) metadata\n", ctx->hostname);
status = ICY_WAITING;
ret = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, ctx->path);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Could not make request to %s\n", ctx->hostname);
DPRINTF(E_LOG, L_SCAN, "Error making request to %s\n", ctx->hostname);
status = ICY_DONE;
evhttp_connection_free(evcon);
goto no_icy;
}
DPRINTF(E_INFO, L_SCAN, "Making request to %s asking for ICY (Shoutcast) metadata\n", url);
#endif
/* Can't count on server support for ICY metadata, so
* while waiting for a reply make a parallel call to scan_metadata_ffmpeg.
* This call will also determine final return value.
*/
no_icy:
ret = scan_metadata_ffmpeg(url, mfi);
@ -247,13 +291,58 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
mfi->description = strdup("MPEG audio file");
}
/* Wait till ICY request completes or we reach timeout */
for (i = 0; (status == ICY_WAITING) && (i <= ICY_TIMEOUT); i++)
sleep(1);
/* Wait for ICY request to complete or timeout */
pthread_mutex_lock(&ctx->lck);
free_icy(ctx);
if (status == ICY_WAITING)
pthread_cond_wait(&ctx->cond, &ctx->lck);
DPRINTF(E_DBG, L_SCAN, "scan_metadata_icy exiting with status %d after waiting %d sec\n", status, i);
pthread_mutex_unlock(&ctx->lck);
/* Copy result to mfi */
if (ctx->icy_name)
{
if (mfi->title)
free(mfi->title);
if (mfi->artist)
free(mfi->artist);
if (mfi->album_artist)
free(mfi->album_artist);
mfi->title = strdup(ctx->icy_name);
mfi->artist = strdup(ctx->icy_name);
mfi->album_artist = strdup(ctx->icy_name);
free(ctx->icy_name);
}
if (ctx->icy_description)
{
if (mfi->album)
free(mfi->album);
mfi->album = ctx->icy_description;
}
if (ctx->icy_genre)
{
if (mfi->genre)
free(mfi->genre);
mfi->genre = ctx->icy_genre;
}
/* Clean up */
if (evcon)
evhttp_connection_free(evcon);
pthread_cond_destroy(&ctx->cond);
pthread_mutex_destroy(&ctx->lck);
free(ctx);
end = time(NULL);
DPRINTF(E_DBG, L_SCAN, "ICY metadata scan of %s completed in %.f sec\n", url, difftime(end, start));
return 1;
}

View File

@ -38,7 +38,7 @@
#include <plist/plist.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
#endif

View File

@ -53,7 +53,6 @@
#include "httpd_dacp.h"
#include "transcode.h"
/*
* HTTP client quirks by User-Agent, from mt-daapd
*
@ -123,12 +122,19 @@ static struct event exitev;
static struct evhttp *evhttpd;
static pthread_t tid_httpd;
#ifdef HAVE_LIBEVENT2_OLD
struct stream_ctx *g_st;
#endif
static void
stream_end(struct stream_ctx *st, int failed)
{
if (st->req->evcon)
evhttp_connection_set_closecb(st->req->evcon, NULL, NULL);
struct evhttp_connection *evcon;
evcon = evhttp_request_get_connection(st->req);
if (evcon)
evhttp_connection_set_closecb(evcon, NULL, NULL);
if (!failed)
evhttp_send_reply_end(st->req);
@ -143,6 +149,11 @@ stream_end(struct stream_ctx *st, int failed)
close(st->fd);
}
#ifdef HAVE_LIBEVENT2_OLD
if (g_st == st)
g_st = NULL;
#endif
free(st);
}
@ -177,6 +188,15 @@ stream_chunk_resched_cb(struct evhttp_connection *evcon, void *arg)
}
}
#ifdef HAVE_LIBEVENT2_OLD
static void
stream_chunk_resched_cb_wrapper(struct bufferevent *bufev, void *arg)
{
if (g_st)
stream_chunk_resched_cb(NULL, g_st);
}
#endif
static void
stream_chunk_xcode_cb(int fd, short event, void *arg)
{
@ -224,7 +244,17 @@ stream_chunk_xcode_cb(int fd, short event, void *arg)
else
ret = xcoded;
#ifdef HAVE_LIBEVENT2_OLD
evhttp_send_reply_chunk(st->req, st->evbuf);
struct evhttp_connection *evcon = evhttp_request_get_connection(st->req);
struct bufferevent *bufev = evhttp_connection_get_bufferevent(evcon);
g_st = st; // Can't pass st to callback so use global - limits libevent 2.0 to a single stream
bufev->writecb = stream_chunk_resched_cb_wrapper;
#else
evhttp_send_reply_chunk_with_cb(st->req, st->evbuf, stream_chunk_resched_cb, st);
#endif
st->offset += ret;
@ -280,7 +310,17 @@ stream_chunk_raw_cb(int fd, short event, void *arg)
evbuffer_add(st->evbuf, st->buf, ret);
#ifdef HAVE_LIBEVENT2_OLD
evhttp_send_reply_chunk(st->req, st->evbuf);
struct evhttp_connection *evcon = evhttp_request_get_connection(st->req);
struct bufferevent *bufev = evhttp_connection_get_bufferevent(evcon);
g_st = st; // Can't pass st to callback so use global - limits libevent 2.0 to a single stream
bufev->writecb = stream_chunk_resched_cb_wrapper;
#else
evhttp_send_reply_chunk_with_cb(st->req, st->evbuf, stream_chunk_resched_cb, st);
#endif
st->offset += ret;
@ -312,6 +352,9 @@ httpd_stream_file(struct evhttp_request *req, int id)
void (*stream_cb)(int fd, short event, void *arg);
struct stat sb;
struct timeval tv;
struct evhttp_connection *evcon;
struct evkeyvalq *input_headers;
struct evkeyvalq *output_headers;
const char *param;
const char *param_end;
char buf[64];
@ -323,7 +366,10 @@ httpd_stream_file(struct evhttp_request *req, int id)
offset = 0;
end_offset = 0;
param = evhttp_find_header(req->input_headers, "Range");
input_headers = evhttp_request_get_input_headers(req);
param = evhttp_find_header(input_headers, "Range");
if (param)
{
DPRINTF(E_DBG, L_HTTPD, "Found Range header: %s\n", param);
@ -385,7 +431,9 @@ httpd_stream_file(struct evhttp_request *req, int id)
memset(st, 0, sizeof(struct stream_ctx));
st->fd = -1;
transcode = transcode_needed(req->input_headers, mfi->codectype);
transcode = transcode_needed(input_headers, mfi->codectype);
output_headers = evhttp_request_get_output_headers(req);
if (transcode)
{
@ -403,8 +451,8 @@ httpd_stream_file(struct evhttp_request *req, int id)
goto out_free_st;
}
if (!evhttp_find_header(req->output_headers, "Content-Type"))
evhttp_add_header(req->output_headers, "Content-Type", "audio/wav");
if (!evhttp_find_header(output_headers, "Content-Type"))
evhttp_add_header(output_headers, "Content-Type", "audio/wav");
}
else
{
@ -468,21 +516,21 @@ httpd_stream_file(struct evhttp_request *req, int id)
DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
else
{
evhttp_remove_header(req->output_headers, "Content-Type");
evhttp_add_header(req->output_headers, "Content-Type", buf);
evhttp_remove_header(output_headers, "Content-Type");
evhttp_add_header(output_headers, "Content-Type", buf);
}
}
/* If no Content-Type has been set and we're streaming audio, add a proper
* Content-Type for the file we're streaming. Remember DAAP streams audio
* with application/x-dmap-tagged as the Content-Type (ugh!).
*/
else if (!evhttp_find_header(req->output_headers, "Content-Type") && mfi->type)
else if (!evhttp_find_header(output_headers, "Content-Type") && mfi->type)
{
ret = snprintf(buf, sizeof(buf), "audio/%s", mfi->type);
if ((ret < 0) || (ret >= sizeof(buf)))
DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
else
evhttp_add_header(req->output_headers, "Content-Type", buf);
evhttp_add_header(output_headers, "Content-Type", buf);
}
}
@ -491,7 +539,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
{
DPRINTF(E_LOG, L_HTTPD, "Could not allocate an evbuffer for streaming\n");
evhttp_clear_headers(req->output_headers);
evhttp_clear_headers(output_headers);
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
goto out_cleanup;
@ -502,7 +550,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
{
DPRINTF(E_LOG, L_HTTPD, "Could not expand evbuffer for streaming\n");
evhttp_clear_headers(req->output_headers);
evhttp_clear_headers(output_headers);
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
goto out_cleanup;
@ -516,7 +564,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
{
DPRINTF(E_LOG, L_HTTPD, "Could not add one-shot event for streaming\n");
evhttp_clear_headers(req->output_headers);
evhttp_clear_headers(output_headers);
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
goto out_cleanup;
@ -539,7 +587,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
if ((ret < 0) || (ret >= sizeof(buf)))
DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
else
evhttp_add_header(req->output_headers, "Content-Length", buf);
evhttp_add_header(output_headers, "Content-Length", buf);
}
evhttp_send_reply_start(req, HTTP_OK, "OK");
@ -558,13 +606,13 @@ httpd_stream_file(struct evhttp_request *req, int id)
if ((ret < 0) || (ret >= sizeof(buf)))
DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
else
evhttp_add_header(req->output_headers, "Content-Range", buf);
evhttp_add_header(output_headers, "Content-Range", buf);
ret = snprintf(buf, sizeof(buf), "%" PRIi64, ((end_offset) ? end_offset + 1 : (int64_t)st->size) - offset);
if ((ret < 0) || (ret >= sizeof(buf)))
DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
else
evhttp_add_header(req->output_headers, "Content-Length", buf);
evhttp_add_header(output_headers, "Content-Length", buf);
evhttp_send_reply_start(req, 206, "Partial Content");
}
@ -579,7 +627,9 @@ httpd_stream_file(struct evhttp_request *req, int id)
}
#endif
evhttp_connection_set_closecb(req->evcon, stream_fail_cb, st);
evcon = evhttp_request_get_connection(req);
evhttp_connection_set_closecb(evcon, stream_fail_cb, st);
DPRINTF(E_INFO, L_HTTPD, "Kicking off streaming for %s\n", mfi->path);
@ -609,6 +659,7 @@ httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struc
unsigned char outbuf[128 * 1024];
z_stream strm;
struct evbuffer *gzbuf;
struct evkeyvalq *headers;
const char *param;
int flush;
int zret;
@ -621,7 +672,9 @@ httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struc
goto no_gzip;
}
param = evhttp_find_header(req->input_headers, "Accept-Encoding");
headers = evhttp_request_get_input_headers(req);
param = evhttp_find_header(headers, "Accept-Encoding");
if (!param)
{
DPRINTF(E_DBG, L_HTTPD, "Not gzipping; no Accept-Encoding header\n");
@ -702,7 +755,9 @@ httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struc
deflateEnd(&strm);
evhttp_add_header(req->output_headers, "Content-Encoding", "gzip");
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "Content-Encoding", "gzip");
evhttp_send_reply(req, code, reason, gzbuf);
evbuffer_free(gzbuf);
@ -731,6 +786,7 @@ path_is_legal(char *path)
static void
redirect_to_index(struct evhttp_request *req, char *uri)
{
struct evkeyvalq *headers;
char buf[256];
int slashed;
int ret;
@ -746,7 +802,9 @@ redirect_to_index(struct evhttp_request *req, char *uri)
return;
}
evhttp_add_header(req->output_headers, "Location", buf);
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "Location", buf);
evhttp_send_reply(req, HTTP_MOVETEMP, "Moved", NULL);
}
@ -754,12 +812,14 @@ redirect_to_index(struct evhttp_request *req, char *uri)
static void
serve_file(struct evhttp_request *req, char *uri)
{
const char *host;
char *ext;
char path[PATH_MAX];
char *deref;
char *ctype;
char *passwd;
struct evbuffer *evbuf;
struct evkeyvalq *headers;
struct stat sb;
int fd;
int i;
@ -779,8 +839,9 @@ serve_file(struct evhttp_request *req, char *uri)
}
else
{
if ((strcmp(req->remote_host, "::1") != 0)
&& (strcmp(req->remote_host, "127.0.0.1") != 0))
host = evhttp_request_get_host(req);
if ((strcmp(host, "::1") != 0)
&& (strcmp(host, "127.0.0.1") != 0))
{
DPRINTF(E_LOG, L_HTTPD, "Remote web interface request denied; no password set\n");
@ -910,8 +971,9 @@ serve_file(struct evhttp_request *req, char *uri)
}
}
evhttp_add_header(req->output_headers, "Content-Type", ctype);
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "Content-Type", ctype);
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);
@ -925,7 +987,7 @@ httpd_gen_cb(struct evhttp_request *req, void *arg)
char *uri;
char *ptr;
req_uri = evhttp_request_uri(req);
req_uri = evhttp_request_get_uri(req);
if (!req_uri)
{
redirect_to_index(req, "/");
@ -1011,6 +1073,7 @@ exit_cb(int fd, short event, void *arg)
char *
httpd_fixup_uri(struct evhttp_request *req)
{
struct evkeyvalq *headers;
const char *ua;
const char *uri;
const char *u;
@ -1019,7 +1082,7 @@ httpd_fixup_uri(struct evhttp_request *req)
char *f;
int len;
uri = evhttp_request_uri(req);
uri = evhttp_request_get_uri(req);
if (!uri)
return NULL;
@ -1028,7 +1091,8 @@ httpd_fixup_uri(struct evhttp_request *req)
if (!q)
return strdup(uri);
ua = evhttp_find_header(req->input_headers, "User-Agent");
headers = evhttp_request_get_input_headers(req);
ua = evhttp_find_header(headers, "User-Agent");
if (!ua)
return strdup(uri);
@ -1093,6 +1157,7 @@ int
httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *realm)
{
struct evbuffer *evbuf;
struct evkeyvalq *headers;
char *header;
const char *auth;
char *authuser;
@ -1100,7 +1165,8 @@ httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *rea
int len;
int ret;
auth = evhttp_find_header(req->input_headers, "Authorization");
headers = evhttp_request_get_input_headers(req);
auth = evhttp_find_header(headers, "Authorization");
if (!auth)
{
DPRINTF(E_DBG, L_HTTPD, "No Authorization header\n");
@ -1183,7 +1249,8 @@ httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *rea
return -1;
}
evhttp_add_header(req->output_headers, "WWW-Authenticate", header);
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "WWW-Authenticate", header);
evbuffer_add(evbuf, http_reply_401, strlen(http_reply_401));
evhttp_send_reply(req, 401, "Unauthorized", evbuf);

View File

@ -4,9 +4,9 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
# include "evhttp/evhttp_compat.h"
#endif
void

View File

@ -51,6 +51,10 @@
#include "daap_query.h"
#include "dmap_common.h"
#ifdef HAVE_LIBEVENT2
# include <event2/http_struct.h>
#endif
/* httpd event base, from httpd.c */
extern struct event_base *evbase_httpd;
@ -313,6 +317,7 @@ static void
update_refresh_cb(int fd, short event, void *arg)
{
struct daap_update_request *ur;
struct evhttp_connection *evcon;
struct evbuffer *evbuf;
int ret;
@ -339,7 +344,8 @@ update_refresh_cb(int fd, short event, void *arg)
dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_int(evbuf, "musr", current_rev); /* 12 */
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
evcon = evhttp_request_get_connection(ur->req);
evhttp_connection_set_closecb(evcon, NULL, NULL);
httpd_send_reply(ur->req, HTTP_OK, "OK", evbuf);
@ -350,14 +356,16 @@ update_refresh_cb(int fd, short event, void *arg)
static void
update_fail_cb(struct evhttp_connection *evcon, void *arg)
{
struct evhttp_connection *evc;
struct daap_update_request *ur;
ur = (struct daap_update_request *)arg;
DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n");
if (ur->req->evcon)
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
evc = evhttp_request_get_connection(ur->req);
if (evc)
evhttp_connection_set_closecb(evc, NULL, NULL);
update_remove(ur);
update_free(ur);
@ -725,6 +733,7 @@ static void
daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{
struct evbuffer *content;
struct evkeyvalq *headers;
cfg_t *lib;
char *name;
char *passwd;
@ -748,7 +757,8 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char
mpro = 2 << 16 | 10;
apro = 3 << 16 | 12;
clientver = evhttp_find_header(req->input_headers, "Client-DAAP-Version");
headers = evhttp_request_get_input_headers(req);
clientver = evhttp_find_header(headers, "Client-DAAP-Version");
if (clientver)
{
if (strcmp(clientver, "1.0") == 0)
@ -859,6 +869,7 @@ daap_reply_login(struct evhttp_request *req, struct evbuffer *evbuf, char **uri,
{
struct pairing_info pi;
struct daap_session *s;
struct evkeyvalq *headers;
const char *ua;
const char *param;
int request_session_id;
@ -873,7 +884,8 @@ daap_reply_login(struct evhttp_request *req, struct evbuffer *evbuf, char **uri,
return;
}
ua = evhttp_find_header(req->input_headers, "User-Agent");
headers = evhttp_request_get_input_headers(req);
ua = evhttp_find_header(headers, "User-Agent");
if (ua && (strncmp(ua, "Remote", strlen("Remote")) == 0))
{
param = evhttp_find_header(query, "pairing-guid");
@ -949,6 +961,7 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
struct timeval tv;
struct daap_session *s;
struct daap_update_request *ur;
struct evhttp_connection *evcon;
const char *param;
int reqd_rev;
int ret;
@ -1035,7 +1048,9 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
/* If the connection fails before we have an update to push out
* to the client, we need to know.
*/
evhttp_connection_set_closecb(req->evcon, update_fail_cb, ur);
evcon = evhttp_request_get_connection(req);
if (evcon)
evhttp_connection_set_closecb(evcon, update_fail_cb, ur);
}
static void
@ -1107,6 +1122,7 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
struct db_media_file_info dbmfi;
struct evbuffer *song;
struct evbuffer *songlist;
struct evkeyvalq *headers;
const struct dmap_field **meta;
struct sort_ctx *sctx;
const char *param;
@ -1244,7 +1260,8 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
{
nsongs++;
transcode = transcode_needed(req->input_headers, dbmfi.codectype);
headers = evhttp_request_get_input_headers(req);
transcode = transcode_needed(headers, dbmfi.codectype);
ret = dmap_encode_file_metadata(songlist, song, &dbmfi, meta, nmeta, sort_headers, transcode);
if (ret < 0)
@ -2121,6 +2138,7 @@ daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char *
{
char clen[32];
struct daap_session *s;
struct evkeyvalq *headers;
const char *param;
char *ctype;
int id;
@ -2191,10 +2209,11 @@ daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char *
goto no_artwork;
}
evhttp_remove_header(req->output_headers, "Content-Type");
evhttp_add_header(req->output_headers, "Content-Type", ctype);
headers = evhttp_request_get_output_headers(req);
evhttp_remove_header(headers, "Content-Type");
evhttp_add_header(headers, "Content-Type", ctype);
snprintf(clen, sizeof(clen), "%ld", (long)EVBUFFER_LENGTH(evbuf));
evhttp_add_header(req->output_headers, "Content-Length", clen);
evhttp_add_header(headers, "Content-Length", clen);
/* No gzip compression for artwork */
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
@ -2435,6 +2454,7 @@ daap_request(struct evhttp_request *req)
char *uri_parts[7];
struct evbuffer *evbuf;
struct evkeyvalq query;
struct evkeyvalq *headers;
const char *ua;
cfg_t *lib;
char *libname;
@ -2532,7 +2552,8 @@ daap_request(struct evhttp_request *req)
* valid session-id that Remote can only obtain if its pairing-guid is in
* our database. So HTTP authentication is waived for Remote.
*/
ua = evhttp_find_header(req->input_headers, "User-Agent");
headers = evhttp_request_get_input_headers(req);
ua = evhttp_find_header(headers, "User-Agent");
if ((ua) && (strncmp(ua, "Remote", strlen("Remote")) == 0))
passwd = NULL;
@ -2587,13 +2608,14 @@ daap_request(struct evhttp_request *req)
evhttp_parse_query(full_uri, &query);
evhttp_add_header(req->output_headers, "Accept-Ranges", "bytes");
evhttp_add_header(req->output_headers, "DAAP-Server", "forked-daapd/" VERSION);
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "Accept-Ranges", "bytes");
evhttp_add_header(headers, "DAAP-Server", "forked-daapd/" VERSION);
/* Content-Type for all replies, even the actual audio streaming. Note that
* video streaming will override this Content-Type with a more appropriate
* video/<type> Content-Type as expected by clients like Front Row.
*/
evhttp_add_header(req->output_headers, "Content-Type", "application/x-dmap-tagged");
evhttp_add_header(headers, "Content-Type", "application/x-dmap-tagged");
daap_handlers[handler].handler(req, evbuf, uri_parts, &query);
@ -2679,6 +2701,7 @@ void
daap_deinit(void)
{
struct daap_update_request *ur;
struct evhttp_connection *evcon;
int i;
for (i = 0; daap_handlers[i].handler; i++)
@ -2690,10 +2713,11 @@ daap_deinit(void)
{
update_requests = ur->next;
if (ur->req->evcon)
evcon = evhttp_request_get_connection(ur->req);
if (evcon)
{
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
evhttp_connection_free(ur->req->evcon);
evhttp_connection_set_closecb(evcon, NULL, NULL);
evhttp_connection_free(evcon);
}
update_free(ur);

View File

@ -4,9 +4,9 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
# include "evhttp/evhttp_compat.h"
#endif
int

View File

@ -47,7 +47,6 @@
#include "db.h"
#include "player.h"
/* httpd event base, from httpd.c */
extern struct event_base *evbase_httpd;
@ -268,6 +267,7 @@ playstatusupdate_cb(int fd, short what, void *arg)
struct dacp_update_request *ur;
struct evbuffer *evbuf;
struct evbuffer *update;
struct evhttp_connection *evcon;
int ret;
#ifdef USE_EVENTFD
@ -313,7 +313,9 @@ playstatusupdate_cb(int fd, short what, void *arg)
{
update_requests = ur->next;
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
evcon = evhttp_request_get_connection(ur->req);
if (evcon)
evhttp_connection_set_closecb(evcon, NULL, NULL);
evbuffer_add(evbuf, EVBUFFER_DATA(update), EVBUFFER_LENGTH(update));
@ -358,13 +360,15 @@ update_fail_cb(struct evhttp_connection *evcon, void *arg)
{
struct dacp_update_request *ur;
struct dacp_update_request *p;
struct evhttp_connection *evc;
ur = (struct dacp_update_request *)arg;
DPRINTF(E_DBG, L_DACP, "Update request: client closed connection\n");
if (ur->req->evcon)
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
evc = evhttp_request_get_connection(ur->req);
if (evc)
evhttp_connection_set_closecb(evc, NULL, NULL);
if (ur == update_requests)
update_requests = ur->next;
@ -1678,6 +1682,7 @@ dacp_reply_playstatusupdate(struct evhttp_request *req, struct evbuffer *evbuf,
{
struct daap_session *s;
struct dacp_update_request *ur;
struct evhttp_connection *evcon;
const char *param;
int reqd_rev;
int ret;
@ -1733,7 +1738,9 @@ dacp_reply_playstatusupdate(struct evhttp_request *req, struct evbuffer *evbuf,
/* If the connection fails before we have an update to push out
* to the client, we need to know.
*/
evhttp_connection_set_closecb(req->evcon, update_fail_cb, ur);
evcon = evhttp_request_get_connection(req);
if (evcon)
evhttp_connection_set_closecb(evcon, update_fail_cb, ur);
}
static void
@ -1741,6 +1748,7 @@ dacp_reply_nowplayingartwork(struct evhttp_request *req, struct evbuffer *evbuf,
{
char clen[32];
struct daap_session *s;
struct evkeyvalq *headers;
const char *param;
char *ctype;
uint32_t id;
@ -1810,10 +1818,11 @@ dacp_reply_nowplayingartwork(struct evhttp_request *req, struct evbuffer *evbuf,
goto no_artwork;
}
evhttp_remove_header(req->output_headers, "Content-Type");
evhttp_add_header(req->output_headers, "Content-Type", ctype);
headers = evhttp_request_get_output_headers(req);
evhttp_remove_header(headers, "Content-Type");
evhttp_add_header(headers, "Content-Type", ctype);
snprintf(clen, sizeof(clen), "%ld", (long)EVBUFFER_LENGTH(evbuf));
evhttp_add_header(req->output_headers, "Content-Length", clen);
evhttp_add_header(headers, "Content-Length", clen);
/* No gzip compression for artwork */
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
@ -2216,6 +2225,7 @@ dacp_request(struct evhttp_request *req)
char *uri_parts[7];
struct evbuffer *evbuf;
struct evkeyvalq query;
struct evkeyvalq *headers;
int handler;
int ret;
int i;
@ -2307,9 +2317,10 @@ dacp_request(struct evhttp_request *req)
evhttp_parse_query(full_uri, &query);
evhttp_add_header(req->output_headers, "DAAP-Server", "forked-daapd/" VERSION);
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "DAAP-Server", "forked-daapd/" VERSION);
/* Content-Type for all DACP replies; can be overriden as needed */
evhttp_add_header(req->output_headers, "Content-Type", "application/x-dmap-tagged");
evhttp_add_header(headers, "Content-Type", "application/x-dmap-tagged");
dacp_handlers[handler].handler(req, evbuf, uri_parts, &query);
@ -2401,6 +2412,7 @@ void
dacp_deinit(void)
{
struct dacp_update_request *ur;
struct evhttp_connection *evcon;
int i;
player_set_update_handler(NULL);
@ -2412,10 +2424,11 @@ dacp_deinit(void)
{
update_requests = ur->next;
if (ur->req->evcon)
evcon = evhttp_request_get_connection(ur->req);
if (evcon)
{
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
evhttp_connection_free(ur->req->evcon);
evhttp_connection_set_closecb(evcon, NULL, NULL);
evhttp_connection_free(evcon);
}
free(ur);

View File

@ -4,9 +4,9 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
# include "evhttp/evhttp_compat.h"
#endif
int

View File

@ -42,7 +42,6 @@
#include "httpd_rsp.h"
#include "rsp_query.h"
#define RSP_VERSION "1.0"
#define RSP_XML_ROOT "?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?"
@ -219,6 +218,7 @@ static void
rsp_send_error(struct evhttp_request *req, char *errmsg)
{
struct evbuffer *evbuf;
struct evkeyvalq *headers;
mxml_node_t *reply;
mxml_node_t *status;
mxml_node_t *node;
@ -254,8 +254,9 @@ rsp_send_error(struct evhttp_request *req, char *errmsg)
return;
}
evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=utf-8");
evhttp_add_header(req->output_headers, "Connection", "close");
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "Content-Type", "text/xml; charset=utf-8");
evhttp_add_header(headers, "Connection", "close");
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);
@ -265,6 +266,7 @@ static void
rsp_send_reply(struct evhttp_request *req, mxml_node_t *reply)
{
struct evbuffer *evbuf;
struct evkeyvalq *headers;
evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply);
@ -276,8 +278,9 @@ rsp_send_reply(struct evhttp_request *req, mxml_node_t *reply)
return;
}
evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=utf-8");
evhttp_add_header(req->output_headers, "Connection", "close");
headers = evhttp_request_get_output_headers(req);
evhttp_add_header(headers, "Content-Type", "text/xml; charset=utf-8");
evhttp_add_header(headers, "Connection", "close");
httpd_send_reply(req, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);
@ -434,6 +437,7 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
{
struct query_params qp;
struct db_media_file_info dbmfi;
struct evkeyvalq *headers;
const char *param;
char **strval;
mxml_node_t *reply;
@ -526,7 +530,8 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
/* Items block (all items) */
while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
{
transcode = transcode_needed(req->input_headers, dbmfi.codectype);
headers = evhttp_request_get_input_headers(req);
transcode = transcode_needed(headers, dbmfi.codectype);
/* Item block (one item) */
item = mxmlNewElement(items, "item");

View File

@ -4,9 +4,9 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
# include "evhttp/evhttp_compat.h"
#endif
int

View File

@ -48,9 +48,9 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
# include "evhttp/evhttp_compat.h"
#endif
#include <gcrypt.h>
@ -414,8 +414,10 @@ static void
pairing_request_cb(struct evhttp_request *req, void *arg)
{
struct remote_info *ri;
struct evbuffer *input_buffer;
uint8_t *response;
char guid[17];
int response_code;
int len;
int i;
int ret;
@ -429,21 +431,24 @@ pairing_request_cb(struct evhttp_request *req, void *arg)
goto cleanup;
}
if (req->response_code != HTTP_OK)
response_code = evhttp_request_get_response_code(req);
if (response_code != HTTP_OK)
{
DPRINTF(E_LOG, L_REMOTE, "Pairing failed with Remote %s/%s, HTTP response code %d\n", ri->pi.remote_id, ri->pi.name, req->response_code);
DPRINTF(E_LOG, L_REMOTE, "Pairing failed with Remote %s/%s, HTTP response code %d\n", ri->pi.remote_id, ri->pi.name, response_code);
goto cleanup;
}
if (EVBUFFER_LENGTH(req->input_buffer) < 8)
input_buffer = evhttp_request_get_input_buffer(req);
if (EVBUFFER_LENGTH(input_buffer) < 8)
{
DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response too short\n", ri->pi.remote_id, ri->pi.name);
goto cleanup;
}
response = EVBUFFER_DATA(req->input_buffer);
response = EVBUFFER_DATA(input_buffer);
if ((response[0] != 'c') || (response[1] != 'm') || (response[2] != 'p') || (response[3] != 'a'))
{
@ -453,10 +458,10 @@ pairing_request_cb(struct evhttp_request *req, void *arg)
}
len = (response[4] << 24) | (response[5] << 16) | (response[6] << 8) | (response[7]);
if (EVBUFFER_LENGTH(req->input_buffer) < 8 + len)
if (EVBUFFER_LENGTH(input_buffer) < 8 + len)
{
DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response truncated (got %d expected %d)\n",
ri->pi.remote_id, ri->pi.name, (int)EVBUFFER_LENGTH(req->input_buffer), len + 8);
ri->pi.remote_id, ri->pi.name, (int)EVBUFFER_LENGTH(input_buffer), len + 8);
goto cleanup;
}
@ -536,7 +541,7 @@ send_pairing_request(struct remote_info *ri, char *req_uri, int family)
return -1;
}
evcon = evhttp_connection_new(address, port);
evcon = evhttp_connection_base_new(evbase_main, NULL, address, port);
if (!evcon)
{
DPRINTF(E_LOG, L_REMOTE, "Could not create connection for pairing with %s\n", ri->pi.name);
@ -544,8 +549,6 @@ send_pairing_request(struct remote_info *ri, char *req_uri, int family)
return -1;
}
evhttp_connection_set_base(evcon, evbase_main);
req = evhttp_request_new(pairing_request_cb, ri);
if (!req)
{
@ -883,7 +886,7 @@ remote_pairing_read_pin(char *path)
return;
}
DPRINTF(E_DBG, L_REMOTE, "Adding Remote pin data: name '%s', pin '%s'\n", devname, pin);
DPRINTF(E_LOG, L_REMOTE, "Read Remote pairing data (name '%s', pin '%s') from %s\n", devname, pin, path);
pthread_mutex_lock(&remote_lck);

View File

@ -4,7 +4,7 @@
#include <event.h>
#ifdef HAVE_LIBEVENT2
# include <evhttp.h>
# include <event2/http.h>
#else
# include "evhttp/evhttp.h"
#endif