From e9cdf8810250ddea43bbb93778b7ce03c5110a88 Mon Sep 17 00:00:00 2001 From: Craig Markwardt Date: Sun, 1 Jan 2012 23:51:51 -0500 Subject: [PATCH] Revert "Fix 30 minute iTunes/DAAP time-out problem" This reverts commit 7a021b2332402a32ad92494db910344f3a428e0a. --- src/httpd_daap.c | 363 +++++++++-------------------------------------- 1 file changed, 69 insertions(+), 294 deletions(-) diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 637c0b8f..3017b3bf 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -59,17 +59,7 @@ extern struct event_base *evbase_httpd; /* Session timeout in seconds */ #define DAAP_SESSION_TIMEOUT 1800 -/* Amount of time update request can pending before we - send a forced response to keep the channel alive */ -#define DAAP_UPDATE_TIMEOUT 1500 -/* How often we poll for database changes */ -#define DAAP_UPDATE_MONITOR_TIMEOUT 10 -/* XXX Workaround before adding revision support in db.c; - Client will not get dynamic updates. The state of the - database at the time of connection is all the client - gets. */ -#define db_revision_number() (2) struct uri_map { regex_t preg; @@ -77,27 +67,14 @@ struct uri_map { void (*handler)(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query); }; -struct daap_update_request; /* Forward */ struct daap_session { int id; struct event timeout; - /* A pending request, if active */ - struct daap_update_request *update_request; }; struct daap_update_request { - - /* Currently pending request */ struct evhttp_request *req; - /* Time-out when an update *must* be sent */ - struct event timeout; - /* Session that this request belongs to */ - struct daap_session *session; - - /* Current revision number client is reporting */ - int revision_number; - int session_id; struct daap_update_request *next; }; @@ -122,16 +99,6 @@ static int next_session_id; /* Update requests */ static struct daap_update_request *update_requests; -/* Global persistent timer that triggers periodically (10 secs). - Checks the database to see if it has changed, and if so, - pushes a response to all outstanding client update requests. */ -static struct event update_monitor_timer; - -/* Forward declaration */ -static void -daap_update_timeout_cb(int fd, short what, void *arg); -static void -update_request_free(struct daap_update_request *ur, int free_conn); /* Session handling */ @@ -150,9 +117,6 @@ daap_session_compare(const void *aa, const void *bb) return 0; } -/* - * daap_session_free - called by avl_delete() - */ static void daap_session_free(void *item) { @@ -160,37 +124,16 @@ daap_session_free(void *item) s = (struct daap_session *)item; - /* If there is a pending request, then close it out */ - if (s->update_request) - update_request_free(s->update_request, 1 /* Close connection */); evtimer_del(&s->timeout); free(s); - - /* XXX does not handle the case the connection being open but no - pending request. The connection stays silently open but - httpd_daapd refuses to acknowledge stale requests on the - connection. - */ } - -/* - * daap_session_kill - recover when connection dies - */ static void daap_session_kill(struct daap_session *s) { - /* NOTE: automatically calls daap_session_free() */ avl_delete(daap_sessions, s); } -/* - * daap_session_timeout_cb - event callback when session inactivity timeout is triggered - * - * fd - dummy - * what - time event fired - * arg - session pointer - */ static void daap_session_timeout_cb(int fd, short what, void *arg) { @@ -206,10 +149,14 @@ daap_session_timeout_cb(int fd, short what, void *arg) static struct daap_session * daap_session_register(void) { +#if 0 struct timeval tv; +#endif struct daap_session *s; avl_node_t *node; +#if 0 int ret; +#endif s = (struct daap_session *)malloc(sizeof(struct daap_session)); if (!s) @@ -221,6 +168,7 @@ daap_session_register(void) memset(s, 0, sizeof(struct daap_session)); s->id = next_session_id; + next_session_id++; evtimer_set(&s->timeout, daap_session_timeout_cb, s); @@ -235,12 +183,14 @@ daap_session_register(void) return NULL; } +#if 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); +#endif /* 0 */ return s; } @@ -249,7 +199,9 @@ struct daap_session * daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct evbuffer *evbuf) { struct daap_session needle; +#if 0 struct timeval tv; +#endif struct daap_session *s; avl_node_t *node; const char *param; @@ -275,6 +227,7 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev s = (struct daap_session *)node->item; +#if 0 event_del(&s->timeout); evutil_timerclear(&tv); @@ -283,6 +236,7 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev 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); +#endif /* 0 */ return s; @@ -291,19 +245,21 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev return NULL; } -/* - * update_request_free - delete update request and remove from list of pending updates - * - * ur - pointer to update request to remove - * free_con - if set, then close the associated HTTP connection - * - */ + +/* Update requests helpers */ static void -update_request_free(struct daap_update_request *ur, int free_conn) +update_fail_cb(struct evhttp_connection *evcon, void *arg) { + struct daap_update_request *ur; struct daap_update_request *p; - if (ur == 0) return; + ur = (struct daap_update_request *)arg; + + DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n"); + + if (ur->req->evcon) + evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL); + if (ur == update_requests) update_requests = ur->next; else @@ -320,34 +276,10 @@ update_request_free(struct daap_update_request *ur, int free_conn) p->next = ur->next; } - if (ur->session) - ur->session->update_request = 0; - - evtimer_del(&ur->timeout); - if (ur->req && ur->req->evcon) - { - evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL); - if (free_conn) evhttp_connection_free(ur->req->evcon); - } - free(ur); } -/* Update requests helpers */ -static void -update_fail_cb(struct evhttp_connection *evcon, void *arg) -{ - struct daap_update_request *ur; - - ur = (struct daap_update_request *)arg; - - DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n"); - - update_request_free(ur, 1 /* Close connection */); -} - - /* DAAP sort headers helpers */ static struct sort_ctx * daap_sort_context_new(void) @@ -700,12 +632,12 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char dmap_add_int(evbuf, "mpro", mpro); /* 12 */ dmap_add_int(evbuf, "apro", apro); /* 12 */ dmap_add_string(evbuf, "minm", name); /* 8 + strlen(name) */ + #if 0 - /* XXX Strangely, if these are enabled, then the client does - not poll for updates, even if msup == 1 */ dmap_add_int(evbuf, "mstm", DAAP_SESSION_TIMEOUT); /* 12 */ dmap_add_char(evbuf, "msal", 1); /* 9 */ #endif + dmap_add_char(evbuf, "mslr", 1); /* 9 */ dmap_add_char(evbuf, "msau", (passwd) ? 2 : 0); /* 9 */ dmap_add_char(evbuf, "msex", 1); /* 9 */ @@ -716,6 +648,7 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char 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); @@ -844,144 +777,13 @@ daap_reply_logout(struct evhttp_request *req, struct evbuffer *evbuf, char **uri httpd_send_reply(req, 204, "Logout Successful", evbuf); } -/* - * Send update response - * s - current DAAP session - * req - evhttp_request we are responding to - * force - whether we are forcing a reply even if the database is unchanged - * Return value: - * -1: error - * 0: did not send - * 1: reply sent OK - */ -static int -daap_update_response(struct daap_update_request *ur, int force) -{ - int db_rev = db_revision_number(); - struct evbuffer *evbuf; - - DPRINTF(E_DBG, L_DAAP, " (update, session-id=%d, old_rev=%d, current_rev=%d, force=%d)\n", - ur->session_id, ur->revision_number, db_rev, force); - if (!force && ur->revision_number == db_rev) return 0; - - evbuf = evbuffer_new(); - if (evbuffer_expand(evbuf, 32) < 0) - { - DPRINTF(E_LOG, L_DAAP, "Could not expand evbuffer for DAAP update reply\n"); - - dmap_send_error(ur->req, "mupd", "Out of memory"); - return -1; - } - - /* Send back current revision */ - dmap_add_container(evbuf, "mupd", 24); - dmap_add_int(evbuf, "mstt", 200); /* 12 */ - dmap_add_int(evbuf, "musr", db_rev); /* 12 */ - - httpd_send_reply(ur->req, HTTP_OK, "OK", evbuf); - evbuffer_free(evbuf); - DPRINTF(E_DBG, L_DAAP, " (reply OK, session-id=%d, old_rev=%d, current_rev=%d)\n", - ur->session_id, ur->revision_number, db_rev); - - ur->revision_number = db_rev; - return 1; -} - -/* - * daap_update_monitor_cb - global database monitor callback - * - * This function is called periodically, to monitor for database updates - * that need to be sent out. - * - * fd - dummy - * what - timer event - * arg - dummy - */ -static void -daap_update_monitor_cb(int fd, short what, void *arg) -{ - struct timeval tv; - int db_rev = db_revision_number(); - int ret; - struct daap_update_request *ur = 0, *next = 0; - - DPRINTF(E_DBG, L_DAAP, "Periodic update monitor event (db-rev=%d)\n", db_rev); - ur = update_requests; - while (ur) - { - next = ur->next; /* Cache a local copy of "next" */ - DPRINTF(E_DBG, L_DAAP, - " (session-id=%d, request=%d, rev=%d)\n", - ur->session_id, ur->req ? 1 : 0, ur->revision_number); - if (! ur->req ) continue; - - /* Send update to client now */ - ret = 0; - if (db_rev != ur->revision_number) - ret = daap_update_response(ur, 1); - - /* If we sent a reply, remove this update request from the linked list */ - if (ret > 0) update_request_free(ur, 0); - - ur = next; /* Advance to next request */ - } - - /* Reset the timer for next monitor cycle */ - evutil_timerclear(&tv); - tv.tv_sec = DAAP_UPDATE_MONITOR_TIMEOUT; - evtimer_add(&update_monitor_timer, &tv); - - return; -} - -/* - * daap_update_timeout_cb - single update timeout callback - * - * Called when an individual session update has timed out - * - * fd - dummy - * what - timer event - * arg - pointer to update request - */ -static void -daap_update_timeout_cb(int fd, short what, void *arg) -{ - struct daap_update_request *ur; - - ur = (struct daap_update_request *) arg; - - if (ur && ur->req) - { - DPRINTF(E_DBG, L_DAAP, "Session update timeout (session-id=%d)\n", ur->session_id); - daap_update_response(ur, 1); - } - - /* Remove update_request from list */ - update_request_free(ur, 0); - - return; -} - - -/* - * daap_reply_update - accept DAAP update request and respond or queue response - * - * Is passed an update request from HTTP server. If an update is available - * already, then it is responded to immediately, otherwise the request is - * queued with other update_requests for later response. - * - * req - HTTP request - * evbuf - response buffer - * uri - parsed URI - * query - parsed query parameters - * - */ static void daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { struct daap_session *s; - struct daap_update_request *ur, update; + struct daap_update_request *ur; const char *param; + int current_rev = 2; int reqd_rev; int ret; @@ -1007,64 +809,47 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri return; } - DPRINTF(E_DBG, L_DAAP, "DAAP update request (revision=%d)\n", reqd_rev); - - memset(&update, 0, sizeof(update)); - update.revision_number = reqd_rev; - update.session_id = s->id; - update.req = req; - - ret = daap_update_response(&update, 0); - if (ret < 0) - return; - - if (ret == 0) + if (reqd_rev == 1) /* Or revision is not valid */ { - struct timeval tv; - /* We did not send a reply immediately because the database is unchanged, - so queue this request for pushing later. */ - - DPRINTF(E_DBG, L_DAAP, "Queuing update request for session-id=%d\n", s->id); - - /* Create daap_update_request structure */ - ur = (struct daap_update_request *)malloc(sizeof(struct daap_update_request)); - if (!ur) + ret = evbuffer_expand(evbuf, 32); + if (ret < 0) { - DPRINTF(E_LOG, L_DAAP, "Out of memory for update request\n"); - + DPRINTF(E_LOG, L_DAAP, "Could not expand evbuffer for DAAP update reply\n"); + dmap_send_error(req, "mupd", "Out of memory"); return; } - *ur = update; /* Copy temporary request info into malloc'd structure */ - ur->req = req; - ur->next = update_requests; - update_requests = ur; /* Add to master list */ - /* Link the session and the request */ - ur->session = s; - s->update_request = ur; + /* Send back current revision */ + dmap_add_container(evbuf, "mupd", 24); + dmap_add_int(evbuf, "mstt", 200); /* 12 */ + dmap_add_int(evbuf, "musr", current_rev); /* 12 */ - /* Set the time-out timer */ - evtimer_set(&ur->timeout, daap_update_timeout_cb, ur); - event_base_set(evbase_httpd, &ur->timeout); - evutil_timerclear(&tv); - tv.tv_sec = DAAP_UPDATE_TIMEOUT; - - ret = evtimer_add(&ur->timeout, &tv); - if (ret < 0) - { - DPRINTF(E_LOG, L_DAAP, "Could not add update timeout event for session %d\n", s->id); - dmap_send_error(req, "mupd", "Timer setting failed"); - return; - } - - /* If the connection fails before we have an update to push out - * to the client, we need to know. - */ - evhttp_connection_set_closecb(req->evcon, update_fail_cb, ur); + httpd_send_reply(req, HTTP_OK, "OK", evbuf); + + return; } - return; + /* Else, just let the request hang until we have changes to push back */ + ur = (struct daap_update_request *)malloc(sizeof(struct daap_update_request)); + if (!ur) + { + DPRINTF(E_LOG, L_DAAP, "Out of memory for update request\n"); + + dmap_send_error(req, "mupd", "Out of memory"); + return; + } + + /* NOTE: we may need to keep reqd_rev in there too */ + ur->req = req; + + ur->next = update_requests; + update_requests = ur; + + /* If the connection fails before we have an update to push out + * to the client, we need to know. + */ + evhttp_connection_set_closecb(req->evcon, update_fail_cb, ur); } static void @@ -2641,25 +2426,10 @@ daap_init(void) char buf[64]; int i; int ret; - struct timeval tv; next_session_id = 100; /* gotta start somewhere, right? */ update_requests = NULL; - /* Add a monitor timer which periodically polls the database revision number */ - evtimer_set(&update_monitor_timer, daap_update_monitor_cb, 0); - event_base_set(evbase_httpd, &update_monitor_timer); - - evutil_timerclear(&tv); - tv.tv_sec = DAAP_UPDATE_MONITOR_TIMEOUT; - ret = evtimer_add(&update_monitor_timer, &tv); - if (ret < 0) - { - DPRINTF(E_FATAL, L_DAAP, "Could not add update monitor timer\n"); - return -1; - } - - /* Initialize handlers */ for (i = 0; daap_handlers[i].handler; i++) { ret = regcomp(&daap_handlers[i].preg, daap_handlers[i].regexp, REG_EXTENDED | REG_NOSUB); @@ -2672,7 +2442,6 @@ daap_init(void) } } - /* Initialize session tree */ daap_sessions = avl_alloc_tree(daap_session_compare, daap_session_free); if (!daap_sessions) { @@ -2701,10 +2470,16 @@ daap_deinit(void) avl_free_tree(daap_sessions); - /* Free any update requests, starting at the beginning */ - while ( (ur = update_requests) ) + for (ur = update_requests; update_requests; ur = update_requests) { - update_request_free(ur, 1 /* Close connection */); - /* Note: update_requests changes */ + update_requests = ur->next; + + if (ur->req->evcon) + { + evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL); + evhttp_connection_free(ur->req->evcon); + } + + free(ur); } }