示例#1
0
static gboolean
client_out_event(G_GNUC_UNUSED GIOChannel *source, GIOCondition condition,
         gpointer data)
{
    struct client *client = data;

    assert(!client_is_expired(client));

    if (condition != G_IO_OUT) {
        client_set_expired(client);
        return false;
    }

    client_write_deferred(client);

    if (client_is_expired(client)) {
        client_close(client);
        return false;
    }

    g_timer_start(client->last_activity);

    if (g_queue_is_empty(client->deferred_send)) {
        /* done sending deferred buffers exist: schedule
           read */
        client->source_id = g_io_add_watch(client->channel,
                           G_IO_IN|G_IO_ERR|G_IO_HUP,
                           client_in_event, client);
        return false;
    }

    /* write more */
    return true;
}
示例#2
0
void
client_write_output(struct client *client)
{
	if (client_is_expired(client) || !client->send_buf_used)
		return;

	if (!g_queue_is_empty(client->deferred_send)) {
		client_defer_output(client, client->send_buf,
				    client->send_buf_used);

		if (client_is_expired(client))
			return;

		/* try to flush the deferred buffers now; the current
		   server command may take too long to finish, and
		   meanwhile try to feed output to the client,
		   otherwise it will time out.  One reason why
		   deferring is slow might be that currently each
		   client_write() allocates a new deferred buffer.
		   This should be optimized after MPD 0.14. */
		client_write_deferred(client);
	} else
		client_write_direct(client, client->send_buf,
				    client->send_buf_used);

	client->send_buf_used = 0;
}
示例#3
0
gboolean
client_in_event(G_GNUC_UNUSED GIOChannel *source, GIOCondition condition,
        gpointer data)
{
    struct client *client = data;
    enum command_return ret;

    assert(!client_is_expired(client));

    if (condition != G_IO_IN) {
        client_set_expired(client);
        return false;
    }

    g_timer_start(client->last_activity);

    ret = client_read(client);
    switch (ret) {
    case COMMAND_RETURN_OK:
    case COMMAND_RETURN_ERROR:
        break;

    case COMMAND_RETURN_KILL:
        client_close(client);
        //g_main_loop_quit(main_loop);
        return false;

    case COMMAND_RETURN_CLOSE:
        client_close(client);
        return false;
    }

    if (client_is_expired(client)) {
        client_close(client);
        return false;
    }

    if (!g_queue_is_empty(client->deferred_send)) {
        /* deferred buffers exist: schedule write */
        client->source_id = g_io_add_watch(client->channel,
                           G_IO_OUT|G_IO_ERR|G_IO_HUP,
                           client_out_event, client);
        return false;
    }

    /* read more */
    return true;
}
示例#4
0
void
client_idle_add(struct client *client, unsigned flags)
{
	if (client_is_expired(client))
		return;

	client->idle_flags |= flags;
	if (client->idle_waiting
	    && (client->idle_flags & client->idle_subscriptions)) {
		client_idle_notify(client);
		client_write_output(client);
	}
}
示例#5
0
/**
 * Write a block of data to the client.
 */
