Fixes for iTunes v10.5 time-outs.
Details: iTunes v10.5 clients changed how they responded to DAAP protocol, and started disconnecting when the forked-daapd server sent an empty "refresh" reply ("mupd" protocol). This problem is also coupled with session-timeout ("mstm" and "msal"); when these server capabilities were enabled, iTunes 10.x clients did not poll for updates and eventually disconnected. I investigated DAAP network packets using Wireshark. I found that a true iTunes server sends a set of server capabilities in a specific order, and order matters to the client. When the correct order is used, the client correctly polls for updates and does not disconnect. This change: 1. Send server capabilities in different order (daap_reply_server_info). 2. Disables 5-minute update refresh. 3. Disables 30-minute inactivity time-out. Testing: This server version successfully stayed connected to the following clients: * iTunes 10.5.2 * iTunes 10.4.2 * iTunes 9.7.1 * Rhythmbox 0.12.8 The clients stayed connected for at least several hours, sometimes days, with activity or no activity.
This commit is contained in:
parent
54d3951c20
commit
bd10978d52
|
@ -58,9 +58,11 @@ extern struct event_base *evbase_httpd;
|
|||
|
||||
|
||||
/* Session timeout in seconds */
|
||||
#define DAAP_SESSION_TIMEOUT 1800
|
||||
#define DAAP_SESSION_TIMEOUT 0 /* By default the session never times out */
|
||||
/* We announce this timeout to the client when returning server capabilities */
|
||||
#define DAAP_SESSION_TIMEOUT_CAPABILITY 1800
|
||||
/* Update requests refresh interval in seconds */
|
||||
#define DAAP_UPDATE_REFRESH 300
|
||||
#define DAAP_UPDATE_REFRESH 0
|
||||
|
||||
|
||||
struct uri_map {
|
||||
|
@ -130,7 +132,7 @@ daap_session_free(void *item)
|
|||
|
||||
s = (struct daap_session *)item;
|
||||
|
||||
evtimer_del(&s->timeout);
|
||||
if (event_initialized(&s->timeout)) evtimer_del(&s->timeout);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
@ -173,8 +175,10 @@ daap_session_register(void)
|
|||
|
||||
next_session_id++;
|
||||
|
||||
evtimer_set(&s->timeout, daap_session_timeout_cb, s);
|
||||
event_base_set(evbase_httpd, &s->timeout);
|
||||
if (DAAP_SESSION_TIMEOUT > 0) {
|
||||
evtimer_set(&s->timeout, daap_session_timeout_cb, s);
|
||||
event_base_set(evbase_httpd, &s->timeout);
|
||||
}
|
||||
|
||||
node = avl_insert(daap_sessions, s);
|
||||
if (!node)
|
||||
|
@ -185,12 +189,14 @@ daap_session_register(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_SESSION_TIMEOUT;
|
||||
|
||||
ret = evtimer_add(&s->timeout, &tv);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add session timeout event for session %d\n", s->id);
|
||||
if (DAAP_SESSION_TIMEOUT > 0) {
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_SESSION_TIMEOUT;
|
||||
|
||||
ret = evtimer_add(&s->timeout, &tv);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add session timeout event for session %d\n", s->id);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -225,14 +231,18 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev
|
|||
|
||||
s = (struct daap_session *)node->item;
|
||||
|
||||
event_del(&s->timeout);
|
||||
if (DAAP_SESSION_TIMEOUT > 0) {
|
||||
event_del(&s->timeout);
|
||||
}
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_SESSION_TIMEOUT;
|
||||
|
||||
ret = evtimer_add(&s->timeout, &tv);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add session timeout event for session %d\n", s->id);
|
||||
if (DAAP_SESSION_TIMEOUT > 0) {
|
||||
ret = evtimer_add(&s->timeout, &tv);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add session timeout event for session %d\n", s->id);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
|
@ -269,7 +279,7 @@ static void
|
|||
update_free(struct daap_update_request *ur)
|
||||
{
|
||||
if (event_initialized(&ur->timeout))
|
||||
evtimer_del(&ur->timeout);
|
||||
evtimer_del(&ur->timeout);
|
||||
free(ur);
|
||||
}
|
||||
|
||||
|
@ -678,25 +688,23 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char
|
|||
dmap_add_container(evbuf, "msrv", len - 8);
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12 */
|
||||
dmap_add_int(evbuf, "mpro", mpro); /* 12 */
|
||||
dmap_add_int(evbuf, "apro", apro); /* 12 */
|
||||
dmap_add_string(evbuf, "minm", name); /* 8 + strlen(name) */
|
||||
|
||||
dmap_add_int(evbuf, "mstm", DAAP_SESSION_TIMEOUT); /* 12 */
|
||||
dmap_add_char(evbuf, "msal", 1); /* 9 */
|
||||
dmap_add_int(evbuf, "apro", apro); /* 12 */
|
||||
|
||||
dmap_add_char(evbuf, "mslr", 1); /* 9 */
|
||||
dmap_add_int(evbuf, "mstm", DAAP_SESSION_TIMEOUT_CAPABILITY); /* 12 */
|
||||
dmap_add_char(evbuf, "msal", 1); /* 9 */
|
||||
dmap_add_char(evbuf, "msau", (passwd) ? 2 : 0); /* 9 */
|
||||
dmap_add_char(evbuf, "msup", 1); /* 9 */
|
||||
|
||||
dmap_add_char(evbuf, "mspi", 1); /* 9 */
|
||||
dmap_add_char(evbuf, "msex", 1); /* 9 */
|
||||
dmap_add_char(evbuf, "msix", 1); /* 9 */
|
||||
dmap_add_char(evbuf, "msbr", 1); /* 9 */
|
||||
dmap_add_char(evbuf, "msqy", 1); /* 9 */
|
||||
|
||||
dmap_add_char(evbuf, "mspi", 1); /* 9 */
|
||||
dmap_add_int(evbuf, "msdc", 1); /* 12 */
|
||||
|
||||
/* Advertise updates support even though we don't send updates */
|
||||
dmap_add_char(evbuf, "msup", 1); /* 9 */
|
||||
|
||||
httpd_send_reply(req, HTTP_OK, "OK", evbuf);
|
||||
}
|
||||
|
||||
|
@ -887,22 +895,24 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
|
|||
}
|
||||
memset(ur, 0, sizeof(struct daap_update_request));
|
||||
|
||||
evtimer_set(&ur->timeout, update_refresh_cb, ur);
|
||||
event_base_set(evbase_httpd, &ur->timeout);
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_UPDATE_REFRESH;
|
||||
|
||||
ret = evtimer_add(&ur->timeout, &tv);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add update timeout event\n");
|
||||
|
||||
dmap_send_error(req, "mupd", "Could not register timer");
|
||||
|
||||
update_free(ur);
|
||||
return;
|
||||
}
|
||||
if (DAAP_UPDATE_REFRESH > 0) {
|
||||
evtimer_set(&ur->timeout, update_refresh_cb, ur);
|
||||
event_base_set(evbase_httpd, &ur->timeout);
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_UPDATE_REFRESH;
|
||||
|
||||
ret = evtimer_add(&ur->timeout, &tv);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add update timeout event\n");
|
||||
|
||||
dmap_send_error(req, "mupd", "Could not register timer");
|
||||
|
||||
update_free(ur);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: we may need to keep reqd_rev in there too */
|
||||
ur->req = req;
|
||||
|
|
Loading…
Reference in New Issue