Ejemplo n.º 1
0
Archivo: cli.c Proyecto: Juankc125/ivs
static void
client_callback(
    int socket_id,
    void *cookie,
    int read_ready,
    int write_ready,
    int error_seen)
{
    struct client *client = cookie;
    AIM_ASSERT(socket_id == client->fd);

    if (error_seen) {
        int socket_error = 0;
        socklen_t len = sizeof(socket_error);
        getsockopt(socket_id, SOL_SOCKET, SO_ERROR, &socket_error, &len);
        AIM_LOG_INFO("Error seen on CLI socket: %s", strerror(socket_error));
        destroy_client(client);
        return;
    }

    if (read_ready) {
        int c;
        if ((c = read(client->fd, client->read_buffer+client->read_buffer_offset,
                      READ_BUFFER_SIZE - client->read_buffer_offset)) < 0) {
            AIM_LOG_ERROR("read failed: %s", strerror(errno));
            return;
        }

        client->read_buffer_offset += c;

        if (c == 0) {
            /* Peer has shutdown their write side */
            if (client->write_buffer_len == 0 &&
                    aim_pvs_buffer_size(client->write_pvs) == 0) {
                destroy_client(client);
            } else {
                /* We'll destroy the client once we've finished writing to it */
                ind_soc_data_in_pause(client->fd);
                client->read_finished = true;
            }
            return;
        }

        /* Process each complete line */
        char *newline;
        char *start = client->read_buffer;
        int remaining = client->read_buffer_offset;
        while ((newline = memchr(start, '\n', remaining))) {
            *newline = '\0';
            ucli_dispatch_string(client->ucli, client->write_pvs, start);
            remaining -= newline - start + 1;
            start = newline + 1;
        }

        /* Move incomplete line (which may be empty) to the beginning of the read buffer */
        if (client->read_buffer != start) {
            memmove(client->read_buffer, start, remaining);
            client->read_buffer_offset = remaining;
        } else if (client->read_buffer_offset == READ_BUFFER_SIZE) {
            AIM_LOG_WARN("Disconnecting CLI client due to too-long line");
            destroy_client(client);
            return;
        }

        if (aim_pvs_buffer_size(client->write_pvs) > 0) {
            ind_soc_data_out_ready(socket_id);
        }
    }

    if (write_ready) {
        /* Copy PVS data into our write buffer and reset PVS */
        if (client->write_buffer == NULL) {
            client->write_buffer = aim_pvs_buffer_get(client->write_pvs);
            client->write_buffer_len = aim_pvs_buffer_size(client->write_pvs);
            client->write_buffer_offset = 0;
            /* aim_pvs_buffer_reset has a bug, workaround it */
            aim_pvs_destroy(client->write_pvs);
            client->write_pvs = aim_pvs_buffer_create();
        }

        int c = send(client->fd,
                     client->write_buffer+client->write_buffer_offset,
                     client->write_buffer_len-client->write_buffer_offset,
                     MSG_NOSIGNAL);
        if (c <= 0) {
            AIM_LOG_ERROR("write failed: %s", strerror(errno));
            destroy_client(client);
            return;
        }

        client->write_buffer_offset += c;

        /* Free our write buffer if we're finished with it */
        if (client->write_buffer_len == client->write_buffer_offset) {
            aim_free(client->write_buffer);
            client->write_buffer_len = client->write_buffer_offset = 0;
            client->write_buffer = NULL;
            if (aim_pvs_buffer_size(client->write_pvs) == 0) {
                ind_soc_data_out_clear(client->fd);
                if (client->read_finished) {
                    destroy_client(client);
                }
            }
        }
    }
}
Ejemplo n.º 2
0
static void
test_socket(void)
{
    int fds[2];
    struct sock_counters counters[2];
    indigo_time_t start_time, end_time;
    struct itimerval itv;

    signal(SIGALRM, sigalrm);

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
        perror("socketpair");
        abort();
    }

    INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_register(fds[1], socket_callback, &counters[1]) == 0);

    /* No events ready */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Write one byte to fds[0] */
    ind_soc_data_out_ready(fds[0]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Read one byte from fds[1] */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Write one byte to each of fds[0] and fds[1] */
    ind_soc_data_out_ready(fds[0]);
    ind_soc_data_out_ready(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 1);

    /* Read one byte from each of fds[0] and fds[1] */
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 1);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Write one byte to fds[0] */
    ind_soc_data_out_ready(fds[0]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 1);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Pause data in from fds[1], expect no reads */
    ind_soc_data_in_pause(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Resume data in from fds[1] */
    ind_soc_data_in_resume(fds[1]);
    memset(counters, 0, sizeof(counters));
    ind_soc_select_and_run(0);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    /* Block for some time with no events */
    memset(counters, 0, sizeof(counters));
    start_time = INDIGO_CURRENT_TIME;
    ind_soc_select_and_run(100);
    end_time = INDIGO_CURRENT_TIME;
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 0);
    INDIGO_ASSERT(counters[1].write == 0);
    INDIGO_ASSERT((end_time - start_time) >= 100 &&
                  (end_time - start_time) < 200);

    /* Block for some time until SIGALRM, which causes read ready on fd[1] */
    memset(counters, 0, sizeof(counters));
    memset(&itv, 0, sizeof(itv));
    sigalrm_write_fd = fds[0];
    itv.it_value.tv_usec = 100*1000;
    setitimer(ITIMER_REAL, &itv, NULL);
    ind_soc_select_and_run(200);
    INDIGO_ASSERT(counters[0].read == 0);
    INDIGO_ASSERT(counters[0].write == 0);
    INDIGO_ASSERT(counters[1].read == 1);
    INDIGO_ASSERT(counters[1].write == 0);

    INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0);
    INDIGO_ASSERT(ind_soc_socket_unregister(fds[1]) == 0);

    close(fds[0]);
    close(fds[1]);
}