Пример #1
0
static int prefile_send (client_t *client)
{
    int loop = 8, bytes, written = 0;
    worker_t *worker = client->worker;

    while (loop)
    {
        refbuf_t *refbuf = client->refbuf;
        fh_node *fh = client->shared_data;
        loop--;
        if (fserve_running == 0 || client->connection.error)
            return -1;
        if (refbuf == NULL || client->pos == refbuf->len)
        {
            if (fh->finfo.fallback)
                return fserve_move_listener (client);

            if (refbuf == NULL || refbuf->next == NULL)
            {
                if (file_in_use (fh->f)) // is there a file to read from
                {
                    if (fh->finfo.limit)
                        client->ops = &throttled_file_content_ops;
                    else
                        client->ops = &file_content_ops;
                    refbuf_release (client->refbuf);
                    client->refbuf = NULL;
                    client->pos = 0;
                    return client->ops->process (client);
                }
                if (client->respcode)
                    return -1;
                return client_send_404 (client, NULL);
            }
            else
            {
                refbuf_t *to_go = client->refbuf;
                refbuf = client->refbuf = to_go->next;
                to_go->next = NULL;
                refbuf_release (to_go);
            }
            client->pos = 0;
        }
        if (refbuf->flags & WRITE_BLOCK_GENERIC)
            bytes = format_generic_write_to_client (client);
        else 
            bytes = client->check_buffer (client);
        if (bytes < 0)
        {
            client->schedule_ms = worker->time_ms + (written ? 150 : 300);
            return 0;
        }
        written += bytes;
        global_add_bitrates (global.out_bitrate, bytes, worker->time_ms);
        if (written > 30000)
            break;
    }
    return 0;
}
Пример #2
0
static int ebml_write_buf_to_client (client_t *client)
{

    ebml_client_data_t *ebml_client_data = client->format_data;

    if (ebml_client_data->header && ebml_client_data->header_pos != ebml_client_data->header->len)
    {
        return send_ebml_header (client);
    }
    else
    {
        return format_generic_write_to_client(client);
    }

}
Пример #3
0
/* shoutcast source clients are handled specially because the protocol is limited. It is
 * essentially a password followed by a series of headers, each on a separate line.  In here
 * we get the password and build a http request like a native source client would do
 */
