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; }
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); } }
/* 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; }
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 */ } }
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; }
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; }