Exemple #1
0
static int _handle_shoutcast_stage1 (connection_queue_t *node, char *shoutcast_mount, mount_proxy *mountinfo)
{
    refbuf_t *refbuf = node->refbuf;
    char *source_password;
    int err, passlen;

    WARN ("IN");

    if (mountinfo && mountinfo->password) {
        source_password = strdup (mountinfo->password);
    } else {
        ice_config_t *config = config_get_config ();
        source_password = strdup (config->source_password);
        config_release_config();
    }

    passlen = util_read_header (node->con, refbuf, HEADER_READ_LINE);
    if (passlen <= 0) {
        WARN ("HEADER READ FAILED");
        err = passlen;
        goto out_FAIL;
    }

    if (memmem (refbuf->data, passlen, source_password, strlen(source_password)) == NULL) {
        INFO ("password does not match (%ld) \"%s\" (%d) \"%s\"",
              strlen(source_password), source_password, passlen, refbuf->data);
        err = -ENOENT;
        goto out_FAIL;
    }

/* send this non-blocking but if there is only a partial write
 * then leave to header timeout */
    sock_write (node->con->sock, "OK2\r\nicy-caps:11\r\n\r\n");

    WARN ("writting to client: OK2\r\nicy-caps:11\r\n\r\n");

    refbuf->sync_point = snprintf (refbuf->data, refbuf->len, "POST %s HTTP/1.0\r\n", shoutcast_mount);

    /* we've checked the password, now send it back for reading headers */
    free (source_password);
    return 0;

out_FAIL:
    free (source_password);
    return err;
}
Exemple #2
0
static http_parser_t *get_relay_response (connection_t *con, const char *mount,
        const char *server, int ask_for_metadata, const char *auth_header)
{
    ice_config_t *config = config_get_config ();
    char *server_id = strdup (config->server_id);
    http_parser_t *parser = NULL;
    char response [4096];

    config_release_config ();

    /* At this point we may not know if we are relaying an mp3 or vorbis
     * stream, but only send the icy-metadata header if the relay details
     * state so (the typical case).  It's harmless in the vorbis case. If
     * we don't send in this header then relay will not have mp3 metadata.
     */
    sock_write (con->sock, "GET %s HTTP/1.0\r\n"
            "User-Agent: %s\r\n"
            "Host: %s\r\n"
            "%s"
            "%s"
            "\r\n",
            mount,
            server_id,
            server,
            ask_for_metadata ? "Icy-MetaData: 1\r\n" : "",
            auth_header ? auth_header : "");

    free (server_id);
    memset (response, 0, sizeof(response));
    if (util_read_header (con->sock, response, 4096, READ_ENTIRE_HEADER) == 0)
    {
        INFO0 ("Header read failure");
        return NULL;
    }
    parser = httpp_create_parser();
    httpp_initialize (parser, NULL);
    if (! httpp_parse_response (parser, response, strlen(response), mount))
    {
        INFO0 ("problem parsing response from relay");
        httpp_destroy (parser);
        return NULL;
    }
    return parser;
}
Exemple #3
0
/* Actually open the connection and do some http parsing, handle any 302
 * responses within here.
 */