static void client_write(struct client *client, const char *buffer, size_t buflen)
{
	/* if the client is going to be closed, do nothing */
	if (client_is_expired(client))
		return;

	while (buflen > 0 && !client_is_expired(client)) {
		size_t copylen;

		assert(client->send_buf_used < sizeof(client->send_buf));

		copylen = sizeof(client->send_buf) - client->send_buf_used;
		if (copylen > buflen)
			copylen = buflen;

		memcpy(client->send_buf + client->send_buf_used, buffer,
		       copylen);
		buflen -= copylen;
		client->send_buf_used += copylen;
		buffer += copylen;
		if (client->send_buf_used >= sizeof(client->send_buf))
			client_write_output(client);
	}
}
示例#6
0
文件: client.c 项目: azuwis/mpd
static void
client_idle_callback(gpointer data, gpointer user_data)
{
    struct client *client = data;
    unsigned flags = GPOINTER_TO_UINT(user_data);

    if (client_is_expired(client))
        return;

    client->idle_flags |= flags;
    if (client->idle_waiting
            && (client->idle_flags & client->idle_subscriptions)) {
        client_idle_notify(client);
        client_write_output(client);
    }
}
示例#7
0
文件: client.c 项目: azuwis/mpd
static void
client_check_expired_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
{
    struct client *client = data;

    if (client_is_expired(client)) {
        g_debug("[%u] expired", client->num);
        client_close(client);
    } else if (!client->idle_waiting && /* idle clients
					       never expire */
               time(NULL) - client->lastTime >
               client_timeout) {
        g_debug("[%u] timeout", client->num);
        client_close(client);
    }
}
示例#8
0
文件: client.c 项目: azuwis/mpd
static inline void client_set_expired(struct client *client)
{
    if (expire_source_id == 0 && !client_is_expired(client))
        /* delayed deletion */
        expire_source_id = g_idle_add(client_manager_expire_event,
                                      NULL);

    if (client->source_id != 0) {
        g_source_remove(client->source_id);
        client->source_id = 0;
    }

    if (client->channel != NULL) {
        g_io_channel_unref(client->channel);
        client->channel = NULL;
    }
}
示例#9
0
static enum command_return
client_process_command_list(struct client *client, bool list_ok, GSList *list)
{
    enum command_return ret = COMMAND_RETURN_OK;
    unsigned num = 0;

    for (GSList *cur = list; cur != NULL; cur = g_slist_next(cur)) {
        char *cmd = cur->data;

        g_debug("command_process_list: process command \"%s\"",
        cmd);
        ret = command_process(client, num++, cmd);
        g_debug("command_process_list: command returned %i", ret);
        if (ret != COMMAND_RETURN_OK || client_is_expired(client))
            break;
        else if (list_ok)
            client_puts(client, "list_OK\n");
    }

    return ret;
}
示例#10
0
文件: client.c 项目: azuwis/mpd
static int client_input_received(struct client *client, size_t bytesRead)
{
    char *line;
    int ret;

    fifo_buffer_append(client->input, bytesRead);

    /* process all lines */

    while ((line = client_read_line(client)) != NULL) {
        ret = client_process_line(client, line);
        g_free(line);

        if (ret == COMMAND_RETURN_KILL ||
                ret == COMMAND_RETURN_CLOSE)
            return ret;
        if (client_is_expired(client))
            return COMMAND_RETURN_CLOSE;
    }

    return 0;
}
示例#11
0
enum command_return
client_process_line(struct client *client, char *line)
{
    enum command_return ret;

    if (strcmp(line, "noidle") == 0) {
        if (client->idle_waiting) {
            /* send empty idle response and leave idle mode */
            client->idle_waiting = false;
            command_success(client);
            client_write_output(client);
        }

        /* do nothing if the client wasn't idling: the client
           has already received the full idle response from
           client_idle_notify(), which he can now evaluate */

        return COMMAND_RETURN_OK;
    } else if (client->idle_waiting) {
        /* during idle mode, clients must not send anything
           except "noidle" */
        g_warning("[%u] command \"%s\" during idle",
                  client->num, line);
        return COMMAND_RETURN_CLOSE;
    }

    if (client->cmd_list_OK >= 0) {
        if (strcmp(line, CLIENT_LIST_MODE_END) == 0) {
            g_debug("[%u] process command list",
                    client->num);

            /* for scalability reasons, we have prepended
               each new command; now we have to reverse it
               to restore the correct order */
            client->cmd_list = g_slist_reverse(client->cmd_list);

            ret = client_process_command_list(client,
                                              client->cmd_list_OK,
                                              client->cmd_list);
            g_debug("[%u] process command "
                    "list returned %i", client->num, ret);

            if (ret == COMMAND_RETURN_CLOSE ||
                    client_is_expired(client))
                return COMMAND_RETURN_CLOSE;

            if (ret == COMMAND_RETURN_OK)
                command_success(client);

            client_write_output(client);
            free_cmd_list(client->cmd_list);
            client->cmd_list = NULL;
            client->cmd_list_OK = -1;
        } else {
            size_t len = strlen(line) + 1;
            client->cmd_list_size += len;
            if (client->cmd_list_size >
                    client_max_command_list_size) {
                g_warning("[%u] command list size (%lu) "
                          "is larger than the max (%lu)",
                          client->num,
                          (unsigned long)client->cmd_list_size,
                          (unsigned long)client_max_command_list_size);
                return COMMAND_RETURN_CLOSE;
            }

            new_cmd_list_ptr(client, line);
            ret = COMMAND_RETURN_OK;
        }
    } else {
        if (strcmp(line, CLIENT_LIST_MODE_BEGIN) == 0) {
            client->cmd_list_OK = 0;
            ret = COMMAND_RETURN_OK;
        } else if (strcmp(line, CLIENT_LIST_OK_MODE_BEGIN) == 0) {
            client->cmd_list_OK = 1;
            ret = COMMAND_RETURN_OK;
        } else {
            g_debug("[%u] process command \"%s\"",
            client->num, line);
            ret = command_process(client, 0, line);
            g_debug("[%u] command returned %i",
            client->num, ret);

            if (ret == COMMAND_RETURN_CLOSE ||
            client_is_expired(client))
                return COMMAND_RETURN_CLOSE;

            if (ret == COMMAND_RETURN_OK)
                command_success(client);

            client_write_output(client);
        }
    }

    return ret;
}