[raop] Fix possible infinite loop + wrong packet resend (fixes issue #775)
Fixes bugs which were due to incorrect handling of unsigned integer wrap-around: 1. Calling packet_resend() with seqnum + len greater than UINT16_MAX => infinite loop 2. Calling rtp_packet_get() with session->seqnum - seqnum greater than pktbuf_next => wrong packet
This commit is contained in:
parent
6578f28621
commit
f9bfec180f
|
@ -2838,19 +2838,21 @@ control_packet_send(struct raop_session *rs, struct rtp_packet *pkt)
|
|||
}
|
||||
|
||||
static void
|
||||
packets_resend(struct raop_session *rs, uint16_t seqnum, uint16_t len)
|
||||
packets_resend(struct raop_session *rs, uint16_t seqnum, int len)
|
||||
{
|
||||
struct rtp_session *rtp_session;
|
||||
struct rtp_packet *pkt;
|
||||
uint16_t s;
|
||||
int i;
|
||||
bool pkt_missing = false;
|
||||
|
||||
rtp_session = rs->master_session->rtp_session;
|
||||
|
||||
DPRINTF(E_DBG, L_RAOP, "Got retransmit request from '%s': seqnum %" PRIu16 " (len %" PRIu16 "), last RTP session seqnum %" PRIu16 " (len %zu)\n",
|
||||
DPRINTF(E_DBG, L_RAOP, "Got retransmit request from '%s': seqnum %" PRIu16 " (len %d), last RTP session seqnum %" PRIu16 " (len %zu)\n",
|
||||
rs->devname, seqnum, len, rtp_session->seqnum - 1, rtp_session->pktbuf_len);
|
||||
|
||||
for (s = seqnum; s < seqnum + len; s++)
|
||||
// Note that seqnum may wrap around, so we don't use it for counting
|
||||
for (i = 0, s = seqnum; i < len; i++, s++)
|
||||
{
|
||||
pkt = rtp_packet_get(rtp_session, s);
|
||||
if (pkt)
|
||||
|
@ -2860,9 +2862,8 @@ packets_resend(struct raop_session *rs, uint16_t seqnum, uint16_t len)
|
|||
}
|
||||
|
||||
if (pkt_missing)
|
||||
DPRINTF(E_WARN, L_RAOP, "Device '%s' asking for seqnum %" PRIu16 " (len %" PRIu16 "), but not in buffer\n", rs->devname, seqnum, len);
|
||||
else
|
||||
DPRINTF(E_DBG, L_RAOP, "Retransmit done\n");
|
||||
DPRINTF(E_WARN, L_RAOP, "Device '%s' retransmit request for seqnum %" PRIu16 " (len %d) is outside buffer range (last seqnum %" PRIu16 ", len %zu)\n",
|
||||
rs->devname, seqnum, len, rtp_session->seqnum - 1, rtp_session->pktbuf_len);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -201,6 +201,7 @@ rtp_packet_get(struct rtp_session *session, uint16_t seqnum)
|
|||
{
|
||||
uint16_t first;
|
||||
uint16_t last;
|
||||
uint16_t delta;
|
||||
size_t idx;
|
||||
|
||||
if (!session->seqnum || !session->pktbuf_len)
|
||||
|
@ -221,7 +222,11 @@ rtp_packet_get(struct rtp_session *session, uint16_t seqnum)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
idx = (session->pktbuf_next - (session->seqnum - seqnum)) % session->pktbuf_size;
|
||||
// Distance from current seqnum (which is at pktbuf_next) to the requested seqnum
|
||||
delta = session->seqnum - seqnum;
|
||||
|
||||
// Adding pktbuf_size so we don't have to deal with "negative" pktbuf_next - delta
|
||||
idx = (session->pktbuf_next + session->pktbuf_size - delta) % session->pktbuf_size;
|
||||
|
||||
return &session->pktbuf[idx];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue