static void socket_callback( int socket_id, void *cookie, int read_ready, int write_ready, int error_seen) { char buf[2048]; int bytes_read; printf("Socket callback called: id %d. rd %d. wr %d. er %d\n", socket_id, read_ready, write_ready, error_seen); socket_called = 1; if (write_ready) { sock_write_seen = 1; send(socket_id, "x", 1, MSG_DONTWAIT); ind_soc_data_out_clear(socket_id); } if (read_ready) { printf("Reading from socket %d\n", socket_id); bytes_read = read(socket_id, buf, 2048); printf("Read in %d bytes\n", bytes_read); sock_read_seen = 1; ind_soc_data_out_ready(socket_id); } INDIGO_ASSERT(!error_seen); }
int main(int argc, char* argv[]) { ind_soc_config_t config = {0}; int fds[2]; printf("Init returned %d\n", ind_soc_init(&config)); /* Should be called once */ ind_soc_timer_event_register(timer_callback, NULL, IND_SOC_TIMER_IMMEDIATE); ind_soc_select_and_run(10); INDIGO_ASSERT(timer_called); timer_called = 0; ind_soc_select_and_run(1000); INDIGO_ASSERT(!timer_called); ind_soc_timer_event_register(timer_callback, NULL, 100); ind_soc_select_and_run(1000); INDIGO_ASSERT(timer_called); timer_called = 0; ind_soc_timer_event_register(timer_callback_repeat, NULL, 100); ind_soc_select_and_run(1000); INDIGO_ASSERT(timer_called >= 9); ind_soc_timer_event_unregister(timer_callback_repeat, NULL); if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); abort(); } INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, NULL) == 0); INDIGO_ASSERT(ind_soc_socket_register(fds[1], socket_callback, NULL) == 0); ind_soc_data_out_ready(fds[0]); ind_soc_data_out_ready(fds[1]); /* Do stuff for 3 seconds */ ind_soc_select_and_run(3000); INDIGO_ASSERT(socket_called > 0); INDIGO_ASSERT(sock_read_seen > 0); INDIGO_ASSERT(sock_write_seen > 0); return 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]); }
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); } } } } }
/* Test add/remove of sockets */ static void test_socket_mgmt(void) { int fds[2]; struct sock_counters counters[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); abort(); } /* Unregistering a not-registered socket should fail */ INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) < 0); /* Adding and then unregistering a socket should succeed */ INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0); INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0); /* Trying to unregister twice should fail */ INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) < 0); /* Trying to register twice should fail */ INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0); INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) < 0); /* Add another socket, then remove the first */ INDIGO_ASSERT(ind_soc_socket_register(fds[1], socket_callback, &counters[1]) == 0); INDIGO_ASSERT(ind_soc_socket_unregister(fds[0]) == 0); /* Write one byte to fds[1] */ 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 == 0); INDIGO_ASSERT(counters[1].read == 0); INDIGO_ASSERT(counters[1].write == 1); /* Expect no events from the not-registered fds[0] */ 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); /* Register fds[0] and expect a read event */ INDIGO_ASSERT(ind_soc_socket_register(fds[0], socket_callback, &counters[0]) == 0); 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 == 0); 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]); }