diff --git a/src/artwork.c b/src/artwork.c index d72b7d46..33426e4f 100644 --- a/src/artwork.c +++ b/src/artwork.c @@ -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); diff --git a/src/commands.c b/src/commands.c index a08065a6..7043bff1 100644 --- a/src/commands.c +++ b/src/commands.c @@ -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; diff --git a/src/db.c b/src/db.c index 451a36f8..165a696f 100644 --- a/src/db.c +++ b/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; } diff --git a/src/db.h b/src/db.h index 5d272c65..8f547059 100644 --- a/src/db.h +++ b/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); diff --git a/src/evrtsp/rtsp.c b/src/evrtsp/rtsp.c index e5d49748..4d467df7 100644 --- a/src/evrtsp/rtsp.c +++ b/src/evrtsp/rtsp.c @@ -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) { diff --git a/src/httpd.c b/src/httpd.c index f0dc92b2..05144f14 100644 --- a/src/httpd.c +++ b/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) diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 7a95c544..72ef73fc 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -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); diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index e4a7e467..fcb7f812 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -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); diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 7cd9e738..7315e570 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -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; diff --git a/src/httpd_streaming.c b/src/httpd_streaming.c index dd4e6305..31f802e4 100644 --- a/src/httpd_streaming.c +++ b/src/httpd_streaming.c @@ -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 diff --git a/src/input.c b/src/input.c index c96e73f8..5d7dbba4 100644 --- a/src/input.c +++ b/src/input.c @@ -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()); diff --git a/src/inputs/librespot-c/src/channel.c b/src/inputs/librespot-c/src/channel.c index b3539840..fb4255e5 100644 --- a/src/inputs/librespot-c/src/channel.c +++ b/src/inputs/librespot-c/src/channel.c @@ -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; } diff --git a/src/inputs/librespot-c/src/commands.c b/src/inputs/librespot-c/src/commands.c index 09d66205..1b76e8e4 100644 --- a/src/inputs/librespot-c/src/commands.c +++ b/src/inputs/librespot-c/src/commands.c @@ -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; diff --git a/src/inputs/librespot-c/src/connection.c b/src/inputs/librespot-c/src/connection.c index abb6370d..7376f941 100644 --- a/src/inputs/librespot-c/src/connection.c +++ b/src/inputs/librespot-c/src/connection.c @@ -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; diff --git a/src/inputs/librespot-c/src/librespot-c.c b/src/inputs/librespot-c/src/librespot-c.c index f5ba80e1..3319b6a9 100644 --- a/src/inputs/librespot-c/src/librespot-c.c +++ b/src/inputs/librespot-c/src/librespot-c.c @@ -48,6 +48,7 @@ events for proceeding are activated directly. */ #include +#include #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; diff --git a/src/inputs/pipe.c b/src/inputs/pipe.c index c7d925f9..d04b2f2b 100644 --- a/src/inputs/pipe.c +++ b/src/inputs/pipe.c @@ -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); diff --git a/src/library/filescanner.c b/src/library/filescanner.c index 78714c40..5dc43786 100644 --- a/src/library/filescanner.c +++ b/src/library/filescanner.c @@ -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); diff --git a/src/library/filescanner_itunes.c b/src/library/filescanner_itunes.c index 9fab84eb..bf83b09a 100644 --- a/src/library/filescanner_itunes.c +++ b/src/library/filescanner_itunes.c @@ -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 diff --git a/src/library/spotify_webapi.c b/src/library/spotify_webapi.c index 2df6db1f..cdeaf3c5 100644 --- a/src/library/spotify_webapi.c +++ b/src/library/spotify_webapi.c @@ -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); diff --git a/src/main.c b/src/main.c index bd133df3..75438959 100644 --- a/src/main.c +++ b/src/main.c @@ -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) { diff --git a/src/misc.c b/src/misc.c index 8b812be9..3c0d46e8 100644 --- a/src/misc.c +++ b/src/misc.c @@ -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; } diff --git a/src/mpd.c b/src/mpd.c index add34da8..58929e8d 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -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; diff --git a/src/outputs/airplay.c b/src/outputs/airplay.c index f5aedfe6..ab10fded 100644 --- a/src/outputs/airplay.c +++ b/src/outputs/airplay.c @@ -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 == ':') diff --git a/src/outputs/alsa.c b/src/outputs/alsa.c index cdc5d2d5..8e27027c 100644 --- a/src/outputs/alsa.c +++ b/src/outputs/alsa.c @@ -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 diff --git a/src/outputs/raop.c b/src/outputs/raop.c index 4f0968c3..8a769139 100644 --- a/src/outputs/raop.c +++ b/src/outputs/raop.c @@ -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); diff --git a/src/pair_ap/pair-tlv.c b/src/pair_ap/pair-tlv.c index ea1a7614..ef457407 100644 --- a/src/pair_ap/pair-tlv.c +++ b/src/pair_ap/pair-tlv.c @@ -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; diff --git a/src/pair_ap/pair_fruit.c b/src/pair_ap/pair_fruit.c index 86f23636..1ee47ec7 100644 --- a/src/pair_ap/pair_fruit.c +++ b/src/pair_ap/pair_fruit.c @@ -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: diff --git a/src/pair_ap/pair_homekit.c b/src/pair_ap/pair_homekit.c index e45aed8c..88ca638a 100644 --- a/src/pair_ap/pair_homekit.c +++ b/src/pair_ap/pair_homekit.c @@ -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; } diff --git a/src/remote_pairing.c b/src/remote_pairing.c index 2625a3c3..5e7432b6 100644 --- a/src/remote_pairing.c +++ b/src/remote_pairing.c @@ -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); } diff --git a/src/rng.c b/src/rng.c index 00d0e5ce..452bae8e 100644 --- a/src/rng.c +++ b/src/rng.c @@ -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; diff --git a/src/rng.h b/src/rng.h index 200f4a52..8ce82ebf 100644 --- a/src/rng.h +++ b/src/rng.h @@ -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__ */ diff --git a/src/websocket.c b/src/websocket.c index ab4a0a29..6ac4a145 100644 --- a/src/websocket.c +++ b/src/websocket.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -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); }