mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-28 08:05:56 -05:00
Merge pull request #1398 from owntone/coverity_issues
Fixes for misc minor issues reported by Coverity
This commit is contained in:
commit
119eb46daa
@ -851,7 +851,13 @@ parent_dir_image_find(char *out_path, size_t len, const char *dir)
|
||||
DPRINTF(E_LOG, L_ART, "Could not find parent dir name (%s)\n", path);
|
||||
return -1;
|
||||
}
|
||||
strcpy(parentdir, ptr + 1);
|
||||
|
||||
ret = snprintf(parentdir, sizeof(parentdir), "%s", ptr + 1);
|
||||
if ((ret < 0) || (ret >= sizeof(parentdir)))
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "Impossible error occured in parent_dir_image_find(), cause was: %s\n", ptr + 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
path_len = strlen(path);
|
||||
nextensions = ARRAY_SIZE(cover_extension);
|
||||
|
@ -88,22 +88,21 @@ command_cb_sync(struct commands_base *cmdbase, struct command *cmd)
|
||||
// Command execution is waiting for pending events before returning to the caller
|
||||
cmdbase->current_cmd = cmd;
|
||||
cmd->pending = cmd->ret;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Command execution finished, execute the bottom half function
|
||||
if (cmd->ret == 0 && cmd->func_bh)
|
||||
cmd->func_bh(cmd->arg, &cmd->ret);
|
||||
|
||||
event_add(cmdbase->command_event, NULL);
|
||||
// Command execution finished, execute the bottom half function
|
||||
if (cmd->ret == 0 && cmd->func_bh)
|
||||
cmd->func_bh(cmd->arg, &cmd->ret);
|
||||
|
||||
// Signal the calling thread that the command execution finished
|
||||
CHECK_ERR(L_MAIN, pthread_cond_signal(&cmd->cond));
|
||||
CHECK_ERR(L_MAIN, pthread_mutex_unlock(&cmd->lck));
|
||||
event_add(cmdbase->command_event, NULL);
|
||||
|
||||
// Note if cmd->func was cmdloop_exit then cmdbase may be invalid now,
|
||||
// because commands_base_destroy() may have freed it
|
||||
}
|
||||
// Signal the calling thread that the command execution finished
|
||||
CHECK_ERR(L_MAIN, pthread_cond_signal(&cmd->cond));
|
||||
CHECK_ERR(L_MAIN, pthread_mutex_unlock(&cmd->lck));
|
||||
|
||||
// Note if cmd->func was cmdloop_exit then cmdbase may be invalid now,
|
||||
// because commands_base_destroy() may have freed it
|
||||
}
|
||||
|
||||
/*
|
||||
@ -357,7 +356,7 @@ commands_exec_async(struct commands_base *cmdbase, command_function func, void *
|
||||
struct command *cmd;
|
||||
int ret;
|
||||
|
||||
cmd = calloc(1, sizeof(struct command));
|
||||
CHECK_NULL(L_MAIN, cmd = calloc(1, sizeof(struct command)));
|
||||
cmd->func = func;
|
||||
cmd->func_bh = NULL;
|
||||
cmd->arg = arg;
|
||||
|
95
src/db.c
95
src/db.c
@ -775,6 +775,20 @@ free_di(struct directory_info *di, int content_only)
|
||||
memset(di, 0, sizeof(struct directory_info));
|
||||
}
|
||||
|
||||
void
|
||||
free_wi(struct watch_info *wi, int content_only)
|
||||
{
|
||||
if (!wi)
|
||||
return;
|
||||
|
||||
free(wi->path);
|
||||
|
||||
if (!content_only)
|
||||
free(wi);
|
||||
else
|
||||
memset(wi, 0, sizeof(struct watch_info));
|
||||
}
|
||||
|
||||
void
|
||||
free_query_params(struct query_params *qp, int content_only)
|
||||
{
|
||||
@ -2682,8 +2696,8 @@ db_query_fetch_string_sort(char **string, char **sortstring, struct query_params
|
||||
int
|
||||
db_files_get_count(uint32_t *nitems, uint32_t *nstreams, const char *filter)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
char *query;
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
char *query = NULL;
|
||||
int ret;
|
||||
|
||||
if (!filter && !nstreams)
|
||||
@ -2698,17 +2712,16 @@ db_files_get_count(uint32_t *nitems, uint32_t *nstreams, const char *filter)
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
|
||||
ret = db_blocking_prepare_v2(query, -1, &stmt, NULL);
|
||||
sqlite3_free(query);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = db_blocking_step(stmt);
|
||||
@ -2719,8 +2732,7 @@ db_files_get_count(uint32_t *nitems, uint32_t *nstreams, const char *filter)
|
||||
else
|
||||
DPRINTF(E_LOG, L_DB, "Could not step: %s (%s)\n", sqlite3_errmsg(hdl), query);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (nitems)
|
||||
@ -2733,9 +2745,16 @@ db_files_get_count(uint32_t *nitems, uint32_t *nstreams, const char *filter)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_free(query);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (query)
|
||||
sqlite3_free(query);
|
||||
if (stmt)
|
||||
sqlite3_finalize(stmt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -6059,10 +6078,10 @@ queue_reshuffle(uint32_t item_id, int queue_version)
|
||||
int pos;
|
||||
uint32_t count;
|
||||
struct db_queue_item queue_item;
|
||||
int *shuffle_pos;
|
||||
int *shuffle_pos = NULL;
|
||||
int len;
|
||||
int i;
|
||||
struct query_params qp;
|
||||
struct query_params qp = { 0 };
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Reshuffle queue after item with item-id: %d\n", item_id);
|
||||
@ -6071,43 +6090,39 @@ queue_reshuffle(uint32_t item_id, int queue_version)
|
||||
query = sqlite3_mprintf("UPDATE queue SET shuffle_pos = pos, queue_version = %d;", queue_version);
|
||||
ret = db_query_run(query, 1, 0);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
goto error;
|
||||
|
||||
pos = 0;
|
||||
if (item_id > 0)
|
||||
{
|
||||
pos = db_queue_get_pos(item_id, 0);
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
goto error;
|
||||
|
||||
pos++; // Do not reshuffle the base item
|
||||
}
|
||||
|
||||
ret = db_queue_get_count(&count);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
goto error;
|
||||
|
||||
len = count - pos;
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Reshuffle %d items off %" PRIu32 " total items, starting from pos %d\n", len, count, pos);
|
||||
|
||||
shuffle_pos = malloc(len * sizeof(int));
|
||||
CHECK_NULL(L_DB, shuffle_pos = malloc(len * sizeof(int)));
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
shuffle_pos[i] = i + pos;
|
||||
}
|
||||
|
||||
shuffle_int(&shuffle_rng, shuffle_pos, len);
|
||||
rng_shuffle_int(&shuffle_rng, shuffle_pos, len);
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
qp.filter = sqlite3_mprintf("pos >= %d", pos);
|
||||
|
||||
ret = queue_enum_start(&qp);
|
||||
if (ret < 0)
|
||||
{
|
||||
sqlite3_free(qp.filter);
|
||||
return -1;
|
||||
}
|
||||
goto error;
|
||||
|
||||
i = 0;
|
||||
while ((ret = queue_enum_fetch(&qp, &queue_item, 0)) == 0 && (queue_item.id > 0) && (i < len))
|
||||
@ -6124,12 +6139,18 @@ queue_reshuffle(uint32_t item_id, int queue_version)
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
goto error;
|
||||
|
||||
sqlite3_free(qp.filter);
|
||||
free(shuffle_pos);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
sqlite3_free(qp.filter);
|
||||
free(shuffle_pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -6216,7 +6237,7 @@ db_watch_delete_bywd(uint32_t wd)
|
||||
}
|
||||
|
||||
int
|
||||
db_watch_delete_bypath(char *path)
|
||||
db_watch_delete_bypath(const char *path)
|
||||
{
|
||||
#define Q_TMPL "DELETE FROM inotify WHERE path = '%q';"
|
||||
char *query;
|
||||
@ -6228,7 +6249,7 @@ db_watch_delete_bypath(char *path)
|
||||
}
|
||||
|
||||
int
|
||||
db_watch_delete_bymatch(char *path)
|
||||
db_watch_delete_bymatch(const char *path)
|
||||
{
|
||||
#define Q_TMPL "DELETE FROM inotify WHERE path LIKE '%q/%%';"
|
||||
char *query;
|
||||
@ -6316,12 +6337,12 @@ db_watch_get_byquery(struct watch_info *wi, char *query)
|
||||
}
|
||||
|
||||
int
|
||||
db_watch_get_bywd(struct watch_info *wi)
|
||||
db_watch_get_bywd(struct watch_info *wi, int wd)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM inotify WHERE wd = %d;"
|
||||
char *query;
|
||||
|
||||
query = sqlite3_mprintf(Q_TMPL, wi->wd);
|
||||
query = sqlite3_mprintf(Q_TMPL, wd);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
@ -6333,12 +6354,12 @@ db_watch_get_bywd(struct watch_info *wi)
|
||||
}
|
||||
|
||||
int
|
||||
db_watch_get_bypath(struct watch_info *wi)
|
||||
db_watch_get_bypath(struct watch_info *wi, const char *path)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM inotify WHERE path = '%q';"
|
||||
char *query;
|
||||
|
||||
query = sqlite3_mprintf(Q_TMPL, wi->path);
|
||||
query = sqlite3_mprintf(Q_TMPL, path);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
@ -6350,7 +6371,7 @@ db_watch_get_bypath(struct watch_info *wi)
|
||||
}
|
||||
|
||||
void
|
||||
db_watch_mark_bypath(char *path, enum strip_type strip, uint32_t cookie)
|
||||
db_watch_mark_bypath(const char *path, enum strip_type strip, uint32_t cookie)
|
||||
{
|
||||
#define Q_TMPL "UPDATE inotify SET path = substr(path, %d), cookie = %" PRIi64 " WHERE path = '%q';"
|
||||
char *query;
|
||||
@ -6368,7 +6389,7 @@ db_watch_mark_bypath(char *path, enum strip_type strip, uint32_t cookie)
|
||||
}
|
||||
|
||||
void
|
||||
db_watch_mark_bymatch(char *path, enum strip_type strip, uint32_t cookie)
|
||||
db_watch_mark_bymatch(const char *path, enum strip_type strip, uint32_t cookie)
|
||||
{
|
||||
#define Q_TMPL "UPDATE inotify SET path = substr(path, %d), cookie = %" PRIi64 " WHERE path LIKE '%q/%%';"
|
||||
char *query;
|
||||
@ -6386,7 +6407,7 @@ db_watch_mark_bymatch(char *path, enum strip_type strip, uint32_t cookie)
|
||||
}
|
||||
|
||||
void
|
||||
db_watch_move_bycookie(uint32_t cookie, char *path)
|
||||
db_watch_move_bycookie(uint32_t cookie, const char *path)
|
||||
{
|
||||
#define Q_TMPL "UPDATE inotify SET path = '%q' || path, cookie = 0 WHERE cookie = %" PRIi64 ";"
|
||||
char *query;
|
||||
@ -6611,8 +6632,6 @@ db_pragma_get_cache_size()
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -6620,13 +6639,11 @@ db_pragma_get_cache_size()
|
||||
if (ret == SQLITE_DONE)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "End of query results\n");
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_ROW)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -6717,8 +6734,6 @@ db_pragma_get_synchronous()
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -6726,13 +6741,11 @@ db_pragma_get_synchronous()
|
||||
if (ret == SQLITE_DONE)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "End of query results\n");
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_ROW)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -6781,8 +6794,6 @@ db_pragma_get_mmap_size()
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -6790,13 +6801,11 @@ db_pragma_get_mmap_size()
|
||||
if (ret == SQLITE_DONE)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "End of query results\n");
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_ROW)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
17
src/db.h
17
src/db.h
@ -573,6 +573,9 @@ free_pli(struct playlist_info *pli, int content_only);
|
||||
void
|
||||
free_di(struct directory_info *di, int content_only);
|
||||
|
||||
void
|
||||
free_wi(struct watch_info *wi, int content_only);
|
||||
|
||||
void
|
||||
free_query_params(struct query_params *qp, int content_only);
|
||||
|
||||
@ -960,28 +963,28 @@ int
|
||||
db_watch_delete_bywd(uint32_t wd);
|
||||
|
||||
int
|
||||
db_watch_delete_bypath(char *path);
|
||||
db_watch_delete_bypath(const char *path);
|
||||
|
||||
int
|
||||
db_watch_delete_bymatch(char *path);
|
||||
db_watch_delete_bymatch(const char *path);
|
||||
|
||||
int
|
||||
db_watch_delete_bycookie(uint32_t cookie);
|
||||
|
||||
int
|
||||
db_watch_get_bywd(struct watch_info *wi);
|
||||
db_watch_get_bywd(struct watch_info *wi, int wd);
|
||||
|
||||
int
|
||||
db_watch_get_bypath(struct watch_info *wi);
|
||||
db_watch_get_bypath(struct watch_info *wi, const char *path);
|
||||
|
||||
void
|
||||
db_watch_mark_bypath(char *path, enum strip_type strip, uint32_t cookie);
|
||||
db_watch_mark_bypath(const char *path, enum strip_type strip, uint32_t cookie);
|
||||
|
||||
void
|
||||
db_watch_mark_bymatch(char *path, enum strip_type strip, uint32_t cookie);
|
||||
db_watch_mark_bymatch(const char *path, enum strip_type strip, uint32_t cookie);
|
||||
|
||||
void
|
||||
db_watch_move_bycookie(uint32_t cookie, char *path);
|
||||
db_watch_move_bycookie(uint32_t cookie, const char *path);
|
||||
|
||||
int
|
||||
db_watch_cookie_known(uint32_t cookie);
|
||||
|
@ -1702,13 +1702,23 @@ bind_socket_ai(int family, struct addrinfo *ai, int reuse)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (family == AF_INET6)
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
|
||||
if (family == AF_INET6) {
|
||||
r = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
|
||||
if (r == -1) {
|
||||
event_warn("IPV6_V6ONLY");
|
||||
}
|
||||
}
|
||||
|
||||
r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
|
||||
if (r == -1) {
|
||||
event_warn("SO_KEEPALIVE");
|
||||
}
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
|
||||
if (reuse) {
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(void *)&on, sizeof(on));
|
||||
r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
|
||||
if (r == -1) {
|
||||
event_warn("SO_REUSEADDR");
|
||||
}
|
||||
}
|
||||
|
||||
if (ai != NULL) {
|
||||
|
11
src/httpd.c
11
src/httpd.c
@ -1310,9 +1310,10 @@ httpd_stream_file(struct evhttp_request *req, int id)
|
||||
if (!transcode)
|
||||
{
|
||||
/* Hint the OS */
|
||||
posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_WILLNEED);
|
||||
posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_SEQUENTIAL);
|
||||
posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_NOREUSE);
|
||||
if ( (ret = posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_WILLNEED)) != 0 ||
|
||||
(ret = posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_SEQUENTIAL)) != 0 ||
|
||||
(ret = posix_fadvise(st->fd, st->start_offset, st->stream_size, POSIX_FADV_NOREUSE)) != 0 )
|
||||
DPRINTF(E_DBG, L_HTTPD, "posix_fadvise() failed with error %d\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1353,6 +1354,10 @@ httpd_gzip_deflate(struct evbuffer *in)
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
// Just to keep Coverity from complaining about uninitialized values
|
||||
strm.total_in = 0;
|
||||
strm.total_out = 0;
|
||||
|
||||
// Set up a gzip stream (the "+ 16" in 15 + 16), instead of a zlib stream (default)
|
||||
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
|
||||
if (ret != Z_OK)
|
||||
|
@ -136,9 +136,6 @@ static struct timeval daap_update_refresh_tv = { DAAP_UPDATE_REFRESH, 0 };
|
||||
static void
|
||||
daap_session_free(struct daap_session *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
@ -637,7 +634,7 @@ parse_meta(const struct dmap_field ***out_meta, const char *param)
|
||||
CHECK_NULL(L_DAAP, meta = calloc(nmeta, sizeof(const struct dmap_field *)));
|
||||
|
||||
field = strtok_r(metastr, ",", &ptr);
|
||||
for (i = 0; i < nmeta; i++)
|
||||
for (i = 0; field != NULL && i < nmeta; i++)
|
||||
{
|
||||
for (n = 0; (n < i) && (strcmp(field, meta[n]->desc) != 0); n++);
|
||||
|
||||
@ -662,8 +659,6 @@ parse_meta(const struct dmap_field ***out_meta, const char *param)
|
||||
}
|
||||
|
||||
field = strtok_r(NULL, ",", &ptr);
|
||||
if (!field)
|
||||
break;
|
||||
}
|
||||
|
||||
free(metastr);
|
||||
@ -1185,14 +1180,14 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||
struct evbuffer *songlist;
|
||||
struct evkeyvalq *headers;
|
||||
struct daap_session *s;
|
||||
const struct dmap_field **meta;
|
||||
const struct dmap_field **meta = NULL;
|
||||
struct sort_ctx *sctx;
|
||||
const char *param;
|
||||
const char *client_codecs;
|
||||
const char *tag;
|
||||
char *last_codectype;
|
||||
size_t len;
|
||||
int nmeta;
|
||||
int nmeta = 0;
|
||||
int sort_headers;
|
||||
int nsongs;
|
||||
int transcode;
|
||||
@ -1246,18 +1241,12 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
meta = NULL;
|
||||
nmeta = 0;
|
||||
}
|
||||
|
||||
ret = db_query_start(&qp);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not start query\n");
|
||||
|
||||
free(meta);
|
||||
dmap_error_make(hreq->reply, tag, "Could not start query");
|
||||
goto error;
|
||||
}
|
||||
@ -1320,7 +1309,6 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||
DPRINTF(E_DBG, L_DAAP, "Done with song list, %d songs\n", nsongs);
|
||||
|
||||
free(last_codectype);
|
||||
free(meta);
|
||||
db_query_end(&qp);
|
||||
|
||||
if (ret == -100)
|
||||
@ -1361,6 +1349,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||
CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, sctx->headerlist));
|
||||
}
|
||||
|
||||
free(meta);
|
||||
daap_sort_context_free(sctx);
|
||||
evbuffer_free(song);
|
||||
evbuffer_free(songlist);
|
||||
@ -1369,6 +1358,7 @@ daap_reply_songlist_generic(struct httpd_request *hreq, int playlist)
|
||||
return DAAP_REPLY_OK;
|
||||
|
||||
error:
|
||||
free(meta);
|
||||
daap_sort_context_free(sctx);
|
||||
evbuffer_free(song);
|
||||
evbuffer_free(songlist);
|
||||
@ -1417,7 +1407,7 @@ daap_reply_playlists(struct httpd_request *hreq)
|
||||
struct evbuffer *playlist;
|
||||
const struct dmap_field_map *dfm;
|
||||
const struct dmap_field *df;
|
||||
const struct dmap_field **meta;
|
||||
const struct dmap_field **meta = NULL;
|
||||
const char *param;
|
||||
char **strval;
|
||||
size_t len;
|
||||
@ -1473,7 +1463,6 @@ daap_reply_playlists(struct httpd_request *hreq)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not start query\n");
|
||||
|
||||
free(meta);
|
||||
dmap_error_make(hreq->reply, "aply", "Could not start query");
|
||||
goto error;
|
||||
}
|
||||
@ -1585,7 +1574,6 @@ daap_reply_playlists(struct httpd_request *hreq)
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
free(meta);
|
||||
|
||||
DPRINTF(E_DBG, L_DAAP, "Done with playlist list, %d playlists\n", npls);
|
||||
|
||||
@ -1612,6 +1600,7 @@ daap_reply_playlists(struct httpd_request *hreq)
|
||||
|
||||
CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, playlistlist));
|
||||
|
||||
free(meta);
|
||||
evbuffer_free(playlist);
|
||||
evbuffer_free(playlistlist);
|
||||
free_query_params(&qp, 1);
|
||||
@ -1619,6 +1608,7 @@ daap_reply_playlists(struct httpd_request *hreq)
|
||||
return DAAP_REPLY_OK;
|
||||
|
||||
error:
|
||||
free(meta);
|
||||
evbuffer_free(playlist);
|
||||
evbuffer_free(playlistlist);
|
||||
free_query_params(&qp, 1);
|
||||
@ -1635,7 +1625,7 @@ daap_reply_groups(struct httpd_request *hreq)
|
||||
struct evbuffer *grouplist;
|
||||
const struct dmap_field_map *dfm;
|
||||
const struct dmap_field *df;
|
||||
const struct dmap_field **meta;
|
||||
const struct dmap_field **meta = NULL;
|
||||
struct sort_ctx *sctx;
|
||||
cfg_t *lib;
|
||||
const char *param;
|
||||
@ -1699,7 +1689,6 @@ daap_reply_groups(struct httpd_request *hreq)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not start query\n");
|
||||
|
||||
free(meta);
|
||||
dmap_error_make(hreq->reply, tag, "Could not start query");
|
||||
goto error;
|
||||
}
|
||||
@ -1787,7 +1776,6 @@ daap_reply_groups(struct httpd_request *hreq)
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
free(meta);
|
||||
|
||||
DPRINTF(E_DBG, L_DAAP, "Done with group list, %d groups\n", ngrp);
|
||||
|
||||
@ -1829,6 +1817,7 @@ daap_reply_groups(struct httpd_request *hreq)
|
||||
CHECK_ERR(L_DAAP, evbuffer_add_buffer(hreq->reply, sctx->headerlist));
|
||||
}
|
||||
|
||||
free(meta);
|
||||
daap_sort_context_free(sctx);
|
||||
evbuffer_free(group);
|
||||
evbuffer_free(grouplist);
|
||||
@ -1837,6 +1826,7 @@ daap_reply_groups(struct httpd_request *hreq)
|
||||
return DAAP_REPLY_OK;
|
||||
|
||||
error:
|
||||
free(meta);
|
||||
daap_sort_context_free(sctx);
|
||||
evbuffer_free(group);
|
||||
evbuffer_free(grouplist);
|
||||
|
@ -1410,7 +1410,12 @@ dacp_reply_play(struct httpd_request *hreq)
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
player_playback_start();
|
||||
ret = player_playback_start();
|
||||
if (ret < 0)
|
||||
{
|
||||
httpd_send_error(hreq->req, 500, "Internal Server Error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 204 No Content is the canonical reply */
|
||||
httpd_send_reply(hreq->req, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP);
|
||||
@ -2731,10 +2736,12 @@ dacp_reply_mutetoggle(struct httpd_request *hreq)
|
||||
}
|
||||
|
||||
// We don't actually mute, because the player doesn't currently support unmuting
|
||||
if (speaker_info.selected)
|
||||
player_speaker_disable(speaker_info.id);
|
||||
else
|
||||
player_speaker_enable(speaker_info.id);
|
||||
ret = speaker_info.selected ? player_speaker_disable(speaker_info.id) : player_speaker_enable(speaker_info.id);
|
||||
if (ret < 0)
|
||||
{
|
||||
httpd_send_error(hreq->req, 500, "Internal Server Error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 204 No Content is the canonical reply */
|
||||
httpd_send_reply(hreq->req, HTTP_NOCONTENT, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP);
|
||||
|
@ -1829,7 +1829,7 @@ jsonapi_reply_outputs_set(struct httpd_request *hreq)
|
||||
{
|
||||
nspk = json_object_array_length(outputs);
|
||||
|
||||
ids = calloc((nspk + 1), sizeof(uint64_t));
|
||||
CHECK_NULL(L_WEB, ids = calloc((nspk + 1), sizeof(uint64_t)));
|
||||
ids[0] = nspk;
|
||||
|
||||
ret = 0;
|
||||
@ -2502,8 +2502,8 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
||||
const char *param_uris;
|
||||
const char *param_expression;
|
||||
const char *param;
|
||||
int pos = -1;
|
||||
int limit = -1;
|
||||
int pos;
|
||||
int limit;
|
||||
bool shuffle;
|
||||
int total_count = 0;
|
||||
json_object *reply;
|
||||
@ -2522,6 +2522,8 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
||||
|
||||
DPRINTF(E_DBG, L_WEB, "Add tracks starting at position '%d\n", pos);
|
||||
}
|
||||
else
|
||||
pos = -1;
|
||||
|
||||
param_uris = evhttp_find_header(hreq->query, "uris");
|
||||
param_expression = evhttp_find_header(hreq->query, "expression");
|
||||
@ -2557,9 +2559,10 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
||||
{
|
||||
// This overrides the value specified in query
|
||||
param = evhttp_find_header(hreq->query, "limit");
|
||||
if (param)
|
||||
safe_atoi32(param, &limit);
|
||||
ret = queue_tracks_add_byexpression(param_expression, pos, limit, &total_count);
|
||||
if (param && safe_atoi32(param, &limit) == 0)
|
||||
ret = queue_tracks_add_byexpression(param_expression, pos, limit, &total_count);
|
||||
else
|
||||
ret = queue_tracks_add_byexpression(param_expression, pos, -1, &total_count);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
@ -2579,9 +2582,12 @@ jsonapi_reply_queue_tracks_add(struct httpd_request *hreq)
|
||||
if (param && strcmp(param, "start") == 0)
|
||||
{
|
||||
if ((param = evhttp_find_header(hreq->query, "playback_from_position")))
|
||||
play_item_at_position(param);
|
||||
ret = (play_item_at_position(param) == HTTP_NOCONTENT) ? 0 : -1;
|
||||
else
|
||||
player_playback_start();
|
||||
ret = player_playback_start();
|
||||
|
||||
if (ret < 0)
|
||||
return HTTP_INTERNAL;
|
||||
}
|
||||
|
||||
return HTTP_OK;
|
||||
@ -2610,10 +2616,11 @@ update_pos(uint32_t item_id, const char *new, char shuffle)
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_str(char **str, const char *new)
|
||||
update_str(bool *is_changed, char **str, const char *new)
|
||||
{
|
||||
free(*str);
|
||||
*str = strdup(new);
|
||||
*is_changed = true;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2629,11 +2636,19 @@ jsonapi_reply_queue_tracks_update(struct httpd_request *hreq)
|
||||
player_get_status(&status);
|
||||
|
||||
if (strcmp(hreq->uri_parsed->path_parts[3], "now_playing") != 0)
|
||||
safe_atou32(hreq->uri_parsed->path_parts[3], &item_id);
|
||||
{
|
||||
ret = safe_atou32(hreq->uri_parsed->path_parts[3], &item_id);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "No valid item id given: '%s'\n", hreq->uri_parsed->path);
|
||||
return HTTP_BADREQUEST;
|
||||
}
|
||||
}
|
||||
else
|
||||
item_id = status.item_id;
|
||||
|
||||
if (!item_id || !(queue_item = db_queue_fetch_byitemid(item_id)))
|
||||
queue_item = db_queue_fetch_byitemid(item_id);
|
||||
if (!queue_item)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "No valid item id given, or now_playing given but not playing: '%s'\n", hreq->uri_parsed->path);
|
||||
return HTTP_BADREQUEST;
|
||||
@ -2643,20 +2658,20 @@ jsonapi_reply_queue_tracks_update(struct httpd_request *hreq)
|
||||
is_changed = false;
|
||||
if ((param = evhttp_find_header(hreq->query, "new_position")))
|
||||
ret = update_pos(item_id, param, status.shuffle);
|
||||
if ((param = evhttp_find_header(hreq->query, "title")) && (is_changed = true))
|
||||
update_str(&queue_item->title, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "album")) && (is_changed = true))
|
||||
update_str(&queue_item->album, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "artist")) && (is_changed = true))
|
||||
update_str(&queue_item->artist, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "album_artist")) && (is_changed = true))
|
||||
update_str(&queue_item->album_artist, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "composer")) && (is_changed = true))
|
||||
update_str(&queue_item->composer, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "genre")) && (is_changed = true))
|
||||
update_str(&queue_item->genre, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "artwork_url")) && (is_changed = true))
|
||||
update_str(&queue_item->artwork_url, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "title")))
|
||||
update_str(&is_changed, &queue_item->title, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "album")))
|
||||
update_str(&is_changed, &queue_item->album, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "artist")))
|
||||
update_str(&is_changed, &queue_item->artist, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "album_artist")))
|
||||
update_str(&is_changed, &queue_item->album_artist, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "composer")))
|
||||
update_str(&is_changed, &queue_item->composer, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "genre")))
|
||||
update_str(&is_changed, &queue_item->genre, param);
|
||||
if ((param = evhttp_find_header(hreq->query, "artwork_url")))
|
||||
update_str(&is_changed, &queue_item->artwork_url, param);
|
||||
|
||||
if (ret != HTTP_OK)
|
||||
return ret;
|
||||
|
@ -645,6 +645,7 @@ streaming_init(void)
|
||||
default:
|
||||
DPRINTF(E_LOG, L_STREAMING, "Unsuppported streaming bit_rate=%d, supports: 64/96/128/192/320, defaulting\n", val);
|
||||
}
|
||||
|
||||
DPRINTF(E_INFO, L_STREAMING, "Streaming quality: %d/%d/%d @ %dkbps\n", streaming_quality_out.sample_rate, streaming_quality_out.bits_per_sample, streaming_quality_out.channels, streaming_quality_out.bit_rate/1000);
|
||||
|
||||
val = cfg_getint(cfgsec, "icy_metaint");
|
||||
@ -654,7 +655,12 @@ streaming_init(void)
|
||||
else
|
||||
DPRINTF(E_INFO, L_STREAMING, "Unsupported icy_metaint=%d, supported range: 4096..131072, defaulting to %d\n", val, streaming_icy_metaint);
|
||||
|
||||
pthread_mutex_init(&streaming_sessions_lck, NULL);
|
||||
ret = mutex_init(&streaming_sessions_lck);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_FATAL, L_STREAMING, "Could not initialize mutex (%d): %s\n", ret, strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Non-blocking because otherwise httpd and player thread may deadlock
|
||||
#ifdef HAVE_PIPE2
|
||||
|
@ -217,7 +217,7 @@ metadata_get(struct input_source *source)
|
||||
if (!inputs[source->type]->metadata_get)
|
||||
return NULL;
|
||||
|
||||
metadata = calloc(1, sizeof(struct input_metadata));
|
||||
CHECK_NULL(L_PLAYER, metadata = calloc(1, sizeof(struct input_metadata)));
|
||||
|
||||
ret = inputs[source->type]->metadata_get(metadata, source);
|
||||
if (ret < 0)
|
||||
@ -890,8 +890,8 @@ input_init(void)
|
||||
int i;
|
||||
|
||||
// Prepare input buffer
|
||||
pthread_mutex_init(&input_buffer.mutex, NULL);
|
||||
pthread_cond_init(&input_buffer.cond, NULL);
|
||||
CHECK_ERR(L_PLAYER, mutex_init(&input_buffer.mutex));
|
||||
CHECK_ERR(L_PLAYER, pthread_cond_init(&input_buffer.cond, NULL));
|
||||
|
||||
CHECK_NULL(L_PLAYER, evbase_input = event_base_new());
|
||||
CHECK_NULL(L_PLAYER, input_buffer.evbuf = evbuffer_new());
|
||||
|
@ -51,7 +51,7 @@ path_to_media_id_and_type(struct sp_file *file)
|
||||
struct sp_channel *
|
||||
channel_get(uint32_t channel_id, struct sp_session *session)
|
||||
{
|
||||
if (channel_id > sizeof(session->channels)/sizeof(session->channels)[0])
|
||||
if (channel_id >= sizeof(session->channels)/sizeof(session->channels)[0])
|
||||
return NULL;
|
||||
|
||||
if (session->channels[channel_id].state == SP_CHANNEL_STATE_UNALLOCATED)
|
||||
@ -148,6 +148,7 @@ channel_flush(struct sp_channel *channel)
|
||||
int fd = channel->audio_fd[0];
|
||||
int flags;
|
||||
int got;
|
||||
int ret;
|
||||
|
||||
evbuffer_drain(channel->audio_buf, -1);
|
||||
|
||||
@ -157,13 +158,18 @@ channel_flush(struct sp_channel *channel)
|
||||
if (flags == -1)
|
||||
return -1;
|
||||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
do
|
||||
got = read(fd, buf, sizeof(buf));
|
||||
while (got > 0);
|
||||
|
||||
fcntl(fd, F_SETFL, flags);
|
||||
ret = fcntl(fd, F_SETFL, flags);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -207,6 +207,10 @@ commands_base_new(struct event_base *evbase, command_exit_cb exit_cb)
|
||||
int ret;
|
||||
|
||||
cmdbase = calloc(1, sizeof(struct commands_base));
|
||||
if (!cmdbase)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
ret = pipe2(cmdbase->command_pipe, O_CLOEXEC);
|
||||
@ -370,6 +374,9 @@ commands_exec_async(struct commands_base *cmdbase, command_function func, void *
|
||||
int ret;
|
||||
|
||||
cmd = calloc(1, sizeof(struct command));
|
||||
if (!cmd)
|
||||
return -1;
|
||||
|
||||
cmd->func = func;
|
||||
cmd->func_bh = NULL;
|
||||
cmd->arg = arg;
|
||||
|
@ -620,7 +620,7 @@ response_aplogin_failed(uint8_t *payload, size_t payload_len, struct sp_session
|
||||
}
|
||||
|
||||
sp_errmsg = "(unknown login error)";
|
||||
for (int i = 0; i < sizeof(sp_login_errors); i++)
|
||||
for (int i = 0; i < sizeof(sp_login_errors)/sizeof(sp_login_errors[0]); i++)
|
||||
{
|
||||
if (sp_login_errors[i].errorcode != aplogin_failed->error_code)
|
||||
continue;
|
||||
|
@ -48,6 +48,7 @@ events for proceeding are activated directly.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "librespot-c-internal.h"
|
||||
#include "commands.h"
|
||||
@ -833,6 +834,8 @@ librespotc_write(int fd, sp_progress_cb progress_cb, void *cb_arg)
|
||||
|
||||
cmdargs = calloc(1, sizeof(struct sp_cmdargs));
|
||||
|
||||
assert(cmdargs);
|
||||
|
||||
cmdargs->fd_read = fd;
|
||||
cmdargs->progress_cb = progress_cb;
|
||||
cmdargs->cb_arg = cb_arg;
|
||||
|
@ -180,7 +180,7 @@ pipe_create(const char *path, int id, enum pipetype type, event_callback_fn cb)
|
||||
{
|
||||
struct pipe *pipe;
|
||||
|
||||
pipe = calloc(1, sizeof(struct pipe));
|
||||
CHECK_NULL(L_PLAYER, pipe = calloc(1, sizeof(struct pipe)));
|
||||
pipe->path = strdup(path);
|
||||
pipe->id = id;
|
||||
pipe->fd = -1;
|
||||
@ -916,9 +916,6 @@ pipe_metadata_watch_add(void *arg)
|
||||
pipe_metadata_watch_del(NULL); // Just in case we somehow already have a metadata pipe open
|
||||
|
||||
pipe_metadata.pipe = pipe_create(path, 0, PIPE_METADATA, pipe_metadata_read_cb);
|
||||
if (!pipe_metadata.pipe)
|
||||
return;
|
||||
|
||||
pipe_metadata.evbuf = evbuffer_new();
|
||||
|
||||
ret = watch_add(pipe_metadata.pipe);
|
||||
@ -948,13 +945,18 @@ pipe_thread_start(void)
|
||||
static void
|
||||
pipe_thread_stop(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tid_pipe)
|
||||
return;
|
||||
|
||||
commands_exec_sync(cmdbase, pipe_watch_update, NULL, NULL);
|
||||
|
||||
commands_base_destroy(cmdbase);
|
||||
pthread_join(tid_pipe, NULL);
|
||||
|
||||
ret = pthread_join(tid_pipe, NULL);
|
||||
if (ret != 0)
|
||||
DPRINTF(E_LOG, L_PLAYER, "Could not join pipe thread: %s\n", strerror(errno));
|
||||
|
||||
event_base_free(evbase_pipe);
|
||||
tid_pipe = 0;
|
||||
}
|
||||
@ -1037,9 +1039,10 @@ setup(struct input_source *source)
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
CHECK_NULL(L_PLAYER, pipe = pipe_create(source->path, source->id, PIPE_PCM, NULL));
|
||||
CHECK_NULL(L_PLAYER, source->evbuf = evbuffer_new());
|
||||
|
||||
pipe = pipe_create(source->path, source->id, PIPE_PCM, NULL);
|
||||
|
||||
pipe->fd = fd;
|
||||
pipe->is_autostarted = (source->id == pipe_autostart_id);
|
||||
|
||||
|
@ -170,10 +170,10 @@ virtual_path_make(char *virtual_path, int virtual_path_len, const char *path)
|
||||
|
||||
ret = snprintf(virtual_path, virtual_path_len, "/file:%s", path);
|
||||
if ((ret < 0) || (ret >= virtual_path_len))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Virtual path '/file:%s', virtual_path_len exceeded (%d/%d)\n", path, ret, virtual_path_len);
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Virtual path '/file:%s', virtual_path_len exceeded (%d/%d)\n", path, ret, virtual_path_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -816,7 +816,6 @@ process_directory(char *path, int parent_id, int flags)
|
||||
if (!dirp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -824,7 +823,10 @@ process_directory(char *path, int parent_id, int flags)
|
||||
|
||||
ret = virtual_path_make(virtual_path, sizeof(virtual_path), path);
|
||||
if (ret < 0)
|
||||
return;
|
||||
{
|
||||
closedir(dirp);
|
||||
return;
|
||||
}
|
||||
|
||||
dir_id = db_directory_addorupdate(virtual_path, path, 0, parent_id);
|
||||
if (dir_id <= 0)
|
||||
@ -853,7 +855,6 @@ process_directory(char *path, int parent_id, int flags)
|
||||
if (errno)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "readdir error in %s: %s\n", path, strerror(errno));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -879,7 +880,6 @@ process_directory(char *path, int parent_id, int flags)
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Skipping %s, read_attributes() failed\n", entry);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -916,7 +916,6 @@ process_directory(char *path, int parent_id, int flags)
|
||||
if (wi.wd < 0)
|
||||
{
|
||||
DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1112,8 +1111,8 @@ static void
|
||||
process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
|
||||
{
|
||||
struct watch_enum we;
|
||||
struct watch_info dummy_wi;
|
||||
uint32_t rm_wd;
|
||||
char *s;
|
||||
int flags = 0;
|
||||
int ret;
|
||||
int parent_id;
|
||||
@ -1204,12 +1203,9 @@ process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
|
||||
DPRINTF(E_DBG, L_SCAN, "Directory permissions changed (%s): %s\n", wi->path, path);
|
||||
|
||||
// Find out if we are already watching the dir (ret will be 0)
|
||||
s = wi->path;
|
||||
wi->path = path;
|
||||
ret = db_watch_get_bypath(wi);
|
||||
ret = db_watch_get_bypath(&dummy_wi, path);
|
||||
if (ret == 0)
|
||||
free(wi->path);
|
||||
wi->path = s;
|
||||
free_wi(&dummy_wi, 1);
|
||||
|
||||
// We don't use access() or euidaccess() because they don't work with ACL's
|
||||
// - this also means we can't check for executable permission, which stat()
|
||||
@ -1237,7 +1233,7 @@ process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
|
||||
DPRINTF(E_INFO, L_SCAN, "Directory event, but '%s' already being watched\n", path);
|
||||
}
|
||||
|
||||
if (fd > 0)
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@ -1321,7 +1317,7 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
|
||||
ie->mask |= IN_CLOSE_WRITE;
|
||||
}
|
||||
|
||||
if (fd > 0)
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@ -1336,7 +1332,7 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
|
||||
ret = virtual_path_make(dir_vpath, sizeof(dir_vpath), path);
|
||||
if (ret >= 0)
|
||||
{
|
||||
ptr = strrchr(dir_vpath, '/');
|
||||
CHECK_NULL(L_SCAN, ptr = strrchr(dir_vpath, '/'));
|
||||
*ptr = '\0';
|
||||
|
||||
dir_id = db_directory_id_byvirtualpath(dir_vpath);
|
||||
@ -1539,8 +1535,7 @@ inotify_cb(int fd, short event, void *arg)
|
||||
* the memory space for ie[1+] contains the name of the file
|
||||
* see the inotify documentation
|
||||
*/
|
||||
wi.wd = ie->wd;
|
||||
ret = db_watch_get_bywd(&wi);
|
||||
ret = db_watch_get_bywd(&wi, ie->wd);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (!(ie->mask & IN_IGNORED))
|
||||
@ -1554,30 +1549,30 @@ inotify_cb(int fd, short event, void *arg)
|
||||
DPRINTF(E_DBG, L_SCAN, "%s deleted or backing filesystem unmounted!\n", wi.path);
|
||||
|
||||
db_watch_delete_bywd(ie->wd);
|
||||
free(wi.path);
|
||||
free_wi(&wi, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
path[0] = '\0';
|
||||
|
||||
ret = snprintf(path, PATH_MAX, "%s", wi.path);
|
||||
if ((ret < 0) || (ret >= PATH_MAX))
|
||||
ret = snprintf(path, sizeof(path), "%s", wi.path);
|
||||
if ((ret < 0) || (ret >= sizeof(path)))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Skipping event under %s, PATH_MAX exceeded\n", wi.path);
|
||||
|
||||
free(wi.path);
|
||||
free_wi(&wi, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ie->len > 0)
|
||||
{
|
||||
namelen = PATH_MAX - ret;
|
||||
namelen = sizeof(path) - ret;
|
||||
ret = snprintf(path + ret, namelen, "/%s", ie->name);
|
||||
if ((ret < 0) || (ret >= namelen))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", wi.path, ie->name);
|
||||
|
||||
free(wi.path);
|
||||
free_wi(&wi, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -1595,7 +1590,7 @@ inotify_cb(int fd, short event, void *arg)
|
||||
#else
|
||||
process_inotify_file_defer(&wi, path, ie);
|
||||
#endif
|
||||
free(wi.path);
|
||||
free_wi(&wi, 1);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
@ -749,40 +749,40 @@ process_pl_items(plist_t items, int pl_id, const char *name, struct itml_to_db_m
|
||||
db_transaction_end();
|
||||
}
|
||||
|
||||
static int
|
||||
static bool
|
||||
ignore_pl(plist_t pl, const char *name)
|
||||
{
|
||||
uint64_t kind;
|
||||
int smart;
|
||||
uint8_t master;
|
||||
uint8_t party;
|
||||
|
||||
kind = 0;
|
||||
smart = 0;
|
||||
master = 0;
|
||||
party = 0;
|
||||
if (get_dictval_int_from_key(pl, "Distinguished Kind", &kind) == 0 && kind > 0)
|
||||
{
|
||||
DPRINTF(E_INFO, L_SCAN, "Ignoring iTunes builtin playlist '%s' (k %" PRIu64 ")\n", name, kind);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Special (builtin) playlists */
|
||||
get_dictval_int_from_key(pl, "Distinguished Kind", &kind);
|
||||
if (get_dictval_bool_from_key(pl, "Master", &master) == 0 && master)
|
||||
{
|
||||
DPRINTF(E_INFO, L_SCAN, "Ignoring iTunes Master playlist '%s'\n", name);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (get_dictval_bool_from_key(pl, "Party Shuffle", &party) == 0 && party)
|
||||
{
|
||||
DPRINTF(E_INFO, L_SCAN, "Ignoring iTunes Party Shuffle playlist '%s'\n", name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Import smart playlists (optional) */
|
||||
if (!cfg_getbool(cfg_getsec(cfg, "library"), "itunes_smartpl")
|
||||
&& (plist_dict_get_item(pl, "Smart Info") || plist_dict_get_item(pl, "Smart Criteria")))
|
||||
smart = 1;
|
||||
|
||||
/* Not interested in the Master playlist */
|
||||
get_dictval_bool_from_key(pl, "Master", &master);
|
||||
/* Not interested in Party Shuffle playlists */
|
||||
get_dictval_bool_from_key(pl, "Party Shuffle", &party);
|
||||
|
||||
if ((kind > 0) || smart || party || master)
|
||||
{
|
||||
DPRINTF(E_INFO, L_SCAN, "Ignoring playlist '%s' (k %" PRIu64 " s%d p%d m%d)\n", name, kind, smart, party, master);
|
||||
|
||||
return 1;
|
||||
DPRINTF(E_INFO, L_SCAN, "Ignoring iTunes smart playlist as set in config '%s'\n", name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -351,9 +351,10 @@ request_endpoint(const char *uri)
|
||||
json_object *json_response = NULL;
|
||||
int ret;
|
||||
|
||||
ctx = calloc(1, sizeof(struct http_client_ctx));
|
||||
ctx->output_headers = calloc(1, sizeof(struct keyval));
|
||||
ctx->input_body = evbuffer_new();
|
||||
CHECK_NULL(L_SPOTIFY, ctx = calloc(1, sizeof(struct http_client_ctx)));
|
||||
CHECK_NULL(L_SPOTIFY, ctx->output_headers = calloc(1, sizeof(struct keyval)));
|
||||
CHECK_NULL(L_SPOTIFY, ctx->input_body = evbuffer_new());
|
||||
|
||||
ctx->url = uri;
|
||||
|
||||
snprintf(bearer_token, sizeof(bearer_token), "Bearer %s", spotify_credentials.access_token);
|
||||
@ -1091,7 +1092,9 @@ spotifywebapi_oauth_uri_get(const char *redirect_uri)
|
||||
if (param)
|
||||
{
|
||||
uri_len = strlen(spotify_auth_uri) + strlen(param) + 3;
|
||||
uri = calloc(uri_len, sizeof(char));
|
||||
|
||||
CHECK_NULL(L_SPOTIFY, uri = calloc(uri_len, sizeof(char)));
|
||||
|
||||
snprintf(uri, uri_len, "%s/?%s", spotify_auth_uri, param);
|
||||
|
||||
free(param);
|
||||
|
@ -364,7 +364,7 @@ signal_signalfd_cb(int fd, short event, void *arg)
|
||||
struct signalfd_siginfo info;
|
||||
int status;
|
||||
|
||||
while (read(fd, &info, sizeof(struct signalfd_siginfo)) > 0)
|
||||
while (read(fd, &info, sizeof(struct signalfd_siginfo)) == sizeof(struct signalfd_siginfo))
|
||||
{
|
||||
switch (info.ssi_signo)
|
||||
{
|
||||
|
@ -258,7 +258,7 @@ net_bind(short unsigned *port, int type, const char *log_service_name)
|
||||
char strport[8];
|
||||
int yes = 1;
|
||||
int no = 0;
|
||||
int fd;
|
||||
int fd = -1;
|
||||
int ret;
|
||||
|
||||
cfgaddr = cfg_getstr(cfg_getsec(cfg, "general"), "bind_address");
|
||||
@ -275,7 +275,7 @@ net_bind(short unsigned *port, int type, const char *log_service_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ptr = servinfo, fd = -1; ptr != NULL; ptr = ptr->ai_next)
|
||||
for (ptr = servinfo; ptr != NULL; ptr = ptr->ai_next)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
@ -338,7 +338,8 @@ net_bind(short unsigned *port, int type, const char *log_service_name)
|
||||
return fd;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -811,7 +811,8 @@ parse_group_params(int argc, char **argv, bool group_in_listcommand, struct quer
|
||||
return 0;
|
||||
|
||||
*groupsize = (argc - first_group) / 2;
|
||||
*group = calloc(*groupsize, sizeof(struct mpd_tagtype *));
|
||||
|
||||
CHECK_NULL(L_MPD, *group = calloc(*groupsize, sizeof(struct mpd_tagtype *)));
|
||||
|
||||
// Now process all group/field arguments
|
||||
for (j = 0; j < (*groupsize); j++)
|
||||
@ -3557,7 +3558,7 @@ output_get_cb(struct player_speaker_info *spk, void *arg)
|
||||
if (!param->output
|
||||
&& param->shortid == (unsigned short) spk->id)
|
||||
{
|
||||
param->output = calloc(1, sizeof(struct output));
|
||||
CHECK_NULL(L_MPD, param->output = calloc(1, sizeof(struct output)));
|
||||
|
||||
param->output->id = spk->id;
|
||||
param->output->shortid = (unsigned short) spk->id;
|
||||
|
@ -559,7 +559,8 @@ device_id_colon_parse(uint64_t *id, const char *id_str)
|
||||
char *ptr;
|
||||
int ret;
|
||||
|
||||
s = calloc(1, strlen(id_str) + 1);
|
||||
CHECK_NULL(L_AIRPLAY, s = calloc(1, strlen(id_str) + 1));
|
||||
|
||||
for (ptr = s; *id_str != '\0'; id_str++)
|
||||
{
|
||||
if (*id_str == ':')
|
||||
|
@ -948,6 +948,7 @@ sync_correct(struct alsa_playback_session *pb, double drift, double latency, str
|
||||
{
|
||||
int step;
|
||||
int sign;
|
||||
int ret;
|
||||
|
||||
// We change the sample_rate in steps that are a multiple of 50. So we might
|
||||
// step 44100 -> 44000 -> 40900 -> 44000 -> 44100. If we used percentages to
|
||||
@ -975,7 +976,14 @@ sync_correct(struct alsa_playback_session *pb, double drift, double latency, str
|
||||
pb->quality.sample_rate += sign * step;
|
||||
|
||||
if (pb->sync_resample_step != 0)
|
||||
outputs_quality_subscribe(&pb->quality);
|
||||
{
|
||||
ret = outputs_quality_subscribe(&pb->quality);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LAUDIO, "Error adjusting sample rate to %d to maintain sync\n", pb->quality.sample_rate);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset position so next sync_correct latency correction is only based on
|
||||
// what has elapsed since our correction
|
||||
|
@ -931,7 +931,7 @@ static int
|
||||
raop_parse_auth(struct raop_session *rs, struct evrtsp_request *req)
|
||||
{
|
||||
const char *param;
|
||||
char *auth;
|
||||
char *auth = NULL;
|
||||
char *token;
|
||||
char *ptr;
|
||||
|
||||
@ -951,8 +951,7 @@ raop_parse_auth(struct raop_session *rs, struct evrtsp_request *req)
|
||||
if (!param)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "WWW-Authenticate header not found\n");
|
||||
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_RAOP, "WWW-Authenticate: %s\n", param);
|
||||
@ -960,19 +959,23 @@ raop_parse_auth(struct raop_session *rs, struct evrtsp_request *req)
|
||||
if (strncmp(param, "Digest ", strlen("Digest ")) != 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Unsupported authentication method: %s\n", param);
|
||||
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
auth = strdup(param);
|
||||
if (!auth)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Out of memory for WWW-Authenticate header copy\n");
|
||||
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
token = strchr(auth, ' ');
|
||||
if (!token)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Unexpected WWW-Authenticate auth\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
token++;
|
||||
|
||||
token = strtok_r(token, " =", &ptr);
|
||||
@ -998,8 +1001,6 @@ raop_parse_auth(struct raop_session *rs, struct evrtsp_request *req)
|
||||
token = strtok_r(NULL, " =", &ptr);
|
||||
}
|
||||
|
||||
free(auth);
|
||||
|
||||
if (!rs->realm || !rs->nonce)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Could not find realm/nonce in WWW-Authenticate header\n");
|
||||
@ -1016,12 +1017,17 @@ raop_parse_auth(struct raop_session *rs, struct evrtsp_request *req)
|
||||
rs->nonce = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_RAOP, "Found realm: [%s], nonce: [%s]\n", rs->realm, rs->nonce);
|
||||
|
||||
free(auth);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(auth);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -3363,6 +3369,14 @@ raop_cb_startup_setup(struct evrtsp_request *req, void *arg)
|
||||
}
|
||||
|
||||
token = strchr(transport, ';');
|
||||
if (!token)
|
||||
{
|
||||
DPRINTF(E_LOG, L_RAOP, "Missing semicolon in Transport header: %s\n", transport);
|
||||
|
||||
free(transport);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
token++;
|
||||
|
||||
token = strtok_r(token, ";=", &ptr);
|
||||
|
@ -70,6 +70,9 @@ pair_tlv_new() {
|
||||
|
||||
void
|
||||
pair_tlv_free(pair_tlv_values_t *values) {
|
||||
if (!values)
|
||||
return;
|
||||
|
||||
pair_tlv_t *t = values->head;
|
||||
while (t) {
|
||||
pair_tlv_t *t2 = t;
|
||||
|
@ -347,7 +347,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
bnum u, x;
|
||||
|
||||
*len_M = 0;
|
||||
*bytes_M = 0;
|
||||
*bytes_M = NULL;
|
||||
|
||||
bnum_bin2bn(s, bytes_s, len_s);
|
||||
bnum_bin2bn(B, bytes_B, len_B);
|
||||
@ -384,14 +384,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
calculate_H_AMK(usr->alg, usr->H_AMK, usr->A, usr->M, usr->session_key, usr->session_key_len);
|
||||
|
||||
*bytes_M = usr->M;
|
||||
if (len_M)
|
||||
*len_M = hash_length(usr->alg);
|
||||
}
|
||||
else
|
||||
{
|
||||
*bytes_M = NULL;
|
||||
if (len_M)
|
||||
*len_M = 0;
|
||||
*len_M = hash_length(usr->alg);
|
||||
}
|
||||
|
||||
cleanup2:
|
||||
|
@ -55,6 +55,8 @@
|
||||
#define REQUEST_BUFSIZE 4096
|
||||
#define ENCRYPTED_LEN_MAX 0x400
|
||||
|
||||
// #define DEBUG_SHORT_A 1
|
||||
|
||||
enum pair_keys
|
||||
{
|
||||
PAIR_SETUP_MSG01 = 0,
|
||||
@ -418,6 +420,14 @@ srp_user_get_session_key(struct SRPUser *usr, int *key_length)
|
||||
return usr->session_key;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SHORT_A
|
||||
// This value of "a" will yield a 383 byte A
|
||||
static uint8_t short_a[] = {
|
||||
0xef, 0xb5, 0x93, 0xf5, 0x03, 0x97, 0x69, 0x8e, 0x15, 0xed, 0xee, 0x5b, 0xf2, 0xf9, 0x23, 0x6c,
|
||||
0xf0, 0x59, 0x6c, 0xe2, 0x77, 0xf2, 0x14, 0x16, 0xac, 0x99, 0xfa, 0x31, 0xae, 0x2b, 0xd3, 0x41,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Output: username, bytes_A, len_A */
|
||||
static void
|
||||
srp_user_start_authentication(struct SRPUser *usr, const char **username,
|
||||
@ -425,6 +435,9 @@ srp_user_start_authentication(struct SRPUser *usr, const char **username,
|
||||
{
|
||||
// BN_hex2bn(&(usr->a), "D929DFB605687233C9E9030C2280156D03BDB9FDCF3CCE3BC27D9CCFCB5FF6A1");
|
||||
bnum_random(usr->a, 256);
|
||||
#ifdef DEBUG_SHORT_A
|
||||
bnum_bin2bn(usr->a, short_a, sizeof(short_a));
|
||||
#endif
|
||||
#ifdef DEBUG_PAIR
|
||||
bnum_dump("Random value of usr->a:\n", usr->a);
|
||||
#endif
|
||||
@ -459,7 +472,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
bnum u, x;
|
||||
|
||||
*len_M = 0;
|
||||
*bytes_M = 0;
|
||||
*bytes_M = NULL;
|
||||
|
||||
bnum_bin2bn(s, bytes_s, len_s);
|
||||
bnum_bin2bn(B, bytes_B, len_B);
|
||||
@ -499,14 +512,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
calculate_H_AMK(usr->alg, usr->H_AMK, usr->A, usr->M, usr->session_key, usr->session_key_len);
|
||||
|
||||
*bytes_M = usr->M;
|
||||
if (len_M)
|
||||
*len_M = hash_length(usr->alg);
|
||||
}
|
||||
else
|
||||
{
|
||||
*bytes_M = NULL;
|
||||
if (len_M)
|
||||
*len_M = 0;
|
||||
*len_M = hash_length(usr->alg);
|
||||
}
|
||||
|
||||
cleanup2:
|
||||
@ -1936,6 +1942,7 @@ client_verify_response2(struct pair_verify_context *handle, const uint8_t *data,
|
||||
|
||||
handle->status = PAIR_STATUS_COMPLETED;
|
||||
|
||||
pair_tlv_free(response);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -764,7 +764,7 @@ remote_pairing_pair(const char *pin)
|
||||
return REMOTE_INVALID_PIN;
|
||||
}
|
||||
|
||||
strncpy(cmdarg, pin, sizeof(cmdarg));
|
||||
snprintf(cmdarg, sizeof(cmdarg), "%s", pin);
|
||||
|
||||
return commands_exec_sync(cmdbase, pairing_pair, NULL, &cmdarg);
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ rng_rand_range(struct rng_ctx *ctx, int32_t min, int32_t max)
|
||||
* Durstenfeld in-place shuffling variant
|
||||
*/
|
||||
void
|
||||
shuffle_int(struct rng_ctx *ctx, int *values, int len)
|
||||
rng_shuffle_int(struct rng_ctx *ctx, int *values, int len)
|
||||
{
|
||||
int i;
|
||||
int32_t j;
|
||||
|
@ -19,7 +19,7 @@ int32_t
|
||||
rng_rand_range(struct rng_ctx *ctx, int32_t min, int32_t max);
|
||||
|
||||
void
|
||||
shuffle_int(struct rng_ctx *ctx, int *values, int len);
|
||||
rng_shuffle_int(struct rng_ctx *ctx, int *values, int len);
|
||||
|
||||
#endif /* !__RNG_H__ */
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <json.h>
|
||||
#include <libwebsockets.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -511,13 +510,19 @@ websocket_init(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&websocket_write_event_lock, NULL);
|
||||
websocket_write_events = 0;
|
||||
ret = mutex_init(&websocket_write_event_lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Failed to initialize mutex: %s\n", strerror(ret));
|
||||
lws_context_destroy(context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = pthread_create(&tid_websocket, NULL, websocket, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Could not spawn websocket thread: %s\n", strerror(errno));
|
||||
|
||||
DPRINTF(E_LOG, L_WEB, "Could not spawn websocket thread (%d): %s\n", ret, strerror(ret));
|
||||
pthread_mutex_destroy(&websocket_write_event_lock);
|
||||
lws_context_destroy(context);
|
||||
return -1;
|
||||
}
|
||||
@ -530,10 +535,15 @@ websocket_init(void)
|
||||
void
|
||||
websocket_deinit(void)
|
||||
{
|
||||
if (websocket_port > 0)
|
||||
{
|
||||
websocket_exit = true;
|
||||
pthread_join(tid_websocket, NULL);
|
||||
pthread_mutex_destroy(&websocket_write_event_lock);
|
||||
}
|
||||
int ret;
|
||||
|
||||
if (websocket_port <= 0)
|
||||
return;
|
||||
|
||||
websocket_exit = true;
|
||||
ret = pthread_join(tid_websocket, NULL);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_WEB, "Error joining websocket thread (%d): %s\n", ret, strerror(ret));
|
||||
|
||||
pthread_mutex_destroy(&websocket_write_event_lock);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user