[daap/dacp] Workaround so that libevent cleans up when a long poll is disconnected

See https://github.com/ejurgensen/forked-daapd/issues/870
This commit is contained in:
ejurgensen 2020-01-10 19:22:42 +01:00
parent 87cb3b8b58
commit 92dee0386d
2 changed files with 33 additions and 4 deletions

View File

@ -42,6 +42,7 @@
#include <unistd.h> #include <unistd.h>
#include <event2/event.h> #include <event2/event.h>
#include <event2/bufferevent.h>
#include "httpd_daap.h" #include "httpd_daap.h"
#include "logger.h" #include "logger.h"
@ -998,6 +999,7 @@ daap_reply_update(struct httpd_request *hreq)
{ {
struct daap_update_request *ur; struct daap_update_request *ur;
struct evhttp_connection *evcon; struct evhttp_connection *evcon;
struct bufferevent *bufev;
const char *param; const char *param;
int reqd_rev; int reqd_rev;
int ret; int ret;
@ -1077,7 +1079,18 @@ daap_reply_update(struct httpd_request *hreq)
*/ */
evcon = evhttp_request_get_connection(hreq->req); evcon = evhttp_request_get_connection(hreq->req);
if (evcon) if (evcon)
evhttp_connection_set_closecb(evcon, update_fail_cb, ur); {
evhttp_connection_set_closecb(evcon, update_fail_cb, ur);
// This is a workaround for some versions of libevent (2.0, but possibly
// also 2.1) that don't detect if the client hangs up, and thus don't
// clean up and never call update_fail_cb(). See github issue #870 and
// https://github.com/libevent/libevent/issues/666. It should probably be
// removed again in the future. The workaround is also present in dacp.c
bufev = evhttp_connection_get_bufferevent(evcon);
if (bufev)
bufferevent_enable(bufev, EV_READ);
}
return DAAP_REPLY_NONE; return DAAP_REPLY_NONE;
} }

View File

@ -36,6 +36,7 @@
#endif #endif
#include <event2/event.h> #include <event2/event.h>
#include <event2/bufferevent.h>
#include "httpd_dacp.h" #include "httpd_dacp.h"
#include "httpd_daap.h" #include "httpd_daap.h"
@ -2231,6 +2232,7 @@ dacp_reply_playstatusupdate(struct httpd_request *hreq)
{ {
struct dacp_update_request *ur; struct dacp_update_request *ur;
struct evhttp_connection *evcon; struct evhttp_connection *evcon;
struct bufferevent *bufev;
const char *param; const char *param;
int reqd_rev; int reqd_rev;
int ret; int ret;
@ -2257,7 +2259,10 @@ dacp_reply_playstatusupdate(struct httpd_request *hreq)
return -1; return -1;
} }
if ((reqd_rev == 0) || (reqd_rev == 1)) // Caller didn't use current revision number. It was probably his first
// request so we will give him status immediately, incl. which revision number
// to use when he calls again.
if (reqd_rev != current_rev)
{ {
ret = make_playstatusupdate(hreq->reply); ret = make_playstatusupdate(hreq->reply);
if (ret < 0) if (ret < 0)
@ -2268,7 +2273,7 @@ dacp_reply_playstatusupdate(struct httpd_request *hreq)
return ret; return ret;
} }
/* Else, just let the request hang until we have changes to push back */ // Else, just let the request hang until we have changes to push back
ur = calloc(1, sizeof(struct dacp_update_request)); ur = calloc(1, sizeof(struct dacp_update_request));
if (!ur) if (!ur)
{ {
@ -2288,7 +2293,18 @@ dacp_reply_playstatusupdate(struct httpd_request *hreq)
*/ */
evcon = evhttp_request_get_connection(hreq->req); evcon = evhttp_request_get_connection(hreq->req);
if (evcon) if (evcon)
evhttp_connection_set_closecb(evcon, update_fail_cb, ur); {
evhttp_connection_set_closecb(evcon, update_fail_cb, ur);
// This is a workaround for some versions of libevent (2.0, but possibly
// also 2.1) that don't detect if the client hangs up, and thus don't
// clean up and never call update_fail_cb(). See github issue #870 and
// https://github.com/libevent/libevent/issues/666. It should probably be
// removed again in the future. The workaround is also present in daap.c
bufev = evhttp_connection_get_bufferevent(evcon);
if (bufev)
bufferevent_enable(bufev, EV_READ);
}
return 0; return 0;
} }