mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-27 23:55:57 -05:00
Change queue_remove() to fix segfault because source_head/shuffle_head could become invalid, and to protect against invalid input in general (ref issue #160).
Also try to failsafe source_position() and implement next_ps() all around.
This commit is contained in:
parent
3dde23e060
commit
4fffc057b6
117
src/player.c
117
src/player.c
@ -755,6 +755,17 @@ metadata_check_icy(void)
|
||||
}
|
||||
|
||||
/* Audio sources */
|
||||
|
||||
/* Helper */
|
||||
static struct player_source *
|
||||
next_ps(struct player_source *ps, char shuffle)
|
||||
{
|
||||
if (shuffle)
|
||||
return ps->shuffle_next;
|
||||
else
|
||||
return ps->pl_next;
|
||||
}
|
||||
|
||||
/* Thread: httpd (DACP) */
|
||||
struct player_source *
|
||||
player_queue_make(struct query_params *qp)
|
||||
@ -1449,7 +1460,7 @@ source_next(int force)
|
||||
if (!cur_streaming)
|
||||
ps = head;
|
||||
else
|
||||
ps = (shuffle) ? cur_streaming->shuffle_next : cur_streaming->pl_next;
|
||||
ps = next_ps(cur_streaming, shuffle);
|
||||
|
||||
switch (r_mode)
|
||||
{
|
||||
@ -1600,25 +1611,39 @@ source_prev(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the position of the given song (ps) in the playqueue or shufflequeue.
|
||||
* Returns the position of the given player_source (ps) in the playqueue or shufflequeue.
|
||||
* First song in the queue has position 0. Depending on the 'shuffle' argument,
|
||||
* the position is either determined in the playqueue or shufflequeue.
|
||||
*
|
||||
* @param ps the song to search in the queue
|
||||
* @param ps the source to search in the queue
|
||||
* @param shuffle 0 search in the playqueue, 1 search in the shufflequeue
|
||||
* @return position 0-based in the queue
|
||||
* @return position 0-based in the queue (-1 if not found)
|
||||
*/
|
||||
static int
|
||||
source_position(struct player_source *ps, char shuffle)
|
||||
source_position(struct player_source *source, char shuffle)
|
||||
{
|
||||
struct player_source *p;
|
||||
struct player_source *ps;
|
||||
struct player_source *head;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
for (p = (shuffle ? shuffle_head : source_head); p != ps; p = (shuffle ? p->shuffle_next : p->pl_next))
|
||||
ret++;
|
||||
head = shuffle ? shuffle_head : source_head;
|
||||
if (!head)
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
if (source == head)
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
for (ps = next_ps(head, shuffle); ps != head; ps = next_ps(ps, shuffle))
|
||||
{
|
||||
ret++;
|
||||
if (ps == source)
|
||||
return ret;
|
||||
}
|
||||
|
||||
DPRINTF(E_LOG, L_PLAYER, "Bug! source_position was given non-existent source\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@ -2486,15 +2511,6 @@ playback_abort(void)
|
||||
metadata_purge();
|
||||
}
|
||||
|
||||
static struct player_source *
|
||||
next_ps(struct player_source *ps, char shuffle)
|
||||
{
|
||||
if (shuffle)
|
||||
return ps->shuffle_next;
|
||||
else
|
||||
return ps->pl_next;
|
||||
}
|
||||
|
||||
/* Actual commands, executed in the player thread */
|
||||
static int
|
||||
get_status(struct player_command *cmd)
|
||||
@ -3954,7 +3970,7 @@ queue_move(struct player_command *cmd)
|
||||
if (i == cmd->arg.ps_pos[1])
|
||||
ps_dst = ps;
|
||||
|
||||
ps = shuffle ? ps->shuffle_next : ps->pl_next;
|
||||
ps = next_ps(ps, shuffle);
|
||||
}
|
||||
|
||||
if (!ps_src || !ps_dst || (ps_src == ps_dst))
|
||||
@ -3999,56 +4015,67 @@ static int
|
||||
queue_remove(struct player_command *cmd)
|
||||
{
|
||||
struct player_source *ps;
|
||||
struct player_source *ps_current;
|
||||
uint32_t pos;
|
||||
uint32_t id;
|
||||
int i;
|
||||
|
||||
ps = cur_playing ? cur_playing : cur_streaming;
|
||||
if (!ps)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Current playing/streaming item not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmd->arg.item_range.type == RANGEARG_ID)
|
||||
{
|
||||
id = cmd->arg.item_range.id;
|
||||
DPRINTF(E_DBG, L_PLAYER, "Removing item with id %d\n", id);
|
||||
|
||||
pos = 0;
|
||||
if (id < 1)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Can't remove item, invalid id %d\n", id);
|
||||
return -1;
|
||||
}
|
||||
else if (id == ps->id)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Can't remove current playing item, id %d\n", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ps = source_head->pl_next;
|
||||
while (ps->id != id && ps != source_head)
|
||||
{
|
||||
ps = ps->pl_next;
|
||||
}
|
||||
DPRINTF(E_DBG, L_PLAYER, "Removing item with id %d\n", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = 0;
|
||||
pos = cmd->arg.item_range.start_pos;
|
||||
DPRINTF(E_DBG, L_PLAYER, "Removing item from position %d\n", pos);
|
||||
|
||||
if (pos < 1)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Can't remove item, invalid position %d\n", pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < pos; i++)
|
||||
{
|
||||
ps = shuffle ? ps->shuffle_next : ps->pl_next;
|
||||
}
|
||||
DPRINTF(E_DBG, L_PLAYER, "Removing item from position %d\n", pos);
|
||||
}
|
||||
|
||||
ps_current = cur_playing ? cur_playing : cur_streaming;
|
||||
if (!ps_current)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Current playing/streaming item not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
ps = ps_current;
|
||||
while (ps)
|
||||
{
|
||||
i++;
|
||||
ps = next_ps(ps, shuffle);
|
||||
|
||||
if (ps == ps_current)
|
||||
ps = NULL;
|
||||
else if ((i == pos) || (ps->id == id))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ps)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Can't remove requested item from queue (id %d, pos %d)\n", id, pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ps == source_head)
|
||||
source_head = ps->pl_next;
|
||||
if (ps == shuffle_head)
|
||||
shuffle_head = ps->shuffle_next;
|
||||
|
||||
ps->shuffle_prev->shuffle_next = ps->shuffle_next;
|
||||
ps->shuffle_next->shuffle_prev = ps->shuffle_prev;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user