示例#1
0
/**
 * Reads data from the encoder (as much as available) and returns it
 * as a new #page object.
 */
static struct page *
httpd_output_read_page(struct httpd_output *httpd)
{
	size_t size = 0, nbytes;

	if (httpd->unflushed_input >= 65536) {
		/* we have fed a lot of input into the encoder, but it
		   didn't give anything back yet - flush now to avoid
		   buffer underruns */
		encoder_flush(httpd->encoder, NULL);
		httpd->unflushed_input = 0;
	}

	do {
		nbytes = encoder_read(httpd->encoder, httpd->buffer + size,
				      sizeof(httpd->buffer) - size);
		if (nbytes == 0)
			break;

		httpd->unflushed_input = 0;

		size += nbytes;
	} while (size < sizeof(httpd->buffer));

	if (size == 0)
		return NULL;

	return page_new_copy(httpd->buffer, size);
}
示例#2
0
/**
 * Reads data from the encoder (as much as available) and returns it
 * as a new #page object.
 */
static struct page *
httpd_output_read_page(struct httpd_output *httpd)
{
	size_t size = 0, nbytes;

	do {
		nbytes = encoder_read(httpd->encoder, httpd->buffer + size,
				      sizeof(httpd->buffer) - size);
		if (nbytes == 0)
			break;

		size += nbytes;
	} while (size < sizeof(httpd->buffer));

	if (size == 0)
		return NULL;

	return page_new_copy(httpd->buffer, size);
}
static gboolean
httpd_client_out_event(GIOChannel *source,
		       G_GNUC_UNUSED GIOCondition condition, gpointer data)
{
	struct httpd_client *client = data;
	struct httpd_output *httpd = client->httpd;
	GError *error = NULL;
	GIOStatus status;
	gsize bytes_written;
	gint bytes_to_write;

	g_mutex_lock(httpd->mutex);

	assert(condition == G_IO_OUT);
	assert(client->state == RESPONSE);

	if (client->write_source_id == 0) {
		/* another thread has removed the event source while
		   this thread was waiting for httpd->mutex */
		g_mutex_unlock(httpd->mutex);
		return false;
	}

	if (client->current_page == NULL) {
		client->current_page = g_queue_pop_head(client->pages);
		client->current_position = 0;
	}

	bytes_to_write = bytes_left_till_metadata(client);

	if (bytes_to_write == 0) {
		gint metadata_to_write;

		metadata_to_write = client->metadata_current_position;

		if (!client->metadata_sent) {
			status = write_page_to_channel(source,
						       client->metadata,
						       metadata_to_write,
						       &bytes_written, &error);

			client->metadata_current_position += bytes_written;

			if (client->metadata->size
			    - client->metadata_current_position == 0) {
				client->metadata_fill = 0;
				client->metadata_current_position = 0;
				client->metadata_sent = true;
			}
		} else {
			struct page *empty_meta;
			guchar empty_data = 0;

			empty_meta = page_new_copy(&empty_data, 1);

			status = write_page_to_channel(source,
						       empty_meta,
						       metadata_to_write,
						       &bytes_written, &error);

			client->metadata_current_position += bytes_written;

			if (empty_meta->size
			    - client->metadata_current_position == 0) {
				client->metadata_fill = 0;
				client->metadata_current_position = 0;
			}
		}

		bytes_written = 0;
	} else {
		status = write_n_bytes_to_channel(source, client->current_page,
						  client->current_position, bytes_to_write,
						  &bytes_written, &error);
	}

	switch (status) {
	case G_IO_STATUS_NORMAL:
		client->current_position += bytes_written;
		assert(client->current_position <= client->current_page->size);

		if (client->metadata_requested)
			client->metadata_fill += bytes_written;

		if (client->current_position >= client->current_page->size) {
			page_unref(client->current_page);
			client->current_page = NULL;

			if (g_queue_is_empty(client->pages)) {
				/* all pages are sent: remove the
				   event source */
				client->write_source_id = 0;

				g_mutex_unlock(httpd->mutex);
				return false;
			}
		}

		g_mutex_unlock(httpd->mutex);
		return true;

	case G_IO_STATUS_AGAIN:
		g_mutex_unlock(httpd->mutex);
		return true;

	case G_IO_STATUS_EOF:
		/* client has disconnected */

		httpd_client_close(client);
		g_mutex_unlock(httpd->mutex);
		return false;

	case G_IO_STATUS_ERROR:
		/* I/O error */

		g_warning("failed to write to client: %s", error->message);
		g_error_free(error);

		httpd_client_close(client);
		g_mutex_unlock(httpd->mutex);
		return false;
	}

	/* unreachable */
	httpd_client_close(client);
	g_mutex_unlock(httpd->mutex);
	return false;
}
struct page*
icy_server_metadata_page(const struct tag *tag, ...)
{
	va_list args;
	const gchar *tag_items[TAG_NUM_OF_ITEM_TYPES];
	gint last_item, item;
	guint position;
	gchar *icy_string;
	struct page *icy_metadata;
	gchar stream_title[(1 + 255 - 28) * 16]; // Length + Metadata -
						 // "StreamTitle='';StreamUrl='';"
						 // = 4081 - 28

	last_item = -1;

	va_start(args, tag);
	while (1) {
		enum tag_type type;
		const gchar *tag_item;

		type = va_arg(args, enum tag_type);

		if (type == TAG_NUM_OF_ITEM_TYPES)
			break;

		tag_item = tag_get_value(tag, type);

		if (tag_item)
			tag_items[++last_item] = tag_item;
	}
	va_end(args);

	position = item = 0;
	while (position < sizeof(stream_title) && item <= last_item) {
		gint length = 0;

		length = g_strlcpy(stream_title + position,
				   tag_items[item++],
				   sizeof(stream_title) - position);

		position += length;

		if (item <= last_item) {
			length = g_strlcpy(stream_title + position,
					   " - ",
					   sizeof(stream_title) - position);

			position += length;
		}
	}

	icy_string = icy_server_metadata_string(stream_title, "");

	if (icy_string == NULL)
		return NULL;

	icy_metadata = page_new_copy(icy_string, (icy_string[0] * 16) + 1);

	g_free(icy_string);

	return icy_metadata;
}