Ejemplo n.º 1
0
/* Add listener to the pending lists of either the source or fserve thread. This can be run
 * from the connection or auth thread context. return -1 to indicate that client has been
 * terminated, 0 for receiving content.
 */
static int add_authenticated_listener (const char *mount, mount_proxy *mountinfo, client_t *client)
{
    int ret = 0;

    if (client->parser->req_type != httpp_req_head)
        client->flags |= CLIENT_AUTHENTICATED;

    /* some win32 setups do not do TCP win scaling well, so allow an override */
    if (mountinfo && mountinfo->so_sndbuf > 0)
        sock_set_send_buffer (client->connection.sock, mountinfo->so_sndbuf);

    /* check whether we are processing a streamlist request for slaves */
    if (strcmp (mount, "/admin/streams") == 0)
    {
        client->flags |= CLIENT_IS_SLAVE;
        if (client->parser->req_type == httpp_req_stats)
        {
            stats_add_listener (client, STATS_SLAVE|STATS_GENERAL);
            return 0;
        }
        mount = httpp_get_query_param (client->parser, "mount");
        if (mount == NULL)
        {
            command_list_mounts (client, TEXT);
            return 0;
        }
        mountinfo = config_find_mount (config_get_config_unlocked(), mount);
    }

    /* Here we are parsing the URI request to see if the extension is .xsl, if
     * so, then process this request as an XSLT request
     */
    if (util_check_valid_extension (mount) == XSLT_CONTENT)
    {
        /* If the file exists, then transform it, otherwise, write a 404 */
        DEBUG0("Stats request, sending XSL transformed stats");
        return stats_transform_xslt (client, mount);
    }

    ret = source_add_listener (mount, mountinfo, client);

    if (ret == -2)
    {
        if (mountinfo && mountinfo->file_seekable == 0)
        {
            DEBUG1 ("disable seek on file matching %s", mountinfo->mountname);
            httpp_deletevar (client->parser, "range");
            client->flags |= CLIENT_NO_CONTENT_LENGTH;
        }
        ret = fserve_client_create (client, mount);
    }
    return ret;
}
Ejemplo n.º 2
0
/* catch all function for admin requests.  If file has xsl extension then
 * transform it using the available stats, else send the XML tree of the
 * stats
 */
static int command_stats (client_t *client, const char *filename)
{
    admin_response_type response = RAW;
    const char *show_mount = NULL;
    xmlDocPtr doc;

    if (filename)
        if (util_check_valid_extension (filename) == XSLT_CONTENT)
            response = XSLT;

    show_mount = httpp_get_query_param (client->parser, "mount");

    doc = stats_get_xml (STATS_ALL, show_mount);
    return admin_send_response (doc, client, response, filename);
}
Ejemplo n.º 3
0
/* Add listener to the pending lists of either the  source or fserve thread.
 * This can be run from the connection or auth thread context
 */
