Пример #1
0
/* find/create handle and return it with the structure in a locked state */
static fh_node *open_fh (fbinfo *finfo)
{
    fh_node *fh, *result;

    if (finfo->mount == NULL)
        finfo->mount = "";
    fh = calloc (1, sizeof (fh_node));
    memcpy (&fh->finfo, finfo, sizeof (fbinfo));
    if (avl_get_by_key (fh_cache, fh, (void**)&result) == 0)
    {
        free (fh);
        thread_mutex_lock (&result->lock);
        avl_tree_unlock (fh_cache);
        if (finfo->flags & FS_FALLBACK)
        {
            if (result->finfo.type != finfo->type && finfo->type != FORMAT_TYPE_UNDEFINED)
            {
                WARN1 ("format mismatched for %s", finfo->mount);
                thread_mutex_unlock (&result->lock);
                return NULL;
            }
            result->expire = (time_t)-1;
        }
        return result;
    }

    // insert new one
    if (fh->finfo.mount[0])
    {
        char *fullpath= util_get_path_from_normalised_uri (fh->finfo.mount, fh->finfo.flags&FS_USE_ADMIN);
        char *contenttype = fserve_content_type (fullpath);
        format_type_t type = format_get_type (contenttype);

        if (fh->finfo.type == FORMAT_TYPE_UNDEFINED)
            fh->finfo.type = type;
        if (finfo->flags & FS_FALLBACK)
        {
            if (fh->finfo.type != type && type != FORMAT_TYPE_UNDEFINED && fh->finfo.type != FORMAT_TYPE_UNDEFINED)
            {
                avl_tree_unlock (fh_cache);
                free (contenttype);
                free (fullpath);
                free (fh);
                WARN1 ("format mismatched for %s", finfo->mount);
                return NULL;
            }
            fh->expire = (time_t)-1;
            INFO2 ("lookup of fallback file \"%s\" (%d)", finfo->mount, finfo->limit);
        }
        else
            INFO1 ("lookup of \"%s\"", finfo->mount);
        if (file_open (&fh->f, fullpath) < 0)
        {
            INFO1 ("Failed to open \"%s\"", fullpath);
            avl_tree_unlock (fh_cache);
            free (contenttype);
            free (fullpath);
            free (fh);
            return NULL;
        }
        free (fullpath);
        fh->format = calloc (1, sizeof (format_plugin_t));
        fh->format->type = fh->finfo.type;
        fh->format->contenttype = strdup (contenttype);
        free (contenttype);
        if (fh->finfo.type != FORMAT_TYPE_UNDEFINED)
        {
            fh->format->mount = strdup (fh->finfo.mount);
            if (format_get_plugin (fh->format) < 0)
            {
                avl_tree_unlock (fh_cache);
                file_close (&fh->f);
                free (fh->format);
                free (fh);
                return NULL;
            }
        }
        if (fh->finfo.limit)
            fh->out_bitrate = rate_setup (10000, 1000);
    }
    fh->clients = avl_tree_new (client_compare, NULL);
    thread_mutex_create (&fh->lock);
    thread_mutex_lock (&fh->lock);
    avl_insert (fh_cache, fh);
    avl_tree_unlock (fh_cache);

    fh->refcount = 0;
    fh->peak = 0;
    fh->finfo.mount = strdup (finfo->mount);
    fh->finfo.fallback = NULL;

    return fh;
}
Пример #2
0
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source, int response)
{
    ice_config_t *config;

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    config = config_get_config();
    if (global.sources < config->source_limit)
    {
        const char *contenttype;
        const char *expectcontinue;
        mount_proxy *mountinfo;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                config_release_config();
                global_unlock();
                if (response)
                {
                    client_send_403 (source->client, "Content-type not supported");
                    source->client = NULL;
                }
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_GENERIC;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (response)
            {
                client_send_403 (source->client, "internal format allocation problem");
                source->client = NULL;
            }
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

	/* For PUT support we check for 100-continue and send back a 100 to stay in spec */
	expectcontinue = httpp_getvar (source->parser, "expect");
	if (expectcontinue != NULL)
	{
#ifdef HAVE_STRCASESTR
	    if (strcasestr (expectcontinue, "100-continue") != NULL)
#else
	    WARN0("OS doesn't support case insenestive substring checks...");
	    if (strstr (expectcontinue, "100-continue") != NULL)
#endif
	    {
		client_send_100 (source->client);
	    }
	}

        global.sources++;
        stats_event_args (NULL, "sources", "%d", global.sources);
        global_unlock();

        source->running = 1;
        mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL);
        source_update_settings (config, source, mountinfo);
        config_release_config();
        slave_rebuild_mounts();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (response)
    {
        client_send_403 (source->client, "too many sources connected");
        source->client = NULL;
    }

    return -1;
}
Пример #3
0
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source, int response)
{
    ice_config_t *config = config_get_config();

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    if (global.sources < config->source_limit)
    {
        char *contenttype;
        mount_proxy *mountinfo;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                global_unlock();
                config_release_config();
                if (response)
                {
                    client_send_404 (source->client, "Content-type not supported");
                    source->client = NULL;
                }
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_GENERIC;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (response)
            {
                client_send_404 (source->client, "internal format allocation problem");
                source->client = NULL;
            }
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

        global.sources++;
        stats_event_args (NULL, "sources", "%d", global.sources);
        global_unlock();

        source->running = 1;
        mountinfo = config_find_mount (config, source->mount);
        if (mountinfo == NULL)
            source_update_settings (config, source, mountinfo);
        source_recheck_mounts ();
        config_release_config();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (response)
    {
        client_send_404 (source->client, "too many sources connected");
        source->client = NULL;
    }

    return -1;
}
Пример #4
0
static size_t handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream)
{
    auth_client *auth_user = stream;
    unsigned bytes = size * nmemb;
    client_t *client = auth_user->client;
    auth_thread_data *atd = auth_user->thread_data;
    char *header = (char *)ptr, *header_data;

    if (bytes <= 1 || client == NULL)
        return bytes;
    do
    {
        auth_t *auth = auth_user->auth;
        auth_url *url = auth->state;
        int retcode = 0, header_datalen;

        /* replace the EOL with a nul char, libcurl may not provide a nul */
        header [bytes-2] = '\0';
        if (sscanf (ptr, "HTTP%*c%*u.%*u %3d %*c", &retcode) == 1)
        {
            if (retcode == 403)
            {
                char *p = strchr (ptr, ' ') + 1;
                snprintf (atd->errormsg, sizeof(atd->errormsg), "%s", p);
                p = strchr (atd->errormsg, '\r');
                if (p) *p='\0';
            }
            else if ((auth->flags & AUTH_SKIP_IF_SLOW) && retcode >= 400 && retcode < 600)
            {
                snprintf (atd->errormsg, sizeof(atd->errormsg), "auth on %s disabled, response was \'%.200s...\'", auth->mount, header);
                url->stop_req_until = time (NULL) + url->stop_req_duration; /* prevent further attempts for a while */
                client->flags |= CLIENT_AUTHENTICATED;
                return bytes;
            }
        }
        header_data = strchr (header, ':');
        if (header_data == NULL)
            return bytes;
        header_data++;
        header_data += strspn (header_data, " \t");  // find non-space start
        header_datalen = strcspn (header_data, "\r\n"); // find length

        if (strncasecmp (header, url->auth_header, url->auth_header_len) == 0)
        {
            client->flags |= CLIENT_AUTHENTICATED;
            if (header_data)
            {
                if (strstr (header_data, "withintro"))
                    client->flags |= CLIENT_HAS_INTRO_CONTENT;
                if (strstr (header_data, "hijack"))
                    client->flags |= CLIENT_HIJACKER;
                if (strstr (header_data, "0"))
                {
                    WARN0 ("auth header returned with 0 value");
                    client->flags &= ~CLIENT_AUTHENTICATED;
                }
            }
            break;
        }
        if (strncasecmp (header, url->timelimit_header, url->timelimit_header_len) == 0)
        {
            unsigned int limit = 60;
            sscanf (header_data, "%u\r\n", &limit);
            client->connection.discon.time = time(NULL) + limit;
            break;
        }
        if (strncasecmp (header, "icecast-slave:", 14) == 0)
        {
            client->flags |= CLIENT_IS_SLAVE;
            break;
        }

        if (strncasecmp (header, "icecast-auth-message:", 21) == 0)
        {
            snprintf (atd->errormsg, sizeof (atd->errormsg), "%.*s", header_datalen, header_data);
            break;
        }
        if (strncasecmp (header, "ice-username:"******"%s", header_data);
                free (client->username);
                client->username = name;
            }
            break;
        }
        if (strncasecmp (header, "Location:", 9) == 0)
        {
            free (atd->location);
            atd->location = malloc (header_datalen+1);
            if (atd->location)
                snprintf (atd->location, header_datalen+1, "%s", header_data);
            break;
        }
        if (strncasecmp (header, "Mountpoint:", 11) == 0)
        {
            char *mount = malloc (header_datalen+1);
            if (mount)
            {
                snprintf (mount, header_datalen+1, "%s", header_data);
                free (auth_user->mount);
                auth_user->mount = mount;
            }
            break;
        }
        if (strncasecmp (header, "content-type:", 13) == 0)
        {
            format_type_t type = format_get_type (header_data);

            if (client->refbuf && (type == FORMAT_TYPE_AAC || type == FORMAT_TYPE_MPEG))
            {
                struct build_intro_contents *x = (void*)client->refbuf->data;
                x->type = type;
                mpeg_setup (&x->sync, client->connection.ip);
            }
            break;
        }
    } while (0);

    return (int)bytes;
}
Пример #5
0
static size_t handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream)
{
    auth_client *auth_user = stream;
    unsigned bytes = size * nmemb;
    client_t *client = auth_user->client;
    auth_thread_data *atd = auth_user->thread_data;

    if (bytes <= 1) // we should have the EOL at least
        return bytes;
    if (client)
    {
        auth_t *auth = auth_user->auth;
        auth_url *url = auth->state;
        int retcode = 0;
        char *p = ptr;

        /* replace the EOL with a nul char, libcurl may not provide a nul */
        p[bytes-2] = '\0';
        if (sscanf (ptr, "HTTP%*c%*u.%*u %3d %*c", &retcode) == 1)
        {
            if (retcode == 403)
            {
                char *p = strchr (ptr, ' ') + 1;
                snprintf (atd->errormsg, sizeof(atd->errormsg), "%s", p);
                p = strchr (atd->errormsg, '\r');
                if (p) *p='\0';
            }
        }
        if (strncasecmp (ptr, url->auth_header, url->auth_header_len) == 0)
        {
            client->flags |= CLIENT_AUTHENTICATED;
            p = strchr (ptr, ':');
            if (p)
            {
                ++p;
                if (strstr (p, "withintro"))
                    client->flags |= CLIENT_HAS_INTRO_CONTENT;
                if (strstr (p, "hijack"))
                    client->flags |= CLIENT_HIJACKER;
                if (strstr (p, "0"))
                {
                    WARN0 ("auth header returned with 0 value");
                    client->flags &= ~CLIENT_AUTHENTICATED;
                }
            }
        }
        if (strncasecmp (ptr, url->timelimit_header, url->timelimit_header_len) == 0)
        {
            unsigned int limit = 0;
            sscanf ((char *)ptr+url->timelimit_header_len, "%u\r\n", &limit);
            client->connection.discon_time = time(NULL) + limit;
        }
        if (strncasecmp (ptr, "icecast-slave: 1", 16) == 0)
            client->flags |= CLIENT_IS_SLAVE;

        if (strncasecmp (ptr, "icecast-auth-message: ", 22) == 0)
        {
            char *eol;
            snprintf (atd->errormsg, sizeof (atd->errormsg), "%s", (char*)ptr+22);
            eol = strchr (atd->errormsg, '\r');
            if (eol == NULL)
                eol = strchr (atd->errormsg, '\n');
            if (eol)
                *eol = '\0';
        }
        if (strncasecmp (ptr, "ice-username: "******"\r\n");
            char *name = malloc (len+1);
            if (name)
            {
                snprintf (name, len+1, "%s", (char *)ptr+14);
                free (client->username);
                client->username = name;
            }
        }
        if (strncasecmp (ptr, "Location: ", 10) == 0)
        {
            int len = strcspn ((char*)ptr+10, "\r\n");
            free (atd->location);
            atd->location = malloc (len+1);
            snprintf (atd->location, len+1, "%s", (char *)ptr+10);
        }
        if (strncasecmp (ptr, "Mountpoint: ", 12) == 0)
        {
            int len = strcspn ((char*)ptr+12, "\r\n");
            char *mount = malloc (len+1);
            if (mount)
            {
                snprintf (mount, len+1, "%s", (char *)ptr+12);
                free (auth_user->mount);
                auth_user->mount = mount;
            }
        }
        if (strncasecmp (ptr, "content-type: ", 14) == 0)
        {
            format_type_t type = format_get_type ((char*)ptr+14);

            if (client->refbuf && (type == FORMAT_TYPE_AAC || type == FORMAT_TYPE_MPEG))
            {
                struct build_intro_contents *x = (void*)client->refbuf->data;
                x->type = type;
                mpeg_setup (&x->sync, client->connection.ip);
            }
        }
    }

    return (int)bytes;
}
Пример #6
0
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source)
{
    ice_config_t *config = config_get_config();

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    if (global.sources < config->source_limit)
    {
        char *contenttype;
        mount_proxy *mountproxy = config->mounts;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                global_unlock();
                config_release_config();
                if (source->client)
                    client_send_404 (source->client, "Content-type not supported");
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_MP3;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (source->client)
                client_send_404 (source->client, "internal format allocation problem");
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

        global.sources++;
        global_unlock();

        /* set global settings first */
        source->queue_size_limit = config->queue_size_limit;
        source->timeout = config->source_timeout;
        source->burst_size = config->burst_size;

        /* for relays, we don't yet have a client, however we do require one
         * to retrieve the stream from.  This is created here, quite late,
         * because we can't use this client to return an error code/message,
         * so we only do this once we know we're going to accept the source.
         */
        if (source->client == NULL)
            source->client = client_create (source->con, source->parser);

        while (mountproxy)
        {
            if (strcmp (mountproxy->mountname, source->mount) == 0)
            {
                source_apply_mount (source, mountproxy);
                break;
            }
            mountproxy = mountproxy->next;
        }
        config_release_config();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (source->client)
        client_send_404 (source->client, "too many sources connected");

    return -1;
}