From d5e0950ec6fc3a803bf8918be72cff7463299ba0 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 18 Apr 2016 16:27:50 -0400 Subject: [PATCH] Wrap enet_host_service() to hide the logic required to make retransmissions work --- src/ControlStream.c | 6 +++--- src/Limelight-internal.h | 3 +++ src/Misc.c | 20 ++++++++++++++++++++ src/RtspConnection.c | 6 +++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/ControlStream.c b/src/ControlStream.c index 175037a..5fd166c 100644 --- a/src/ControlStream.c +++ b/src/ControlStream.c @@ -301,7 +301,7 @@ static int sendMessageEnet(short ptype, short paylen, const void* payload) { memcpy(&packet[1], payload, paylen); // Gen 5+ servers do control protocol over ENet instead of TCP - while ((err = enet_host_service(client, &event, 0)) > 0) { + while ((err = serviceEnetHost(client, &event, 0)) > 0) { if (event.type == ENET_EVENT_TYPE_RECEIVE) { enet_packet_destroy(event.packet); } @@ -391,7 +391,7 @@ static int sendMessageAndDiscardReply(short ptype, short paylen, const void* pay return 0; } - if (enet_host_service(client, &event, CONTROL_STREAM_TIMEOUT_SEC * 1000) <= 0 || + if (serviceEnetHost(client, &event, CONTROL_STREAM_TIMEOUT_SEC * 1000) <= 0 || event.type != ENET_EVENT_TYPE_RECEIVE) { PltUnlockMutex(&enetMutex); return 0; @@ -642,7 +642,7 @@ int startControlStream(void) { } // Wait for the connect to complete - if (enet_host_service(client, &event, CONTROL_STREAM_TIMEOUT_SEC * 1000) <= 0 || + if (serviceEnetHost(client, &event, CONTROL_STREAM_TIMEOUT_SEC * 1000) <= 0 || event.type != ENET_EVENT_TYPE_CONNECT) { Limelog("RTSP: Failed to connect to UDP port 47999\n"); enet_peer_reset(peer); diff --git a/src/Limelight-internal.h b/src/Limelight-internal.h index 448f93c..f8712aa 100644 --- a/src/Limelight-internal.h +++ b/src/Limelight-internal.h @@ -6,6 +6,8 @@ #include "PlatformThreads.h" #include "Video.h" +#include + // Common globals extern char* RemoteAddrString; extern struct sockaddr_storage RemoteAddr; @@ -18,6 +20,7 @@ extern AUDIO_RENDERER_CALLBACKS AudioCallbacks; extern int NegotiatedVideoFormat; int isBeforeSignedInt(int numA, int numB, int ambiguousCase); +int serviceEnetHost(ENetHost* client, ENetEvent* event, enet_uint32 timeoutMs); void fixupMissingCallbacks(PDECODER_RENDERER_CALLBACKS* drCallbacks, PAUDIO_RENDERER_CALLBACKS* arCallbacks, PCONNECTION_LISTENER_CALLBACKS* clCallbacks); diff --git a/src/Misc.c b/src/Misc.c index 4069f65..1e1fd53 100644 --- a/src/Misc.c +++ b/src/Misc.c @@ -1,5 +1,25 @@ #include "Limelight-internal.h" +#define ENET_SERVICE_RETRIES 10 + +// This function wraps enet_host_service() and hides the fact that it must be called +// multiple times for retransmissions to work correctly. It is meant to be a drop-in +// replacement for enet_host_service(). +int serviceEnetHost(ENetHost* client, ENetEvent* event, enet_uint32 timeoutMs) { + int i; + int ret; + + // We need to call enet_host_service() multiple times to make sure retransmissions happen + for (i = 0; i < ENET_SERVICE_RETRIES; i++) { + ret = enet_host_service(client, event, timeoutMs / ENET_SERVICE_RETRIES); + if (ret != 0 || timeoutMs == 0) { + break; + } + } + + return ret; +} + int isBeforeSignedInt(int numA, int numB, int ambiguousCase) { // This should be the common case for most callers if (numA == numB) { diff --git a/src/RtspConnection.c b/src/RtspConnection.c index 2e5a2c1..a67ff8f 100644 --- a/src/RtspConnection.c +++ b/src/RtspConnection.c @@ -141,7 +141,7 @@ static int transactRtspMessageEnet(PRTSP_MESSAGE request, PRTSP_MESSAGE response } // Wait for a reply - if (enet_host_service(client, &event, RTSP_TIMEOUT_SEC * 1000) <= 0 || + if (serviceEnetHost(client, &event, RTSP_TIMEOUT_SEC * 1000) <= 0 || event.type != ENET_EVENT_TYPE_RECEIVE) { Limelog("Failed to receive RTSP reply\n"); ret = 0; @@ -162,7 +162,7 @@ static int transactRtspMessageEnet(PRTSP_MESSAGE request, PRTSP_MESSAGE response // Wait for the payload if we're expecting some if (expectingPayload) { // The payload comes in a second packet - if (enet_host_service(client, &event, RTSP_TIMEOUT_SEC * 1000) <= 0 || + if (serviceEnetHost(client, &event, RTSP_TIMEOUT_SEC * 1000) <= 0 || event.type != ENET_EVENT_TYPE_RECEIVE) { Limelog("Failed to receive RTSP reply payload\n"); ret = 0; @@ -490,7 +490,7 @@ int performRtspHandshake(void) { } // Wait for the connect to complete - if (enet_host_service(client, &event, RTSP_TIMEOUT_SEC * 1000) <= 0 || + if (serviceEnetHost(client, &event, RTSP_TIMEOUT_SEC * 1000) <= 0 || event.type != ENET_EVENT_TYPE_CONNECT) { Limelog("RTSP: Failed to connect to UDP port 48010\n"); enet_peer_reset(peer);