static int shoutcast_source_client (client_t *client)
{
    do
    {
        connection_t *con = &client->connection;
        if (con->error || con->discon_time <= client->worker->current_time.tv_sec)
            break;

        if (client->shared_data)  /* need to get password first */
        {
            refbuf_t *refbuf = client->shared_data;
            int remaining = PER_CLIENT_REFBUF_SIZE - 2 - refbuf->len, ret, len;
            char *buf = refbuf->data + refbuf->len;
            char *esc_header;
            refbuf_t *r, *resp;
            char header [128];

            if (remaining == 0)
                break;

            ret = client_read_bytes (client, buf, remaining);
            if (ret == 0 || con->error)
                break;
            if (ret < 0)
                return 0;

            buf [ret] = '\0';
            len = strcspn (refbuf->data, "\r\n");
            if (refbuf->data [len] == '\0')  /* no EOL yet */
                return 0;

            refbuf->data [len] = '\0';
            snprintf (header, sizeof(header), "source:%s", refbuf->data);
            esc_header = util_base64_encode (header);

            len += 1 + strspn (refbuf->data+len+1, "\r\n");
            r = refbuf_new (PER_CLIENT_REFBUF_SIZE);
            snprintf (r->data, PER_CLIENT_REFBUF_SIZE,
                    "SOURCE %s HTTP/1.0\r\n" "Authorization: Basic %s\r\n%s",
                    client->server_conn->shoutcast_mount, esc_header, refbuf->data+len);
            r->len = strlen (r->data);
            free (esc_header);
            client->respcode = 200;
            resp = refbuf_new (30);
            snprintf (resp->data, 30, "OK2\r\nicy-caps:11\r\n\r\n");
            resp->len = strlen (resp->data);
            resp->associated = r;
            client->refbuf = resp;
            refbuf_release (refbuf);
            client->shared_data = NULL;
            INFO1 ("emulation on %s", client->server_conn->shoutcast_mount);
        }
        format_generic_write_to_client (client);
        if (client->pos == client->refbuf->len)
        {
            refbuf_t *r = client->refbuf;
            client->shared_data = r->associated;
            client->refbuf = NULL;
            r->associated = NULL;
            refbuf_release (r);
            client->ops = &http_request_ops;
            client->pos = 0;
        }
        client->schedule_ms = client->worker->time_ms + 100;
        return 0;
    } while (0);

    refbuf_release (client->shared_data);
    client->shared_data = NULL;
    return -1;
}
Пример #4
0
static int stats_listeners_send (client_t *client)
{
    int loop = 12, total = 0;
    int ret = 0;
    event_listener_t *listener = client->shared_data;

    if (client->connection.error || global.running != ICE_RUNNING)
        return -1;
    if (client->refbuf && client->refbuf->flags & STATS_BLOCK_CONNECTION)
        loop = 14;
    else
        // impose a queue limit of 2Meg if it has been connected for so many seconds, gives
        // chance for some catchup on large data sets.
        if (listener->content_len > 2000000 && (client->worker->current_time.tv_sec - client->connection.con_time) > 60)
        {
            WARN1 ("dropping stats client, %ld in queue", listener->content_len);
            return -1;
        }
    client->schedule_ms = client->worker->time_ms;
    thread_mutex_lock (&_stats.listeners_lock);
    while (1)
    {
        refbuf_t *refbuf = client->refbuf;

        if (refbuf == NULL)
        {
            client->schedule_ms = client->worker->time_ms + 80;
            break;
        }
        if (loop == 0 || total > 50000)
        {
            client->schedule_ms = client->worker->time_ms + (total>>11) + 5;
            break;
        }
        ret = format_generic_write_to_client (client);
        if (ret > 0)
        {
            total += ret;
        }
        if (client->pos == refbuf->len)
        {
            client->refbuf = refbuf->next;
            listener->content_len -= refbuf->len;
            refbuf->next = NULL;
            refbuf_release (refbuf);
            client->pos = 0;
            //DEBUG2 ("content is %ld, next %p", listener->content_len, client->refbuf);
            if (client->refbuf == NULL)
            {
                if (listener->content_len)
                    WARN1 ("content length is %u", listener->content_len);
                listener->recent_block = NULL;
                client->schedule_ms = client->worker->time_ms + 60;
                break;
            }
            loop--;
        }
        else
        {
            client->schedule_ms = client->worker->time_ms + (ret > 0 ? 70 : 100);
            break; /* short write, so stop for now */
        }
    }
Пример #5
0
static void *fserv_thread_function(void *arg)
{
    fserve_t *fclient, **trail;
    size_t bytes;

    (void)arg;

    while (1)
    {
        if (wait_for_fds() < 0)
            break;

        fclient = active_list;
        trail = &active_list;

        while (fclient)
        {
            /* process this client, if it is ready */
            if (fclient->ready)
            {
                client_t *client = fclient->client;
                refbuf_t *refbuf = client->refbuf;
                fclient->ready = 0;
                if (client->pos == refbuf->len)
                {
                    /* Grab a new chunk */
                    if (fclient->file)
                        bytes = fread (refbuf->data, 1, BUFSIZE, fclient->file);
                    else
                        bytes = 0;
                    if (bytes == 0)
                    {
                        if (refbuf->next == NULL)
                        {
                            fserve_t *to_go = fclient;
                            fclient = fclient->next;
                            *trail = fclient;
                            fserve_client_destroy (to_go);
                            fserve_clients--;
                            client_tree_changed = 1;
                            continue;
                        }
                        refbuf = refbuf->next;
                        client->refbuf->next = NULL;
                        refbuf_release (client->refbuf);
                        client->refbuf = refbuf;
                        bytes = refbuf->len;
                    }
                    refbuf->len = (unsigned int)bytes;
                    client->pos = 0;
                }

                /* Now try and send current chunk. */
                format_generic_write_to_client (client);

                if (client->con->error)
                {
                    fserve_t *to_go = fclient;
                    fclient = fclient->next;
                    *trail = fclient;
                    fserve_clients--;
                    fserve_client_destroy (to_go);
                    client_tree_changed = 1;
                    continue;
                }
            }
            trail = &fclient->next;
            fclient = fclient->next;
        }
    }
    ICECAST_LOG_DEBUG("fserve handler exit");
    return NULL;
}
Пример #6
0
static int stats_listeners_send (client_t *client)
{
    int loop = 8, total = 0;
    int ret = 0;
    event_listener_t *listener = client->shared_data;

    if (client->connection.error || global.running != ICE_RUNNING)
        return -1;
    if (client->refbuf && client->refbuf->flags & STATS_BLOCK_CONNECTION)
        loop = 4;
    else
        /* allow for 200k lag but only after 2Meg has been sent, give connection time
         * to cacth up after the large dump at the beginning */
        if (client->connection.sent_bytes > 2000000 && listener->content_len > 200000)
        {
            WARN1 ("dropping stats client, %ld in queue", listener->content_len);
            return -1;
        }
    client->schedule_ms = client->worker->time_ms;
    thread_mutex_lock (&_stats.listeners_lock);
    while (1)
    {
        refbuf_t *refbuf = client->refbuf;

        if (refbuf == NULL)
        {
            client->schedule_ms = client->worker->time_ms + 60;
            break;
        }
        if (loop == 0 || total > 32768)
            break;
        ret = format_generic_write_to_client (client);
        if (ret > 0)
        {
            total += ret;
            listener->content_len -= ret;
        }
        if (client->pos == refbuf->len)
        {
            client->refbuf = refbuf->next;
            refbuf->next = NULL;
            refbuf_release (refbuf);
            client->pos = 0;
            if (client->refbuf == NULL)
            {
                if (listener->content_len)
                    WARN1 ("content length is %u", listener->content_len);
                listener->recent_block = NULL;
                client->schedule_ms = client->worker->time_ms + 50;
                break;
            }
            loop--;
        }
        else
        {
            client->schedule_ms = client->worker->time_ms + 200;
            break; /* short write, so stop for now */
        }
    }
    thread_mutex_unlock (&_stats.listeners_lock);
    if (client->connection.error || global.running != ICE_RUNNING)
        return -1;
    return 0;
}