From ba251b16aebd84ae2b75b1747efe0c588fff91d2 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Wed, 20 Jan 2010 18:24:52 +0100 Subject: [PATCH] Start keeping track of DAAP sessions This will soon be required as we'll need to keep some knowledge about the session in some cases. This also makes us a bit more compliant. --- src/httpd_daap.c | 182 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 170 insertions(+), 12 deletions(-) diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 2645bb78..60d6117f 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -55,6 +55,10 @@ struct uri_map { void (*handler)(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query); }; +struct daap_session { + int id; +}; + #define DMAP_TYPE_BYTE 0x01 #define DMAP_TYPE_UBYTE 0x02 #define DMAP_TYPE_SHORT 0x03 @@ -330,10 +334,26 @@ static char *default_meta_group = "dmap.itemname,dmap.persistentid,daap.songalbu static avl_tree_t *dmap_fields_hash; -/* Next session ID */ -static int session_id; +/* DAAP session tracking */ +static avl_tree_t *daap_sessions; +static int next_session_id; +static int +daap_session_compare(const void *aa, const void *bb) +{ + struct daap_session *a = (struct daap_session *)aa; + struct daap_session *b = (struct daap_session *)bb; + + if (a->id < b->id) + return -1; + + if (a->id > b->id) + return 1; + + return 0; +} + static int dmap_field_map_compare(const void *aa, const void *bb) { @@ -557,6 +577,78 @@ static void daap_send_error(struct evhttp_request *req, char *container, char *errmsg); +/* Session handling */ +static struct daap_session * +daap_session_register(void) +{ + struct daap_session *s; + avl_node_t *node; + + s = (struct daap_session *)malloc(sizeof(struct daap_session)); + if (!s) + { + DPRINTF(E_LOG, L_DAAP, "Out of memory for DAAP session\n"); + return NULL; + } + + memset(s, 0, sizeof(struct daap_session)); + + s->id = next_session_id; + + next_session_id++; + + node = avl_insert(daap_sessions, s); + if (!node) + { + DPRINTF(E_LOG, L_DAAP, "Could not register DAAP session: %s\n", strerror(errno)); + + free(s); + return NULL; + } + + return s; +} + +static void +daap_session_kill(struct daap_session *s) +{ + avl_delete(daap_sessions, s); +} + +static struct daap_session * +daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct evbuffer *evbuf) +{ + struct daap_session needle; + avl_node_t *node; + const char *param; + int ret; + + param = evhttp_find_header(query, "session-id"); + if (!param) + { + DPRINTF(E_WARN, L_DAAP, "No session-id specified in request\n"); + goto invalid; + } + + ret = safe_atoi(param, &needle.id); + if (ret < 0) + goto invalid; + + node = avl_search(daap_sessions, &needle); + if (!node) + { + DPRINTF(E_WARN, L_DAAP, "DAAP session id %d not found\n", needle.id); + goto invalid; + } + + return (struct daap_session *)node->item; + + invalid: + evhttp_send_reply(req, 403, "Forbidden", evbuf); + return NULL; +} + + static struct dmap_field_map * dmap_find_field(uint32_t hash) { @@ -851,6 +943,7 @@ daap_reply_content_codes(struct evhttp_request *req, struct evbuffer *evbuf, cha static void daap_reply_login(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; int ret; ret = evbuffer_expand(evbuf, 32); @@ -862,12 +955,16 @@ daap_reply_login(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, return; } + s = daap_session_register(); + if (!s) + { + daap_send_error(req, "mlog", "Could not start session"); + return; + } + dmap_add_container(evbuf, "mlog", 24); dmap_add_int(evbuf, "mstt", 200); /* 12 */ - dmap_add_int(evbuf, "mlid", session_id); /* 12 */ - - /* We don't actually care about session id at the moment */ - session_id++; + dmap_add_int(evbuf, "mlid", s->id); /* 12 */ evhttp_send_reply(req, HTTP_OK, "OK", evbuf); } @@ -875,6 +972,14 @@ daap_reply_login(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, static void daap_reply_logout(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; + + s = daap_session_find(req, query, evbuf); + if (!s) + return; + + daap_session_kill(s); + evhttp_send_reply(req, 204, "Logout Successful", evbuf); } @@ -915,12 +1020,17 @@ daap_reply_activity(struct evhttp_request *req, struct evbuffer *evbuf, char **u static void daap_reply_dblist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; cfg_t *lib; char *name; int namelen; int count; int ret; + s = daap_session_find(req, query, evbuf); + if (!s) + return; + lib = cfg_getnsec(cfg, "library", 0); name = cfg_getstr(lib, "name"); namelen = strlen(name); @@ -1306,15 +1416,26 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf, static void daap_reply_dbsonglist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; + + s = daap_session_find(req, query, evbuf); + if (!s) + return; + daap_reply_songlist_generic(req, evbuf, -1, query); } static void daap_reply_plsonglist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; int playlist; int ret; + s = daap_session_find(req, query, evbuf); + if (!s) + return; + ret = safe_atoi(uri[3], &playlist); if (ret < 0) { @@ -1331,6 +1452,7 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char ** { struct query_params qp; struct db_playlist_info dbpli; + struct daap_session *s; struct evbuffer *playlistlist; struct evbuffer *playlist; struct dmap_field_map *dfm; @@ -1344,6 +1466,10 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char ** int i; int ret; + s = daap_session_find(req, query, evbuf); + if (!s) + return; + ret = evbuffer_expand(evbuf, 61); if (ret < 0) { @@ -1559,6 +1685,7 @@ daap_reply_groups(struct evhttp_request *req, struct evbuffer *evbuf, char **uri { struct query_params qp; struct db_group_info dbgri; + struct daap_session *s; struct evbuffer *group; struct evbuffer *grouplist; struct dmap_field_map *dfm; @@ -1573,6 +1700,10 @@ daap_reply_groups(struct evhttp_request *req, struct evbuffer *evbuf, char **uri int ret; char *tag; + s = daap_session_find(req, query, evbuf); + if (!s) + return; + /* For now we only support album groups */ tag = "agal"; @@ -1793,12 +1924,17 @@ static void daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { struct query_params qp; + struct daap_session *s; struct evbuffer *itemlist; char *browse_item; char *tag; int nitems; int ret; + s = daap_session_find(req, query, evbuf); + if (!s) + return; + memset(&qp, 0, sizeof(struct query_params)); if (strcmp(uri[3], "artists") == 0) @@ -1919,6 +2055,12 @@ daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri static void daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; + + s = daap_session_find(req, query, evbuf); + if (!s) + return; + /* Sorry, we have no artwork */ evhttp_send_reply(req, HTTP_NOCONTENT, "No Content", evbuf); } @@ -1926,9 +2068,14 @@ daap_reply_extra_data(struct evhttp_request *req, struct evbuffer *evbuf, char * static void daap_stream(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) { + struct daap_session *s; int id; int ret; + s = daap_session_find(req, query, evbuf); + if (!s) + return; + ret = safe_atoi(uri[3], &id); if (ret < 0) evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request"); @@ -2238,7 +2385,7 @@ daap_init(void) int i; int ret; - session_id = 100; /* gotta start somewhere, right? */ + next_session_id = 100; /* gotta start somewhere, right? */ ret = daap_query_init(); if (ret < 0) @@ -2256,12 +2403,20 @@ daap_init(void) } } + daap_sessions = avl_alloc_tree(daap_session_compare, free); + if (!daap_sessions) + { + DPRINTF(E_FATAL, L_DAAP, "DAAP init could not allocate DAAP sessions AVL tree\n"); + + goto daap_avl_alloc_fail; + } + dmap_fields_hash = avl_alloc_tree(dmap_field_map_compare, NULL); if (!dmap_fields_hash) { - DPRINTF(E_FATAL, L_DAAP, "DAAP init could not allocate AVL tree\n"); + DPRINTF(E_FATAL, L_DAAP, "DAAP init could not allocate DMAP fields AVL tree\n"); - goto avl_alloc_fail; + goto dmap_avl_alloc_fail; } for (i = 0; dmap_fields[i].type != 0; i++) @@ -2284,15 +2439,17 @@ daap_init(void) DPRINTF(E_FATAL, L_DAAP, "Hash %x, string %s\n", dfm->hash, dfm->desc); } - goto avl_insert_fail; + goto dmap_avl_insert_fail; } } return 0; - avl_insert_fail: + dmap_avl_insert_fail: avl_free_tree(dmap_fields_hash); - avl_alloc_fail: + dmap_avl_alloc_fail: + avl_free_tree(daap_sessions); + daap_avl_alloc_fail: for (i = 0; daap_handlers[i].handler; i++) regfree(&daap_handlers[i].preg); regexp_fail: @@ -2311,5 +2468,6 @@ daap_deinit(void) for (i = 0; daap_handlers[i].handler; i++) regfree(&daap_handlers[i].preg); + avl_free_tree(daap_sessions); avl_free_tree(dmap_fields_hash); }