static int add_authenticated_listener (const char *mount, mount_proxy *mountinfo, client_t *client)
{
    int ret = 0;
    source_t *source = NULL;

    client->authenticated = 1;

    /* Here we are parsing the URI request to see if the extension is .xsl, if
     * so, then process this request as an XSLT request
     */
    if (util_check_valid_extension (mount) == XSLT_CONTENT)
    {
        /* If the file exists, then transform it, otherwise, write a 404 */
        ICECAST_LOG_DEBUG("Stats request, sending XSL transformed stats");
        stats_transform_xslt (client, mount);
        return 0;
    }

    avl_tree_rlock (global.source_tree);
    source = source_find_mount (mount);

    if (source)
    {
        if (mountinfo)
        {
            if (check_duplicate_logins (source, client, mountinfo->auth) == 0)
            {
                avl_tree_unlock (global.source_tree);
                return -1;
            }

            /* set a per-mount disconnect time if auth hasn't set one already */
            if (mountinfo->max_listener_duration && client->con->discon_time == 0)
                client->con->discon_time = time(NULL) + mountinfo->max_listener_duration;
        }

        ret = add_listener_to_source (source, client);
        avl_tree_unlock (global.source_tree);
        if (ret == 0)
            ICECAST_LOG_DEBUG("client authenticated, passed to source");
    }
    else
    {
        avl_tree_unlock (global.source_tree);
        fserve_client_create (client, mount);
    }
    return ret;
}
Ejemplo n.º 4
0
static void _handle_get_request (client_t *client, char *passed_uri)
{
    int fileserve;
    int port;
    int i;
    char *serverhost = NULL;
    int serverport = 0;
    aliases *alias;
    ice_config_t *config;
    char *uri = passed_uri;

    config = config_get_config();
    fileserve = config->fileserve;
    port = config->port;
    for(i = 0; i < global.server_sockets; i++) {
        if(global.serversock[i] == client->con->serversock) {
            serverhost = config->listeners[i].bind_address;
            serverport = config->listeners[i].port;
            break;
        }
    }
    alias = config->aliases;

    /* there are several types of HTTP GET clients
    ** media clients, which are looking for a source (eg, URI = /stream.ogg)
    ** stats clients, which are looking for /admin/stats.xml
    ** and directory server authorizers, which are looking for /GUID-xxxxxxxx 
    ** (where xxxxxx is the GUID in question) - this isn't implemented yet.
    ** we need to handle the latter two before the former, as the latter two
    ** aren't subject to the limits.
    */
    /* TODO: add GUID-xxxxxx */

    /* Handle aliases */
    while(alias) {
        if(strcmp(uri, alias->source) == 0 && (alias->port == -1 || alias->port == serverport) && (alias->bind_address == NULL || (serverhost != NULL && strcmp(alias->bind_address, serverhost) == 0))) {
            uri = strdup (alias->destination);
            DEBUG2 ("alias has made %s into %s", passed_uri, uri);
            break;
        }
        alias = alias->next;
    }
    config_release_config();

    stats_event_inc(NULL, "client_connections");

    /* Dispatch all admin requests */
    if ((strcmp(uri, "/admin.cgi") == 0) ||
        (strncmp(uri, "/admin/", 7) == 0)) {
        admin_handle_request(client, uri);
        if (uri != passed_uri) free (uri);
        return;
    }

    /* Here we are parsing the URI request to see
    ** if the extension is .xsl, if so, then process
    ** this request as an XSLT request
    */
    if (util_check_valid_extension (uri) == XSLT_CONTENT)
    {
        /* If the file exists, then transform it, otherwise, write a 404 */
        DEBUG0("Stats request, sending XSL transformed stats");
        stats_transform_xslt (client, uri);
        if (uri != passed_uri) free (uri);
        return;
    }

    add_client (uri, client);
    if (uri != passed_uri) free (uri);
}
Ejemplo n.º 5
0
static void _handle_get_request(connection_t *con,
        http_parser_t *parser, char *passed_uri)
{
    char *fullpath;
    client_t *client;
    int bytes;
    struct stat statbuf;
    source_t *source;
    int fileserve;
    char *host;
    int port;
    int i;
    char *serverhost = NULL;
    int serverport = 0;
    aliases *alias;
    ice_config_t *config;
    int client_limit;
    int ret;
    char *uri = passed_uri;

    config = config_get_config();
    fileserve = config->fileserve;
    host = config->hostname;
    port = config->port;
    for(i = 0; i < MAX_LISTEN_SOCKETS; i++) {
        if(global.serversock[i] == con->serversock) {
            serverhost = config->listeners[i].bind_address;
            serverport = config->listeners[i].port;
            break;
        }
    }
    alias = config->aliases;
    client_limit = config->client_limit;

    /* there are several types of HTTP GET clients
    ** media clients, which are looking for a source (eg, URI = /stream.ogg)
    ** stats clients, which are looking for /admin/stats.xml
    ** and directory server authorizers, which are looking for /GUID-xxxxxxxx 
    ** (where xxxxxx is the GUID in question) - this isn't implemented yet.
    ** we need to handle the latter two before the former, as the latter two
    ** aren't subject to the limits.
    */
    /* TODO: add GUID-xxxxxx */

    /* Handle aliases */
    while(alias) {
        if(strcmp(uri, alias->source) == 0 && (alias->port == -1 || alias->port == serverport) && (alias->bind_address == NULL || (serverhost != NULL && strcmp(alias->bind_address, serverhost) == 0))) {
            uri = strdup (alias->destination);
            DEBUG2 ("alias has made %s into %s", passed_uri, uri);
            break;
        }
        alias = alias->next;
    }
    config_release_config();

    /* make a client */
    client = client_create(con, parser);
    stats_event_inc(NULL, "client_connections");

    /* Dispatch all admin requests */
    if (strncmp(uri, "/admin/", 7) == 0) {
        admin_handle_request(client, uri);
        if (uri != passed_uri) free (uri);
        return;
    }

    /* Here we are parsing the URI request to see
    ** if the extension is .xsl, if so, then process
    ** this request as an XSLT request
    */
    fullpath = util_get_path_from_normalised_uri(uri);
    if (util_check_valid_extension(fullpath) == XSLT_CONTENT) {
        /* If the file exists, then transform it, otherwise, write a 404 */
        if (stat(fullpath, &statbuf) == 0) {
            DEBUG0("Stats request, sending XSL transformed stats");
            client->respcode = 200;
            bytes = sock_write(client->con->sock, 
                    "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
            if(bytes > 0) client->con->sent_bytes = bytes;
            stats_transform_xslt(client, fullpath);
            client_destroy(client);
        }
        else {
            client_send_404(client, "The file you requested could not be found");
        }
        free(fullpath);
        if (uri != passed_uri) free (uri);
        return;
    }
    else if(fileserve && stat(fullpath, &statbuf) == 0 && 
#ifdef _WIN32
            ((statbuf.st_mode) & _S_IFREG))
#else
            S_ISREG(statbuf.st_mode)) 
#endif
    {
        fserve_client_create(client, fullpath);
        free(fullpath);
        if (uri != passed_uri) free (uri);
        return;
    }
    free(fullpath);

    if(strcmp(util_get_extension(uri), "m3u") == 0) {
        char *sourceuri = strdup(uri);
        char *dot = strrchr(sourceuri, '.');
        *dot = 0;
        client->respcode = 200;
        bytes = sock_write(client->con->sock,
                    "HTTP/1.0 200 OK\r\n"
                    "Content-Type: audio/x-mpegurl\r\n\r\n"
                    "http://%s:%d%s\r\n", 
                    host, 
                    port,
                    sourceuri
                    );
        if(bytes > 0) client->con->sent_bytes = bytes;
        client_destroy(client);
        free(sourceuri);
        if (uri != passed_uri) free (uri);
        return;
    }

    global_lock();
    if (global.clients >= client_limit) {
        global_unlock();
        client_send_404(client,
                "The server is already full. Try again later.");
        if (uri != passed_uri) free (uri);
        return;
    }
    global_unlock();
                    
    avl_tree_rlock(global.source_tree);
    source = source_find_mount(uri);
    if (source) {
        DEBUG0("Source found for client");

        /* The source may not be the requested source - it might have gone
         * via one or more fallbacks. We only reject it for no-mount if it's
         * the originally requested source
         */
        if(strcmp(uri, source->mount) == 0 && source->no_mount) {
            avl_tree_unlock(global.source_tree);
            client_send_404(client, "This mount is unavailable.");
            if (uri != passed_uri) free (uri);
            return;
        }
        if (source->running == 0)
        {
            avl_tree_unlock(global.source_tree);
            DEBUG0("inactive source, client dropped");
            client_send_404(client, "This mount is unavailable.");
            if (uri != passed_uri) free (uri);
            return;
        }

        /* Check for any required authentication first */
        if(source->authenticator != NULL) {
            ret = auth_check_client(source, client);
            if(ret != AUTH_OK) {
                avl_tree_unlock(global.source_tree);
                if (ret == AUTH_FORBIDDEN) {
                    INFO1("Client attempted to log multiple times to source "
                        "(\"%s\")", uri);
                    client_send_403(client);
                }
                else {
                /* If not FORBIDDEN, default to 401 */
                    INFO1("Client attempted to log in to source (\"%s\")with "
                        "incorrect or missing password", uri);
                    client_send_401(client);
                }
                if (uri != passed_uri) free (uri);
                return;
            }
        }

        /* And then check that there's actually room in the server... */
        global_lock();
        if (global.clients >= client_limit) {
            global_unlock();
            avl_tree_unlock(global.source_tree);
            client_send_404(client, 
                    "The server is already full. Try again later.");
            if (uri != passed_uri) free (uri);
            return;
        }
        /* Early-out for per-source max listeners. This gets checked again
         * by the source itself, later. This route gives a useful message to
         * the client, also.
         */
        else if(source->max_listeners != -1 && 
                source->listeners >= source->max_listeners) 
        {
            global_unlock();
            avl_tree_unlock(global.source_tree);
            client_send_404(client, 
                    "Too many clients on this mountpoint. Try again later.");
            if (uri != passed_uri) free (uri);
            return;
        }
        global.clients++;
        global_unlock();
                        
        source->format->create_client_data (source, client);

        source->format->client_send_headers(source->format, source, client);
                        
        bytes = sock_write(client->con->sock, "\r\n");
        if(bytes > 0) client->con->sent_bytes += bytes;
                            
        sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
        sock_set_nodelay(client->con->sock);
                        
        avl_tree_wlock(source->pending_tree);
        avl_insert(source->pending_tree, (void *)client);
        avl_tree_unlock(source->pending_tree);
    }
                    
    avl_tree_unlock(global.source_tree);
                    
    if (!source) {
        DEBUG0("Source not found for client");
        client_send_404(client, "The source you requested could not be found.");
    }
    if (uri != passed_uri) free (uri);
}