static void listen_callback( int socket_id, void *cookie, int read_ready, int write_ready, int error_seen) { AIM_LOG_TRACE("Accepting CLI client"); int fd; if ((fd = accept(listen_socket, NULL, NULL)) < 0) { AIM_LOG_ERROR("Failed to accept on CLI socket: %s", strerror(errno)); return; } struct client *client = aim_zmalloc(sizeof(*client)); client->fd = fd; client->write_pvs = aim_pvs_buffer_create(); client->ucli = ucli_create("ivs", NULL, NULL); indigo_error_t rv = ind_soc_socket_register(fd, client_callback, client); if (rv < 0) { AIM_LOG_ERROR("Failed to register CLI client socket: %s", indigo_strerror(rv)); return; } }
/** * Basic output function for all log messages. */ static void aim_log_output__(aim_log_t* l, const char* fname, const char* file, int line, const char* fmt, va_list vargs) { aim_pvs_t* msg; char* pmsg; msg = aim_pvs_buffer_create(); if(AIM_BIT_GET(l->options, AIM_LOG_OPTION_TIMESTAMP)) { aim_log_time__(msg); } aim_vprintf(msg, fmt, vargs); if(l->options & (1 << AIM_LOG_OPTION_FUNC)) { aim_printf(msg, " [%s]", fname); } if(l->options & (1 << AIM_LOG_OPTION_FILE_LINE)) { aim_printf(msg, " [%s:%d]", file, line); } aim_printf(msg, "\n"); pmsg = aim_pvs_buffer_get(msg); aim_printf(l->pvs, "%s", pmsg); aim_free(pmsg); aim_pvs_destroy(msg); }
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); } } } } }
int aim_main(int argc, char* argv[]) { int i; { const char* tstStrings[] = { "This", "is", "a", "complete", "sentence." }; char* join = aim_strjoin(" ", tstStrings, AIM_ARRAYSIZE(tstStrings)); if(strcmp(join, "This is a complete sentence.")) { printf("fail: join='%s'\n", join); } AIM_FREE(join); } for(i = 0; i < argc; i++) { aim_printf(&aim_pvs_stdout, "arg%d: '%s'\n", i, argv[i]); } { /* Test data */ char data[2500]; memset(data, 0xFF, sizeof(data)); aim_printf(&aim_pvs_stdout, "data is %{data}", data, sizeof(data)); } { char* sdata = "DEADBEEFCAFE"; char* data; int size; aim_sparse(&sdata, &aim_pvs_stdout, "{data}", &data, &size); aim_printf(&aim_pvs_stdout, "data is %{data}\n", data, size); aim_free(data); } utest_list(); AIM_LOG_MSG("Should print 1-27"); AIM_LOG_MSG("%d %d %d %d %d %d %d %d %d " "%d %d %d %d %d %d %d %d %d " "%d %d %d %d %d %d %d %d %d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27); aim_printf(&aim_pvs_stdout, "aim_pvs_stdout from %s:%d\n", __FILE__, __LINE__); { char c; aim_pvs_t* pvs = aim_pvs_buffer_create(); aim_printf(pvs, "\nConsider "); aim_printf(pvs, "%s ", "the"); aim_printf(pvs, "alphabet: "); for(c = 'A'; c <= 'Z'; c++) { aim_printf(pvs, "%c", c); } aim_printf(pvs, "\n"); { char* s = aim_pvs_buffer_get(pvs); aim_printf(&aim_pvs_stdout, "first: %s", s); free(s); aim_printf(pvs, "(second)"); s = aim_pvs_buffer_get(pvs); aim_printf(&aim_pvs_stdout, "second: %s", s); free(s); aim_pvs_destroy(pvs); } { aim_ratelimiter_t rl; aim_ratelimiter_init(&rl, 10, 5, NULL); /* 5 (6?) tokens available at t=0 */ assert(aim_ratelimiter_limit(&rl, 0) == 0); assert(aim_ratelimiter_limit(&rl, 0) == 0); assert(aim_ratelimiter_limit(&rl, 0) == 0); assert(aim_ratelimiter_limit(&rl, 0) == 0); assert(aim_ratelimiter_limit(&rl, 0) == 0); assert(aim_ratelimiter_limit(&rl, 0) == 0); assert(aim_ratelimiter_limit(&rl, 0) < 0); /* Another token at t=10 */ assert(aim_ratelimiter_limit(&rl, 10) == 0); assert(aim_ratelimiter_limit(&rl, 10) < 0); /* Nothing at t=15 */ assert(aim_ratelimiter_limit(&rl, 15) < 0); /* 4 more tokens granted by t=50 */ assert(aim_ratelimiter_limit(&rl, 50) == 0); assert(aim_ratelimiter_limit(&rl, 50) == 0); assert(aim_ratelimiter_limit(&rl, 50) == 0); assert(aim_ratelimiter_limit(&rl, 50) == 0); assert(aim_ratelimiter_limit(&rl, 50) < 0); } { aim_printf(&aim_pvs_stdout, "valgrind_status=%d\n", aim_valgrind_status()); } AIM_LOG_MSG("%{aim_error}", AIM_ERROR_PARAM); } return 0; }