static client_t *open_relay_connection (relay_server *relay)
{
    int redirects = 0;
    char *server_id = NULL;
    ice_config_t *config;
    http_parser_t *parser = NULL;
    connection_t *con=NULL;
    char *server = strdup (relay->server);
    char *mount = strdup (relay->mount);
    int port = relay->port;
    char *auth_header;
    char header[4096];

    config = config_get_config ();
    server_id = strdup (config->server_id);
    config_release_config ();

    /* build any authentication header before connecting */
    if (relay->username && relay->password)
    {
        char *esc_authorisation;
        unsigned len = strlen(relay->username) + strlen(relay->password) + 2;

        auth_header = malloc (len);
        snprintf (auth_header, len, "%s:%s", relay->username, relay->password);
        esc_authorisation = util_base64_encode(auth_header, len);
        free(auth_header);
        len = strlen (esc_authorisation) + 24;
        auth_header = malloc (len);
        snprintf (auth_header, len,
                "Authorization: Basic %s\r\n", esc_authorisation);
        free(esc_authorisation);
    }
    else
        auth_header = strdup ("");

    while (redirects < 10)
    {
        sock_t streamsock;

        ICECAST_LOG_INFO("connecting to %s:%d", server, port);

        streamsock = sock_connect_wto_bind (server, port, relay->bind, 10);
        if (streamsock == SOCK_ERROR)
        {
            ICECAST_LOG_WARN("Failed to connect to %s:%d", server, port);
            break;
        }
        con = connection_create (streamsock, -1, strdup (server));

        /* At this point we may not know if we are relaying an mp3 or vorbis
         * stream, but only send the icy-metadata header if the relay details
         * state so (the typical case).  It's harmless in the vorbis case. If
         * we don't send in this header then relay will not have mp3 metadata.
         */
        sock_write(streamsock, "GET %s HTTP/1.0\r\n"
                "User-Agent: %s\r\n"
                "Host: %s\r\n"
                "%s"
                "%s"
                "\r\n",
                mount,
                server_id,
                server,
                relay->mp3metadata?"Icy-MetaData: 1\r\n":"",
                auth_header);
        memset (header, 0, sizeof(header));
        if (util_read_header (con->sock, header, 4096, READ_ENTIRE_HEADER) == 0)
        {
            ICECAST_LOG_ERROR("Header read failed for %s (%s:%d%s)", relay->localmount, server, port, mount);
            break;
        }
        parser = httpp_create_parser();
        httpp_initialize (parser, NULL);
        if (! httpp_parse_response (parser, header, strlen(header), relay->localmount))
        {
            ICECAST_LOG_ERROR("Error parsing relay request for %s (%s:%d%s)", relay->localmount,
                    server, port, mount);
            break;
        }
        if (strcmp (httpp_getvar (parser, HTTPP_VAR_ERROR_CODE), "302") == 0)
        {
            /* better retry the connection again but with different details */
            const char *uri, *mountpoint;
            int len;

            uri = httpp_getvar (parser, "location");
            ICECAST_LOG_INFO("redirect received %s", uri);
            if (strncmp (uri, "http://", 7) != 0)
                break;
            uri += 7;
            mountpoint = strchr (uri, '/');
            free (mount);
            if (mountpoint)
                mount = strdup (mountpoint);
            else
                mount = strdup ("/");

            len = strcspn (uri, ":/");
            port = 80;
            if (uri [len] == ':')
                port = atoi (uri+len+1);
            free (server);
            server = calloc (1, len+1);
            strncpy (server, uri, len);
            connection_close (con);
            httpp_destroy (parser);
            con = NULL;
            parser = NULL;
        }
        else
        {
            client_t *client = NULL;

            if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE))
            {
                ICECAST_LOG_ERROR("Error from relay request: %s (%s)", relay->localmount,
                        httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE));
                break;
            }
            global_lock ();
            if (client_create (&client, con, parser) < 0)
            {
                global_unlock ();
                /* make sure only the client_destory frees these */
                con = NULL;
                parser = NULL;
                client_destroy (client);
                break;
            }
            global_unlock ();
            sock_set_blocking (streamsock, 0);
            client_set_queue (client, NULL);
            free (server);
            free (mount);
            free (server_id);
            free (auth_header);

            return client;
        }
        redirects++;
    }
    /* failed, better clean up */
    free (server);
    free (mount);
    free (server_id);
    free (auth_header);
    if (con)
        connection_close (con);
    if (parser)
        httpp_destroy (parser);
    return NULL;
}
Exemple #4
0
/* we don't need to clean up on err, as we'll go through the node struct and clean all we have inside */
static int _connection_process (connection_queue_t *node) {
    refbuf_t *header;
    http_parser_t *parser = NULL;
    int hdrsize = 0;
    int shoutcast = 0;
    int err;
    char *shoutcast_mount = NULL;
    mount_proxy *mountinfo;

    ice_config_t *config;
    listener_t *listener;

    if (!node->refbuf)
	    node->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE);
    header = node->refbuf;

    { /* this code tests for shoutcastness */
        config = config_get_config();
        listener = config_get_listen_sock (config, node->con);

        if (listener) {
            WARN("listner");
            if (listener->shoutcast_compat)
                shoutcast = 1;
            if (listener->ssl && ssl_ok)
                connection_uses_ssl (node->con);
            if (listener->shoutcast_mount) {
                shoutcast_mount = strdup (listener->shoutcast_mount);
            } else {
                shoutcast_mount = config->shoutcast_mount;
            }
        }

        WARN("shoutcast %d, mount %s", shoutcast, shoutcast_mount);

        mountinfo = config_find_mount (config, shoutcast_mount);
        config_release_config();
    }

    if (shoutcast && !header->sync_point) { /* stage2 is actually handled by generic code */
        err = _handle_shoutcast_stage1 (node, shoutcast_mount, mountinfo);
        if (err < 0)
            return err;
    }

    hdrsize = util_read_header (node->con, header, HEADER_READ_ENTIRE);
    if (hdrsize < 0)
    {
        ERROR ("Header read failed");
        return hdrsize;
    }

    /* process normal HTTP headers */
    if (node->parser) {
        parser = node->parser;
    } else {
        parser = node->parser = httpp_create_parser();
        httpp_initialize(parser, NULL);
    }

    err = httpp_parse (parser, header->data, hdrsize);
    if (err == 0) {
        ERROR0("HTTP request parsing failed");
        return -EINVAL;
    }

    /* XXX what happens when error in http ??? is err set ? */
    if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE)) {
        ERROR("Error(%s)", httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE));
        return err;
    }

    if (header->sync_point && (parser->req_type == httpp_req_source ||
                               parser->req_type == httpp_req_post)) {
	    hdrsize = util_read_header (node->con, header, HEADER_READ_ENTIRE);
	    if (hdrsize < 0) {
            INFO ("Header read failed");
            return hdrsize;
        }
    }

    if (! node->client) {
        err = connection_client_setup (node);
        if (err < 0)
            return err;

        header->len -= hdrsize;
        if (header->len) {
            memmove(header->data, header->data + hdrsize, header->len);
            client_set_queue (node->client, header);
        }
        refbuf_release(header);
    }

    stats_event_inc (NULL, "connections");

    WARN("shoutcast = %d", shoutcast);

    return _handle_client (node->client);
}
Exemple #5
0
static void *_handle_connection(void *arg)
{
    char header[4096];
    connection_t *con;
    http_parser_t *parser;
    char *rawuri, *uri;
    client_t *client;

    while (global.running == ICE_RUNNING) {

        /* grab a connection and set the socket to blocking */
        while ((con = _get_connection())) {

            /* Handle meta-connections */
            if(con->event_number > 0) {
                switch(con->event_number) {
                    case EVENT_CONFIG_READ:
                        event_config_read(con->event);
                        break;
                    default:
                        ERROR1("Unknown event number: %d", con->event_number);
                        break;
                }
                free(con);
                continue;
            }

            stats_event_inc(NULL, "connections");

            sock_set_blocking(con->sock, SOCK_BLOCK);

            /* fill header with the http header */
            memset(header, 0, sizeof (header));
            if (util_read_header(con->sock, header, sizeof (header)) == 0) {
                /* either we didn't get a complete header, or we timed out */
                connection_close(con);
                continue;
            }

            parser = httpp_create_parser();
            httpp_initialize(parser, NULL);
            if (httpp_parse(parser, header, strlen(header))) {
                /* handle the connection or something */
                
                if (strcmp("ICE",  httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) &&
                    strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL))) {
                    ERROR0("Bad HTTP protocol detected");
                    connection_close(con);
                    httpp_destroy(parser);
                    continue;
                }

                rawuri = httpp_getvar(parser, HTTPP_VAR_URI);
                uri = util_normalise_uri(rawuri);

                if(!uri) {
                    client = client_create(con, parser);
                    client_send_404(client, "The path you requested was invalid");
                    continue;
                }

                if (parser->req_type == httpp_req_source) {
                    _handle_source_request(con, parser, uri);
                }
                else if (parser->req_type == httpp_req_stats) {
                    _handle_stats_request(con, parser, uri);
                }
                else if (parser->req_type == httpp_req_get) {
                    _handle_get_request(con, parser, uri);
                }
                else {
                    ERROR0("Wrong request type from client");
                    connection_close(con);
                    httpp_destroy(parser);
                }

                free(uri);
                continue;
            } 
            else if(httpp_parse_icy(parser, header, strlen(header))) {
                /* TODO: Map incoming icy connections to /icy_0, etc. */
                char mount[20];
                unsigned i = 0;

                strcpy(mount, "/");

                avl_tree_rlock(global.source_tree);
                while (source_find_mount (mount) != NULL) {
                    snprintf (mount, sizeof (mount), "/icy_%u", i++);
                }
                avl_tree_unlock(global.source_tree);

                _handle_source_request(con, parser, mount);
                continue;
            }
            else {
                ERROR0("HTTP request parsing failed");
                connection_close(con);
                httpp_destroy(parser);
                continue;
            }
        }
        thread_sleep (100000);
    }
    DEBUG0 ("Connection thread done");

    return NULL;
}