mirror of
https://github.com/owntone/owntone-server.git
synced 2025-03-20 12:34:18 -04:00
Merge branch: libevent compability improvements
This commit is contained in:
commit
30aa93479d
12
INSTALL
12
INSTALL
@ -24,14 +24,16 @@ sudo apt-get install \
|
|||||||
antlr3 libantlr3c-dev libconfuse-dev libunistring-dev libsqlite3-dev \
|
antlr3 libantlr3c-dev libconfuse-dev libunistring-dev libsqlite3-dev \
|
||||||
libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libasound2-dev \
|
libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libasound2-dev \
|
||||||
libmxml-dev libgcrypt11-dev libavahi-client-dev libavl-dev zlib1g-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
|
Depending on the version of libav/ffmpeg in your distribution you may also need
|
||||||
libavresample-dev.
|
libavresample-dev.
|
||||||
|
|
||||||
Note that libevent1-dev is not in the Debian repository, but you can get the
|
Note that while forked-daapd will work with versions of libevent between 2.0.0
|
||||||
packages in the Ubuntu repository. You can also use libevent 2, but it must be
|
and 2.1.3, it is recommended to use either libevent 1 or 2.1.4+. Otherwise you
|
||||||
version 2.1.4 or newer.
|
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:
|
Then run the following:
|
||||||
|
|
||||||
@ -86,7 +88,7 @@ Libraries:
|
|||||||
from <http://libav.org/releases/>
|
from <http://libav.org/releases/>
|
||||||
- libconfuse
|
- libconfuse
|
||||||
from <http://www.nongnu.org/confuse/>
|
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/>
|
from <http://libevent.org/>
|
||||||
- libavl 0.3.5
|
- libavl 0.3.5
|
||||||
from <http://ftp.debian.org/debian/pool/main/liba/libavl>
|
from <http://ftp.debian.org/debian/pool/main/liba/libavl>
|
||||||
|
19
configure.ac
19
configure.ac
@ -160,19 +160,28 @@ fi
|
|||||||
|
|
||||||
PKG_CHECK_MODULES(MINIXML, [ mxml ])
|
PKG_CHECK_MODULES(MINIXML, [ mxml ])
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBEVENT, [ libevent >= 2.1.4 ],
|
PKG_CHECK_MODULES(LIBEVENT, [ libevent >= 2 ],
|
||||||
AC_DEFINE(HAVE_LIBEVENT2, 1, [Define to 1 if you have libevent >= 2.1.4]),
|
AC_DEFINE(HAVE_LIBEVENT2, 1, [Define to 1 if you have libevent 2]),
|
||||||
try_libevent1=true;
|
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
|
if test x$try_libevent1 = xtrue; then
|
||||||
AC_CHECK_HEADER(event.h, , AC_MSG_ERROR([event.h not found]))
|
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_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)
|
AC_SUBST(LIBEVENT_LIBS)
|
||||||
AM_CONDITIONAL(COND_LIBEVENT2, false)
|
AM_CONDITIONAL(COND_LIBEVENT1, true)
|
||||||
else
|
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
|
fi
|
||||||
|
|
||||||
AC_CHECK_HEADER(avl.h, , AC_MSG_ERROR([avl.h not found]))
|
AC_CHECK_HEADER(avl.h, , AC_MSG_ERROR([avl.h not found]))
|
||||||
|
@ -31,13 +31,21 @@ else
|
|||||||
FFURL_SRC=ffmpeg_url_evbuffer.c ffmpeg_url_evbuffer.h
|
FFURL_SRC=ffmpeg_url_evbuffer.c ffmpeg_url_evbuffer.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if COND_LIBEVENT2
|
if COND_LIBEVENT1
|
||||||
RTSP_SRC=evrtsp/rtsp.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
|
EVHTTP_SRC=evhttp/http.c evhttp/evhttp.h evhttp/evhttp_compat.c evhttp/evhttp_compat.h evhttp/http-internal.h evhttp/log.h
|
||||||
else
|
|
||||||
EVHTTP_SRC=evhttp/http.c evhttp/evhttp.h evhttp/http-internal.h evhttp/log.h
|
|
||||||
RTSP_SRC=evrtsp/rtsp-libevent1.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
|
RTSP_SRC=evrtsp/rtsp-libevent1.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
|
||||||
endif
|
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 = \
|
GPERF_FILES = \
|
||||||
daap_query.gperf \
|
daap_query.gperf \
|
||||||
rsp_query.gperf \
|
rsp_query.gperf \
|
||||||
|
24
src/db.c
24
src/db.c
@ -1580,7 +1580,7 @@ db_query_fetch_file(struct query_params *qp, struct db_media_file_info *dbmfi)
|
|||||||
ret = db_blocking_step(qp->stmt);
|
ret = db_blocking_step(qp->stmt);
|
||||||
if (ret == SQLITE_DONE)
|
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;
|
dbmfi->id = NULL;
|
||||||
return 0;
|
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);
|
ret = db_blocking_step(qp->stmt);
|
||||||
if (ret == SQLITE_DONE)
|
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;
|
dbpli->id = NULL;
|
||||||
return 0;
|
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);
|
ret = db_blocking_step(qp->stmt);
|
||||||
if (ret == SQLITE_DONE)
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (ret != SQLITE_ROW)
|
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);
|
ret = db_blocking_step(qp->stmt);
|
||||||
if (ret == SQLITE_DONE)
|
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;
|
*string = NULL;
|
||||||
return 0;
|
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);
|
ret = db_blocking_step(qp->stmt);
|
||||||
if (ret == SQLITE_DONE)
|
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;
|
*string = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1997,7 +1997,7 @@ db_file_path_byid(int id)
|
|||||||
if (ret != SQLITE_ROW)
|
if (ret != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
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_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
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_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
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_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
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_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
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_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
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_ROW)
|
||||||
{
|
{
|
||||||
if (ret == SQLITE_DONE)
|
if (ret == SQLITE_DONE)
|
||||||
DPRINTF(E_INFO, L_DB, "No results\n");
|
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||||
else
|
else
|
||||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp.h"
|
||||||
#endif
|
#endif
|
||||||
|
42
src/evhttp/evhttp_compat.c
Normal file
42
src/evhttp/evhttp_compat.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
27
src/evhttp/evhttp_compat.h
Normal file
27
src/evhttp/evhttp_compat.h
Normal 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
1808
src/evrtsp/rtsp-libevent20.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
else if (type & F_SCAN_TYPE_URL)
|
||||||
{
|
{
|
||||||
mfi->data_kind = 1; /* url/stream */
|
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);
|
ret = scan_metadata_icy(path, mfi);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (type & F_SCAN_TYPE_SPOTIFY)
|
else if (type & F_SCAN_TYPE_SPOTIFY)
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "filescanner.h"
|
#include "filescanner.h"
|
||||||
@ -313,10 +314,85 @@ extract_metadata(struct media_file_info *mfi, AVFormatContext *ctx, AVStream *au
|
|||||||
return mdcount;
|
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
|
int
|
||||||
scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||||
{
|
{
|
||||||
AVFormatContext *ctx;
|
AVFormatContext *ctx;
|
||||||
|
AVDictionary *options;
|
||||||
const struct metadata_map *extra_md_map;
|
const struct metadata_map *extra_md_map;
|
||||||
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
|
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
|
||||||
enum AVCodecID codec_id;
|
enum AVCodecID codec_id;
|
||||||
@ -334,9 +410,13 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ctx = NULL;
|
ctx = NULL;
|
||||||
|
options = NULL;
|
||||||
|
|
||||||
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3)
|
#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
|
#else
|
||||||
ret = av_open_input_file(&ctx, file, NULL, 0, NULL);
|
ret = av_open_input_file(&ctx, file, NULL, 0, NULL);
|
||||||
#endif
|
#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);
|
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 */
|
/* Get some more information on the audio stream */
|
||||||
if (audio_stream)
|
if (audio_stream)
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
@ -37,16 +34,17 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#if defined HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
@ -71,15 +69,16 @@ struct icy_ctx
|
|||||||
char hostname[PATH_MAX];
|
char hostname[PATH_MAX];
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
|
char *icy_name;
|
||||||
|
char *icy_description;
|
||||||
|
char *icy_genre;
|
||||||
|
|
||||||
|
pthread_mutex_t lck;
|
||||||
|
pthread_cond_t cond;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
#ifndef HAVE_LIBEVENT2
|
||||||
free_icy(struct icy_ctx *ctx)
|
|
||||||
{
|
|
||||||
if (ctx)
|
|
||||||
free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
resolve_address(char *hostname, char *s, size_t maxlen)
|
resolve_address(char *hostname, char *s, size_t maxlen)
|
||||||
{
|
{
|
||||||
@ -102,62 +101,81 @@ resolve_address(char *hostname, char *s, size_t maxlen)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
strncpy(s, "Unknown AF", maxlen);
|
strncpy(s, "Unknown AF", maxlen);
|
||||||
|
freeaddrinfo(result);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBEVENT2_OLD
|
||||||
static void
|
static void
|
||||||
scan_icy_request_cb(struct evhttp_request *req, void *arg)
|
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;
|
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 */
|
/* Will always return -1 to make evhttp close the connection - we only need the http headers */
|
||||||
static int
|
static int
|
||||||
scan_icy_header_cb(struct evhttp_request *req, void *arg)
|
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;
|
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);
|
ctx->icy_name = strdup(ptr);
|
||||||
mfi->artist = strdup(ptr);
|
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, name is %s\n", ctx->icy_name);
|
||||||
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, name (title/artist) is %s\n", mfi->title);
|
|
||||||
}
|
}
|
||||||
if ( (ptr = evhttp_find_header(req->input_headers, "icy-description")) )
|
if ( (ptr = evhttp_find_header(headers, "icy-description")) )
|
||||||
{
|
{
|
||||||
mfi->album = strdup(ptr);
|
ctx->icy_description = strdup(ptr);
|
||||||
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, description (album) is %s\n", mfi->album);
|
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);
|
ctx->icy_genre = strdup(ptr);
|
||||||
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, genre is %s\n", mfi->genre);
|
DPRINTF(E_DBG, L_SCAN, "Found ICY metadata, genre is %s\n", ctx->icy_genre);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ICY_DONE;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
scan_metadata_icy(char *url, struct media_file_info *mfi)
|
scan_metadata_icy(char *url, struct media_file_info *mfi)
|
||||||
{
|
{
|
||||||
struct evhttp_connection *evcon;
|
|
||||||
struct evhttp_request *req;
|
|
||||||
struct icy_ctx *ctx;
|
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 ret;
|
||||||
int i;
|
|
||||||
|
|
||||||
status = ICY_INIT;
|
status = ICY_INIT;
|
||||||
|
start = time(NULL);
|
||||||
|
|
||||||
/* We can set this straight away */
|
/* We can set this straight away */
|
||||||
mfi->url = strdup(url);
|
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");
|
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));
|
memset(ctx, 0, sizeof(struct icy_ctx));
|
||||||
|
|
||||||
|
pthread_mutex_init(&ctx->lck, NULL);
|
||||||
|
pthread_cond_init(&ctx->cond, NULL);
|
||||||
|
|
||||||
ctx->url = url;
|
ctx->url = url;
|
||||||
|
|
||||||
/* TODO https */
|
/* TODO https */
|
||||||
@ -185,6 +206,21 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
|
|||||||
if (ctx->port < 0)
|
if (ctx->port < 0)
|
||||||
ctx->port = 80;
|
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 */
|
/* Resolve IP address */
|
||||||
ret = resolve_address(ctx->hostname, ctx->address, sizeof(ctx->address));
|
ret = resolve_address(ctx->hostname, ctx->address, sizeof(ctx->address));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -205,37 +241,45 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
|
|||||||
goto no_icy;
|
goto no_icy;
|
||||||
}
|
}
|
||||||
evhttp_connection_set_base(evcon, evbase_main);
|
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);
|
evhttp_connection_set_timeout(evcon, ICY_TIMEOUT);
|
||||||
|
|
||||||
/* Set up request */
|
/* Set up request */
|
||||||
req = evhttp_request_new(scan_icy_request_cb, mfi);
|
req = evhttp_request_new(scan_icy_request_cb, ctx);
|
||||||
if (!req)
|
if (!req)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_SCAN, "Could not create request to %s\n", ctx->hostname);
|
DPRINTF(E_LOG, L_SCAN, "Could not create request to %s\n", ctx->hostname);
|
||||||
|
|
||||||
evhttp_connection_free(evcon);
|
|
||||||
goto no_icy;
|
goto no_icy;
|
||||||
}
|
}
|
||||||
req->header_cb = scan_icy_header_cb;
|
|
||||||
evhttp_add_header(req->output_headers, "Host", ctx->hostname);
|
evhttp_request_set_header_cb(req, scan_icy_header_cb);
|
||||||
evhttp_add_header(req->output_headers, "Icy-MetaData", "1");
|
|
||||||
|
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 */
|
/* Make request */
|
||||||
|
DPRINTF(E_INFO, L_SCAN, "Making request to %s asking for ICY (Shoutcast) metadata\n", ctx->hostname);
|
||||||
|
|
||||||
status = ICY_WAITING;
|
status = ICY_WAITING;
|
||||||
ret = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, ctx->path);
|
ret = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, ctx->path);
|
||||||
if (ret < 0)
|
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;
|
status = ICY_DONE;
|
||||||
evhttp_connection_free(evcon);
|
|
||||||
goto no_icy;
|
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
|
/* Can't count on server support for ICY metadata, so
|
||||||
* while waiting for a reply make a parallel call to scan_metadata_ffmpeg.
|
* while waiting for a reply make a parallel call to scan_metadata_ffmpeg.
|
||||||
* This call will also determine final return value.
|
|
||||||
*/
|
*/
|
||||||
no_icy:
|
no_icy:
|
||||||
ret = scan_metadata_ffmpeg(url, mfi);
|
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");
|
mfi->description = strdup("MPEG audio file");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait till ICY request completes or we reach timeout */
|
/* Wait for ICY request to complete or timeout */
|
||||||
for (i = 0; (status == ICY_WAITING) && (i <= ICY_TIMEOUT); i++)
|
pthread_mutex_lock(&ctx->lck);
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#include <plist/plist.h>
|
#include <plist/plist.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp.h"
|
||||||
#endif
|
#endif
|
||||||
|
125
src/httpd.c
125
src/httpd.c
@ -53,7 +53,6 @@
|
|||||||
#include "httpd_dacp.h"
|
#include "httpd_dacp.h"
|
||||||
#include "transcode.h"
|
#include "transcode.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HTTP client quirks by User-Agent, from mt-daapd
|
* HTTP client quirks by User-Agent, from mt-daapd
|
||||||
*
|
*
|
||||||
@ -123,12 +122,19 @@ static struct event exitev;
|
|||||||
static struct evhttp *evhttpd;
|
static struct evhttp *evhttpd;
|
||||||
static pthread_t tid_httpd;
|
static pthread_t tid_httpd;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVENT2_OLD
|
||||||
|
struct stream_ctx *g_st;
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stream_end(struct stream_ctx *st, int failed)
|
stream_end(struct stream_ctx *st, int failed)
|
||||||
{
|
{
|
||||||
if (st->req->evcon)
|
struct evhttp_connection *evcon;
|
||||||
evhttp_connection_set_closecb(st->req->evcon, NULL, NULL);
|
|
||||||
|
evcon = evhttp_request_get_connection(st->req);
|
||||||
|
|
||||||
|
if (evcon)
|
||||||
|
evhttp_connection_set_closecb(evcon, NULL, NULL);
|
||||||
|
|
||||||
if (!failed)
|
if (!failed)
|
||||||
evhttp_send_reply_end(st->req);
|
evhttp_send_reply_end(st->req);
|
||||||
@ -143,6 +149,11 @@ stream_end(struct stream_ctx *st, int failed)
|
|||||||
close(st->fd);
|
close(st->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVENT2_OLD
|
||||||
|
if (g_st == st)
|
||||||
|
g_st = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
free(st);
|
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
|
static void
|
||||||
stream_chunk_xcode_cb(int fd, short event, void *arg)
|
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
|
else
|
||||||
ret = xcoded;
|
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);
|
evhttp_send_reply_chunk_with_cb(st->req, st->evbuf, stream_chunk_resched_cb, st);
|
||||||
|
#endif
|
||||||
|
|
||||||
st->offset += ret;
|
st->offset += ret;
|
||||||
|
|
||||||
@ -280,7 +310,17 @@ stream_chunk_raw_cb(int fd, short event, void *arg)
|
|||||||
|
|
||||||
evbuffer_add(st->evbuf, st->buf, ret);
|
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);
|
evhttp_send_reply_chunk_with_cb(st->req, st->evbuf, stream_chunk_resched_cb, st);
|
||||||
|
#endif
|
||||||
|
|
||||||
st->offset += ret;
|
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);
|
void (*stream_cb)(int fd, short event, void *arg);
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
|
struct evkeyvalq *input_headers;
|
||||||
|
struct evkeyvalq *output_headers;
|
||||||
const char *param;
|
const char *param;
|
||||||
const char *param_end;
|
const char *param_end;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
@ -323,7 +366,10 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
end_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)
|
if (param)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, L_HTTPD, "Found Range header: %s\n", 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));
|
memset(st, 0, sizeof(struct stream_ctx));
|
||||||
st->fd = -1;
|
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)
|
if (transcode)
|
||||||
{
|
{
|
||||||
@ -403,8 +451,8 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||||||
goto out_free_st;
|
goto out_free_st;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!evhttp_find_header(req->output_headers, "Content-Type"))
|
if (!evhttp_find_header(output_headers, "Content-Type"))
|
||||||
evhttp_add_header(req->output_headers, "Content-Type", "audio/wav");
|
evhttp_add_header(output_headers, "Content-Type", "audio/wav");
|
||||||
}
|
}
|
||||||
else
|
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");
|
DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
evhttp_remove_header(req->output_headers, "Content-Type");
|
evhttp_remove_header(output_headers, "Content-Type");
|
||||||
evhttp_add_header(req->output_headers, "Content-Type", buf);
|
evhttp_add_header(output_headers, "Content-Type", buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If no Content-Type has been set and we're streaming audio, add a proper
|
/* 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
|
* Content-Type for the file we're streaming. Remember DAAP streams audio
|
||||||
* with application/x-dmap-tagged as the Content-Type (ugh!).
|
* 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);
|
ret = snprintf(buf, sizeof(buf), "audio/%s", mfi->type);
|
||||||
if ((ret < 0) || (ret >= sizeof(buf)))
|
if ((ret < 0) || (ret >= sizeof(buf)))
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
|
DPRINTF(E_LOG, L_HTTPD, "Content-Type too large for buffer, dropping\n");
|
||||||
else
|
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");
|
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");
|
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
|
||||||
|
|
||||||
goto out_cleanup;
|
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");
|
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");
|
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
|
||||||
|
|
||||||
goto out_cleanup;
|
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");
|
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");
|
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
|
||||||
|
|
||||||
goto out_cleanup;
|
goto out_cleanup;
|
||||||
@ -539,7 +587,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||||||
if ((ret < 0) || (ret >= sizeof(buf)))
|
if ((ret < 0) || (ret >= sizeof(buf)))
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
|
DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
|
||||||
else
|
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");
|
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)))
|
if ((ret < 0) || (ret >= sizeof(buf)))
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
|
DPRINTF(E_LOG, L_HTTPD, "Content-Range too large for buffer, dropping\n");
|
||||||
else
|
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);
|
ret = snprintf(buf, sizeof(buf), "%" PRIi64, ((end_offset) ? end_offset + 1 : (int64_t)st->size) - offset);
|
||||||
if ((ret < 0) || (ret >= sizeof(buf)))
|
if ((ret < 0) || (ret >= sizeof(buf)))
|
||||||
DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
|
DPRINTF(E_LOG, L_HTTPD, "Content-Length too large for buffer, dropping\n");
|
||||||
else
|
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");
|
evhttp_send_reply_start(req, 206, "Partial Content");
|
||||||
}
|
}
|
||||||
@ -579,7 +627,9 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
|||||||
}
|
}
|
||||||
#endif
|
#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);
|
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];
|
unsigned char outbuf[128 * 1024];
|
||||||
z_stream strm;
|
z_stream strm;
|
||||||
struct evbuffer *gzbuf;
|
struct evbuffer *gzbuf;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *param;
|
const char *param;
|
||||||
int flush;
|
int flush;
|
||||||
int zret;
|
int zret;
|
||||||
@ -621,7 +672,9 @@ httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struc
|
|||||||
goto no_gzip;
|
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)
|
if (!param)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, L_HTTPD, "Not gzipping; no Accept-Encoding header\n");
|
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);
|
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);
|
evhttp_send_reply(req, code, reason, gzbuf);
|
||||||
|
|
||||||
evbuffer_free(gzbuf);
|
evbuffer_free(gzbuf);
|
||||||
@ -731,6 +786,7 @@ path_is_legal(char *path)
|
|||||||
static void
|
static void
|
||||||
redirect_to_index(struct evhttp_request *req, char *uri)
|
redirect_to_index(struct evhttp_request *req, char *uri)
|
||||||
{
|
{
|
||||||
|
struct evkeyvalq *headers;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int slashed;
|
int slashed;
|
||||||
int ret;
|
int ret;
|
||||||
@ -746,7 +802,9 @@ redirect_to_index(struct evhttp_request *req, char *uri)
|
|||||||
return;
|
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);
|
evhttp_send_reply(req, HTTP_MOVETEMP, "Moved", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,12 +812,14 @@ redirect_to_index(struct evhttp_request *req, char *uri)
|
|||||||
static void
|
static void
|
||||||
serve_file(struct evhttp_request *req, char *uri)
|
serve_file(struct evhttp_request *req, char *uri)
|
||||||
{
|
{
|
||||||
|
const char *host;
|
||||||
char *ext;
|
char *ext;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
char *deref;
|
char *deref;
|
||||||
char *ctype;
|
char *ctype;
|
||||||
char *passwd;
|
char *passwd;
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int fd;
|
int fd;
|
||||||
int i;
|
int i;
|
||||||
@ -779,8 +839,9 @@ serve_file(struct evhttp_request *req, char *uri)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((strcmp(req->remote_host, "::1") != 0)
|
host = evhttp_request_get_host(req);
|
||||||
&& (strcmp(req->remote_host, "127.0.0.1") != 0))
|
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");
|
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);
|
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
|
||||||
|
|
||||||
evbuffer_free(evbuf);
|
evbuffer_free(evbuf);
|
||||||
@ -925,7 +987,7 @@ httpd_gen_cb(struct evhttp_request *req, void *arg)
|
|||||||
char *uri;
|
char *uri;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
req_uri = evhttp_request_uri(req);
|
req_uri = evhttp_request_get_uri(req);
|
||||||
if (!req_uri)
|
if (!req_uri)
|
||||||
{
|
{
|
||||||
redirect_to_index(req, "/");
|
redirect_to_index(req, "/");
|
||||||
@ -1011,6 +1073,7 @@ exit_cb(int fd, short event, void *arg)
|
|||||||
char *
|
char *
|
||||||
httpd_fixup_uri(struct evhttp_request *req)
|
httpd_fixup_uri(struct evhttp_request *req)
|
||||||
{
|
{
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *ua;
|
const char *ua;
|
||||||
const char *uri;
|
const char *uri;
|
||||||
const char *u;
|
const char *u;
|
||||||
@ -1019,7 +1082,7 @@ httpd_fixup_uri(struct evhttp_request *req)
|
|||||||
char *f;
|
char *f;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
uri = evhttp_request_uri(req);
|
uri = evhttp_request_get_uri(req);
|
||||||
if (!uri)
|
if (!uri)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -1028,7 +1091,8 @@ httpd_fixup_uri(struct evhttp_request *req)
|
|||||||
if (!q)
|
if (!q)
|
||||||
return strdup(uri);
|
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)
|
if (!ua)
|
||||||
return strdup(uri);
|
return strdup(uri);
|
||||||
|
|
||||||
@ -1093,6 +1157,7 @@ int
|
|||||||
httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *realm)
|
httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *realm)
|
||||||
{
|
{
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
char *header;
|
char *header;
|
||||||
const char *auth;
|
const char *auth;
|
||||||
char *authuser;
|
char *authuser;
|
||||||
@ -1100,7 +1165,8 @@ httpd_basic_auth(struct evhttp_request *req, char *user, char *passwd, char *rea
|
|||||||
int len;
|
int len;
|
||||||
int ret;
|
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)
|
if (!auth)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, L_HTTPD, "No Authorization header\n");
|
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;
|
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));
|
evbuffer_add(evbuf, http_reply_401, strlen(http_reply_401));
|
||||||
evhttp_send_reply(req, 401, "Unauthorized", evbuf);
|
evhttp_send_reply(req, 401, "Unauthorized", evbuf);
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -51,6 +51,10 @@
|
|||||||
#include "daap_query.h"
|
#include "daap_query.h"
|
||||||
#include "dmap_common.h"
|
#include "dmap_common.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBEVENT2
|
||||||
|
# include <event2/http_struct.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* httpd event base, from httpd.c */
|
/* httpd event base, from httpd.c */
|
||||||
extern struct event_base *evbase_httpd;
|
extern struct event_base *evbase_httpd;
|
||||||
|
|
||||||
@ -313,6 +317,7 @@ static void
|
|||||||
update_refresh_cb(int fd, short event, void *arg)
|
update_refresh_cb(int fd, short event, void *arg)
|
||||||
{
|
{
|
||||||
struct daap_update_request *ur;
|
struct daap_update_request *ur;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
int ret;
|
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, "mstt", 200); /* 12 */
|
||||||
dmap_add_int(evbuf, "musr", current_rev); /* 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);
|
httpd_send_reply(ur->req, HTTP_OK, "OK", evbuf);
|
||||||
|
|
||||||
@ -350,14 +356,16 @@ update_refresh_cb(int fd, short event, void *arg)
|
|||||||
static void
|
static void
|
||||||
update_fail_cb(struct evhttp_connection *evcon, void *arg)
|
update_fail_cb(struct evhttp_connection *evcon, void *arg)
|
||||||
{
|
{
|
||||||
|
struct evhttp_connection *evc;
|
||||||
struct daap_update_request *ur;
|
struct daap_update_request *ur;
|
||||||
|
|
||||||
ur = (struct daap_update_request *)arg;
|
ur = (struct daap_update_request *)arg;
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n");
|
DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n");
|
||||||
|
|
||||||
if (ur->req->evcon)
|
evc = evhttp_request_get_connection(ur->req);
|
||||||
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
|
if (evc)
|
||||||
|
evhttp_connection_set_closecb(evc, NULL, NULL);
|
||||||
|
|
||||||
update_remove(ur);
|
update_remove(ur);
|
||||||
update_free(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)
|
daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
|
||||||
{
|
{
|
||||||
struct evbuffer *content;
|
struct evbuffer *content;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
cfg_t *lib;
|
cfg_t *lib;
|
||||||
char *name;
|
char *name;
|
||||||
char *passwd;
|
char *passwd;
|
||||||
@ -748,7 +757,8 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char
|
|||||||
mpro = 2 << 16 | 10;
|
mpro = 2 << 16 | 10;
|
||||||
apro = 3 << 16 | 12;
|
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 (clientver)
|
||||||
{
|
{
|
||||||
if (strcmp(clientver, "1.0") == 0)
|
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 pairing_info pi;
|
||||||
struct daap_session *s;
|
struct daap_session *s;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *ua;
|
const char *ua;
|
||||||
const char *param;
|
const char *param;
|
||||||
int request_session_id;
|
int request_session_id;
|
||||||
@ -873,7 +884,8 @@ daap_reply_login(struct evhttp_request *req, struct evbuffer *evbuf, char **uri,
|
|||||||
return;
|
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))
|
if (ua && (strncmp(ua, "Remote", strlen("Remote")) == 0))
|
||||||
{
|
{
|
||||||
param = evhttp_find_header(query, "pairing-guid");
|
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 timeval tv;
|
||||||
struct daap_session *s;
|
struct daap_session *s;
|
||||||
struct daap_update_request *ur;
|
struct daap_update_request *ur;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
const char *param;
|
const char *param;
|
||||||
int reqd_rev;
|
int reqd_rev;
|
||||||
int ret;
|
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
|
/* If the connection fails before we have an update to push out
|
||||||
* to the client, we need to know.
|
* 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
|
static void
|
||||||
@ -1107,6 +1122,7 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
|
|||||||
struct db_media_file_info dbmfi;
|
struct db_media_file_info dbmfi;
|
||||||
struct evbuffer *song;
|
struct evbuffer *song;
|
||||||
struct evbuffer *songlist;
|
struct evbuffer *songlist;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const struct dmap_field **meta;
|
const struct dmap_field **meta;
|
||||||
struct sort_ctx *sctx;
|
struct sort_ctx *sctx;
|
||||||
const char *param;
|
const char *param;
|
||||||
@ -1244,7 +1260,8 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
|
|||||||
{
|
{
|
||||||
nsongs++;
|
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);
|
ret = dmap_encode_file_metadata(songlist, song, &dbmfi, meta, nmeta, sort_headers, transcode);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -2121,6 +2138,7 @@ daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char *
|
|||||||
{
|
{
|
||||||
char clen[32];
|
char clen[32];
|
||||||
struct daap_session *s;
|
struct daap_session *s;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *param;
|
const char *param;
|
||||||
char *ctype;
|
char *ctype;
|
||||||
int id;
|
int id;
|
||||||
@ -2191,10 +2209,11 @@ daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char *
|
|||||||
goto no_artwork;
|
goto no_artwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_remove_header(req->output_headers, "Content-Type");
|
headers = evhttp_request_get_output_headers(req);
|
||||||
evhttp_add_header(req->output_headers, "Content-Type", ctype);
|
evhttp_remove_header(headers, "Content-Type");
|
||||||
|
evhttp_add_header(headers, "Content-Type", ctype);
|
||||||
snprintf(clen, sizeof(clen), "%ld", (long)EVBUFFER_LENGTH(evbuf));
|
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 */
|
/* No gzip compression for artwork */
|
||||||
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
|
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
|
||||||
@ -2435,6 +2454,7 @@ daap_request(struct evhttp_request *req)
|
|||||||
char *uri_parts[7];
|
char *uri_parts[7];
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
struct evkeyvalq query;
|
struct evkeyvalq query;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *ua;
|
const char *ua;
|
||||||
cfg_t *lib;
|
cfg_t *lib;
|
||||||
char *libname;
|
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
|
* valid session-id that Remote can only obtain if its pairing-guid is in
|
||||||
* our database. So HTTP authentication is waived for Remote.
|
* 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))
|
if ((ua) && (strncmp(ua, "Remote", strlen("Remote")) == 0))
|
||||||
passwd = NULL;
|
passwd = NULL;
|
||||||
|
|
||||||
@ -2587,13 +2608,14 @@ daap_request(struct evhttp_request *req)
|
|||||||
|
|
||||||
evhttp_parse_query(full_uri, &query);
|
evhttp_parse_query(full_uri, &query);
|
||||||
|
|
||||||
evhttp_add_header(req->output_headers, "Accept-Ranges", "bytes");
|
headers = evhttp_request_get_output_headers(req);
|
||||||
evhttp_add_header(req->output_headers, "DAAP-Server", "forked-daapd/" VERSION);
|
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
|
/* Content-Type for all replies, even the actual audio streaming. Note that
|
||||||
* video streaming will override this Content-Type with a more appropriate
|
* video streaming will override this Content-Type with a more appropriate
|
||||||
* video/<type> Content-Type as expected by clients like Front Row.
|
* 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);
|
daap_handlers[handler].handler(req, evbuf, uri_parts, &query);
|
||||||
|
|
||||||
@ -2679,6 +2701,7 @@ void
|
|||||||
daap_deinit(void)
|
daap_deinit(void)
|
||||||
{
|
{
|
||||||
struct daap_update_request *ur;
|
struct daap_update_request *ur;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; daap_handlers[i].handler; i++)
|
for (i = 0; daap_handlers[i].handler; i++)
|
||||||
@ -2690,10 +2713,11 @@ daap_deinit(void)
|
|||||||
{
|
{
|
||||||
update_requests = ur->next;
|
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_set_closecb(evcon, NULL, NULL);
|
||||||
evhttp_connection_free(ur->req->evcon);
|
evhttp_connection_free(evcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_free(ur);
|
update_free(ur);
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
|
||||||
|
|
||||||
/* httpd event base, from httpd.c */
|
/* httpd event base, from httpd.c */
|
||||||
extern struct event_base *evbase_httpd;
|
extern struct event_base *evbase_httpd;
|
||||||
|
|
||||||
@ -268,6 +267,7 @@ playstatusupdate_cb(int fd, short what, void *arg)
|
|||||||
struct dacp_update_request *ur;
|
struct dacp_update_request *ur;
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
struct evbuffer *update;
|
struct evbuffer *update;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef USE_EVENTFD
|
#ifdef USE_EVENTFD
|
||||||
@ -313,7 +313,9 @@ playstatusupdate_cb(int fd, short what, void *arg)
|
|||||||
{
|
{
|
||||||
update_requests = ur->next;
|
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));
|
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 *ur;
|
||||||
struct dacp_update_request *p;
|
struct dacp_update_request *p;
|
||||||
|
struct evhttp_connection *evc;
|
||||||
|
|
||||||
ur = (struct dacp_update_request *)arg;
|
ur = (struct dacp_update_request *)arg;
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_DACP, "Update request: client closed connection\n");
|
DPRINTF(E_DBG, L_DACP, "Update request: client closed connection\n");
|
||||||
|
|
||||||
if (ur->req->evcon)
|
evc = evhttp_request_get_connection(ur->req);
|
||||||
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
|
if (evc)
|
||||||
|
evhttp_connection_set_closecb(evc, NULL, NULL);
|
||||||
|
|
||||||
if (ur == update_requests)
|
if (ur == update_requests)
|
||||||
update_requests = ur->next;
|
update_requests = ur->next;
|
||||||
@ -1678,6 +1682,7 @@ dacp_reply_playstatusupdate(struct evhttp_request *req, struct evbuffer *evbuf,
|
|||||||
{
|
{
|
||||||
struct daap_session *s;
|
struct daap_session *s;
|
||||||
struct dacp_update_request *ur;
|
struct dacp_update_request *ur;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
const char *param;
|
const char *param;
|
||||||
int reqd_rev;
|
int reqd_rev;
|
||||||
int ret;
|
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
|
/* If the connection fails before we have an update to push out
|
||||||
* to the client, we need to know.
|
* 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
|
static void
|
||||||
@ -1741,6 +1748,7 @@ dacp_reply_nowplayingartwork(struct evhttp_request *req, struct evbuffer *evbuf,
|
|||||||
{
|
{
|
||||||
char clen[32];
|
char clen[32];
|
||||||
struct daap_session *s;
|
struct daap_session *s;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *param;
|
const char *param;
|
||||||
char *ctype;
|
char *ctype;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
@ -1810,10 +1818,11 @@ dacp_reply_nowplayingartwork(struct evhttp_request *req, struct evbuffer *evbuf,
|
|||||||
goto no_artwork;
|
goto no_artwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_remove_header(req->output_headers, "Content-Type");
|
headers = evhttp_request_get_output_headers(req);
|
||||||
evhttp_add_header(req->output_headers, "Content-Type", ctype);
|
evhttp_remove_header(headers, "Content-Type");
|
||||||
|
evhttp_add_header(headers, "Content-Type", ctype);
|
||||||
snprintf(clen, sizeof(clen), "%ld", (long)EVBUFFER_LENGTH(evbuf));
|
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 */
|
/* No gzip compression for artwork */
|
||||||
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
|
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
|
||||||
@ -2216,6 +2225,7 @@ dacp_request(struct evhttp_request *req)
|
|||||||
char *uri_parts[7];
|
char *uri_parts[7];
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
struct evkeyvalq query;
|
struct evkeyvalq query;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
int handler;
|
int handler;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
@ -2307,9 +2317,10 @@ dacp_request(struct evhttp_request *req)
|
|||||||
|
|
||||||
evhttp_parse_query(full_uri, &query);
|
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 */
|
/* 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);
|
dacp_handlers[handler].handler(req, evbuf, uri_parts, &query);
|
||||||
|
|
||||||
@ -2401,6 +2412,7 @@ void
|
|||||||
dacp_deinit(void)
|
dacp_deinit(void)
|
||||||
{
|
{
|
||||||
struct dacp_update_request *ur;
|
struct dacp_update_request *ur;
|
||||||
|
struct evhttp_connection *evcon;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
player_set_update_handler(NULL);
|
player_set_update_handler(NULL);
|
||||||
@ -2412,10 +2424,11 @@ dacp_deinit(void)
|
|||||||
{
|
{
|
||||||
update_requests = ur->next;
|
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_set_closecb(evcon, NULL, NULL);
|
||||||
evhttp_connection_free(ur->req->evcon);
|
evhttp_connection_free(evcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ur);
|
free(ur);
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
#include "httpd_rsp.h"
|
#include "httpd_rsp.h"
|
||||||
#include "rsp_query.h"
|
#include "rsp_query.h"
|
||||||
|
|
||||||
|
|
||||||
#define RSP_VERSION "1.0"
|
#define RSP_VERSION "1.0"
|
||||||
#define RSP_XML_ROOT "?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?"
|
#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)
|
rsp_send_error(struct evhttp_request *req, char *errmsg)
|
||||||
{
|
{
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
mxml_node_t *reply;
|
mxml_node_t *reply;
|
||||||
mxml_node_t *status;
|
mxml_node_t *status;
|
||||||
mxml_node_t *node;
|
mxml_node_t *node;
|
||||||
@ -254,8 +254,9 @@ rsp_send_error(struct evhttp_request *req, char *errmsg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=utf-8");
|
headers = evhttp_request_get_output_headers(req);
|
||||||
evhttp_add_header(req->output_headers, "Connection", "close");
|
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);
|
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
|
||||||
|
|
||||||
evbuffer_free(evbuf);
|
evbuffer_free(evbuf);
|
||||||
@ -265,6 +266,7 @@ static void
|
|||||||
rsp_send_reply(struct evhttp_request *req, mxml_node_t *reply)
|
rsp_send_reply(struct evhttp_request *req, mxml_node_t *reply)
|
||||||
{
|
{
|
||||||
struct evbuffer *evbuf;
|
struct evbuffer *evbuf;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
|
|
||||||
evbuf = mxml_to_evbuf(reply);
|
evbuf = mxml_to_evbuf(reply);
|
||||||
mxmlDelete(reply);
|
mxmlDelete(reply);
|
||||||
@ -276,8 +278,9 @@ rsp_send_reply(struct evhttp_request *req, mxml_node_t *reply)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=utf-8");
|
headers = evhttp_request_get_output_headers(req);
|
||||||
evhttp_add_header(req->output_headers, "Connection", "close");
|
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);
|
httpd_send_reply(req, HTTP_OK, "OK", evbuf);
|
||||||
|
|
||||||
evbuffer_free(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 query_params qp;
|
||||||
struct db_media_file_info dbmfi;
|
struct db_media_file_info dbmfi;
|
||||||
|
struct evkeyvalq *headers;
|
||||||
const char *param;
|
const char *param;
|
||||||
char **strval;
|
char **strval;
|
||||||
mxml_node_t *reply;
|
mxml_node_t *reply;
|
||||||
@ -526,7 +530,8 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
|
|||||||
/* Items block (all items) */
|
/* Items block (all items) */
|
||||||
while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
|
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 block (one item) */
|
||||||
item = mxmlNewElement(items, "item");
|
item = mxmlNewElement(items, "item");
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -48,9 +48,9 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
@ -414,8 +414,10 @@ static void
|
|||||||
pairing_request_cb(struct evhttp_request *req, void *arg)
|
pairing_request_cb(struct evhttp_request *req, void *arg)
|
||||||
{
|
{
|
||||||
struct remote_info *ri;
|
struct remote_info *ri;
|
||||||
|
struct evbuffer *input_buffer;
|
||||||
uint8_t *response;
|
uint8_t *response;
|
||||||
char guid[17];
|
char guid[17];
|
||||||
|
int response_code;
|
||||||
int len;
|
int len;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
@ -429,21 +431,24 @@ pairing_request_cb(struct evhttp_request *req, void *arg)
|
|||||||
goto cleanup;
|
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;
|
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);
|
DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response too short\n", ri->pi.remote_id, ri->pi.name);
|
||||||
|
|
||||||
goto cleanup;
|
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'))
|
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]);
|
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",
|
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;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -536,7 +541,7 @@ send_pairing_request(struct remote_info *ri, char *req_uri, int family)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
evcon = evhttp_connection_new(address, port);
|
evcon = evhttp_connection_base_new(evbase_main, NULL, address, port);
|
||||||
if (!evcon)
|
if (!evcon)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_REMOTE, "Could not create connection for pairing with %s\n", ri->pi.name);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_connection_set_base(evcon, evbase_main);
|
|
||||||
|
|
||||||
req = evhttp_request_new(pairing_request_cb, ri);
|
req = evhttp_request_new(pairing_request_cb, ri);
|
||||||
if (!req)
|
if (!req)
|
||||||
{
|
{
|
||||||
@ -883,7 +886,7 @@ remote_pairing_read_pin(char *path)
|
|||||||
return;
|
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);
|
pthread_mutex_lock(&remote_lck);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#ifdef HAVE_LIBEVENT2
|
#ifdef HAVE_LIBEVENT2
|
||||||
# include <evhttp.h>
|
# include <event2/http.h>
|
||||||
#else
|
#else
|
||||||
# include "evhttp/evhttp.h"
|
# include "evhttp/evhttp.h"
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user