예제 #1
0
/**
 * This handles requests that are daap-related.  For example,
 * /server-info, /login, etc.  This should really be split up
 * into multiple functions, and perhaps moved into daap.c
 *
 * \param pwsc Webserver connection info, passed from the webserver
 *
 * \todo Decomplexify this!
 */
void daap_handler(WS_CONNINFO *pwsc) {
    int close;
    DAAP_BLOCK *root;
    int clientrev;

    /* for the /databases URI */
    char *uri;
    unsigned long int db_index;
    unsigned long int playlist_index;
    unsigned long int item=0;
    char *first, *last;
    char* index = 0;
    int streaming=0;
    int compress =0;
    int start_time;
    int end_time;
    int bytes_written;

    MP3FILE *pmp3;
    int file_fd;
    int session_id=0;

    int img_fd;
    struct stat sb;
    long img_size;

    off_t offset=0;
    off_t real_len;
    off_t file_len;

    int bytes_copied=0;

    GZIP_STREAM *gz;

    close=pwsc->close;
    pwsc->close=1;  /* in case we have any errors */
    root=NULL;

    ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
    ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/%s",VERSION);
    ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged");

    if(ws_getvar(pwsc,"session-id")) {
        session_id=atoi(ws_getvar(pwsc,"session-id"));
    }

    if(!strcasecmp(pwsc->uri,"/server-info")) {
        config_set_status(pwsc,session_id,"Sending server info");
        root=daap_response_server_info(config.servername,
                                       ws_getrequestheader(pwsc,"Client-DAAP-Version"));
    } else if (!strcasecmp(pwsc->uri,"/content-codes")) {
        config_set_status(pwsc,session_id,"Sending content codes");
        root=daap_response_content_codes();
    } else if (!strcasecmp(pwsc->uri,"/login")) {
        config_set_status(pwsc,session_id,"Logging in");
        root=daap_response_login(pwsc->hostname);
    } else if (!strcasecmp(pwsc->uri,"/update")) {
        if(!ws_getvar(pwsc,"delta")) { /* first check */
            clientrev=db_version() - 1;
            config_set_status(pwsc,session_id,"Sending database");
        } else {
            clientrev=atoi(ws_getvar(pwsc,"delta"));
            config_set_status(pwsc,session_id,"Waiting for DB updates");
        }
        root=daap_response_update(pwsc->fd,clientrev);
        if((ws_getvar(pwsc,"delta")) && (root==NULL)) {
            DPRINTF(E_LOG,L_WS,"Client %s disconnected\n",pwsc->hostname);
            config_set_status(pwsc,session_id,NULL);
            pwsc->close=1;
            return;
        }
    } else if (!strcasecmp(pwsc->uri,"/logout")) {
        config_set_status(pwsc,session_id,NULL);
        ws_returnerror(pwsc,204,"Logout Successful");
        return;
    } else if(strcmp(pwsc->uri,"/databases")==0) {
        config_set_status(pwsc,session_id,"Sending database info");
        root=daap_response_dbinfo(config.servername);
        if(0 != (index = ws_getvar(pwsc, "index")))
            daap_handle_index(root, index);
    } else if(strncmp(pwsc->uri,"/databases/",11) == 0) {

        /* the /databases/ uri will either be:
         *
         * /databases/id/items, which returns items in a db
         * /databases/id/containers, which returns a container
         * /databases/id/containers/id/items, which returns playlist elements
         * /databases/id/items/id.mp3, to spool an mp3
 * /databases/id/browse/category
         */

        uri = strdup(pwsc->uri);
        first=(char*)&uri[11];
        last=first;
        while((*last) && (*last != '/')) {
            last++;
        }

        if(*last) {
            *last='\0';
            db_index=atoll(first);

            last++;

            if(strncasecmp(last,"items/",6)==0) {
                /* streaming */
                first=last+6;
                while((*last) && (*last != '.'))
                    last++;

                if(*last == '.') {
                    *last='\0';
                    item=atoll(first);
                    streaming=1;
                    DPRINTF(E_DBG,L_DAAP|L_WS,"Streaming request for id %lu\n",item);
                }
                free(uri);
            } else if (strncasecmp(last,"items",5)==0) {
                /* songlist */
                free(uri);
                // pass the meta field request for processing
                // pass the query request for processing
                root=daap_response_songlist(ws_getvar(pwsc,"meta"),
                                            ws_getvar(pwsc,"query"));
                config_set_status(pwsc,session_id,"Sending songlist");
            } else if (strncasecmp(last,"containers/",11)==0) {
                /* playlist elements */
                first=last + 11;
                last=first;
                while((*last) && (*last != '/')) {
                    last++;
                }

                if(*last) {
                    *last='\0';
                    playlist_index=atoll(first);
                    // pass the meta list info for processing
                    root=daap_response_playlist_items(playlist_index,
                                                      ws_getvar(pwsc,"meta"),
                                                      ws_getvar(pwsc,"query"));
                }
                free(uri);
                config_set_status(pwsc,session_id,"Sending playlist info");
            } else if (strncasecmp(last,"containers",10)==0) {
                /* list of playlists */
                free(uri);
                root=daap_response_playlists(config.servername);
                config_set_status(pwsc,session_id,"Sending playlist info");
            } else if (strncasecmp(last,"browse/",7)==0) {
                config_set_status(pwsc,session_id,"Compiling browse info");
                root = daap_response_browse(last + 7,
                                            ws_getvar(pwsc, "filter"));
                config_set_status(pwsc,session_id,"Sending browse info");
                free(uri);
            }
        }

        // prune the full list if an index range was specified
        if(0 != (index = ws_getvar(pwsc, "index")))
            daap_handle_index(root, index);
    }

    if((!root)&&(!streaming)) {
        DPRINTF(E_DBG,L_WS|L_DAAP,"Bad request -- root=%x, streaming=%d\n",root,streaming);
        ws_returnerror(pwsc,400,"Invalid Request");
        config_set_status(pwsc,session_id,NULL);
        return;
    }

    pwsc->close=close;

    if(!streaming) {
        DPRINTF(E_DBG,L_WS,"Satisfying request\n");

        if((config.compress) && ws_testrequestheader(pwsc,"Accept-Encoding","gzip") && root->reported_size >= 1000) {
          compress=1;
        }

        DPRINTF(E_DBG,L_WS|L_DAAP,"Serializing\n");
        start_time = time(NULL);
        if (compress) {
          DPRINTF(E_DBG,L_WS|L_DAAP,"Using compression: %s\n", pwsc->uri);
          gz = gzip_alloc();
          daap_serialize(root,pwsc->fd,gz);
          gzip_compress(gz);
          bytes_written = gz->bytes_out;
          ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
          ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written);
          ws_addresponseheader(pwsc,"Content-Encoding","gzip");
          DPRINTF(E_DBG,L_WS,"Emitting headers\n");
          ws_emitheaders(pwsc);
          if (gzip_close(gz,pwsc->fd) != bytes_written) {
            DPRINTF(E_LOG,L_WS|L_DAAP,"Error compressing data\n");
          }
          DPRINTF(E_DBG,L_WS|L_DAAP,"Compression ratio: %f\n",((double) bytes_written)/(8.0 + root->reported_size))
        }
        else {
예제 #2
0
/**
 * do the transcode, emitting the headers, content type,
 * and shoving the file down the wire
 *
 * @param pwsc connection to transcode to
 * @param file file to transcode
 * @param codec source codec
 * @param duration time in ms
 * @returns bytes transferred, or -1 on error
 */
int plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, int headers) {
    PLUGIN_ENTRY *ppi, *ptc=NULL;
    PLUGIN_TRANSCODE_FN *pfn = NULL;
    void *vp_ssc;
    int post_error = 1;
    int result = -1;

    /* first, find the plugin that will do the conversion */
    ppi = _plugin_list.next;
    while((ppi) && (!pfn)) {
        if(ppi->pinfo->type & PLUGIN_TRANSCODE) {
            if(strstr(ppi->pinfo->codeclist,pmp3->codectype)) {
                ptc = ppi;
                pfn = ppi->pinfo->transcode_fns;
            }
        }
        ppi = ppi->next;
    }

    if(pfn) {
        DPRINTF(E_DBG,L_PLUG,"Transcoding %s with %s\n",pmp3->path,
                ptc->pinfo->server);

        vp_ssc = pfn->ssc_init();
        if(vp_ssc) {
            if(pfn->ssc_open(vp_ssc,pmp3)) {
                /* start reading and throwing */
                if(headers) {
                    ws_addresponseheader(pwsc,"Content-Type","audio/wav");
                    ws_addresponseheader(pwsc,"Connection","Close");
                    if(!offset) {
                        ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
                    } else {
                        ws_addresponseheader(pwsc,"Content-Range",
                                             "bytes %ld-*/*",
                                             (long)offset);
                        ws_writefd(pwsc,"HTTP/1.1 206 Partial Content\r\n");
                    }
                    ws_emitheaders(pwsc);
                }

                /* start reading/writing */
                result = __plugin_ssc_copy(pwsc,pfn,vp_ssc,offset);
                post_error = 0;
                pfn->ssc_close(vp_ssc);
            } else {
                DPRINTF(E_LOG,L_PLUG,"Error opening %s for ssc: %s\n",
                        pmp3->path,pfn->ssc_error(vp_ssc));
            }
            pfn->ssc_deinit(vp_ssc);
        } else {
            DPRINTF(E_LOG,L_PLUG,"Error initializing transcoder: %s\n",
                    ptc->pinfo->server);
        }
    }

    if(post_error) {
        pwsc->error = EPERM; /* ?? */
        ws_returnerror(pwsc,500,"Internal error");
    }

    return result;
}