SXE_RETURN sxe_hex_to_bytes(unsigned char * bytes, const char * hex, unsigned hex_length) { SXE_RETURN result = SXE_RETURN_ERROR_INTERNAL; unsigned i; char character; unsigned nibble_high; unsigned nibble_low; SXEA1((hex_length % 1) == 0, "sxe_hex_to_bytes: hex string length %u is odd", hex_length); SXEE6("(bytes=%p,hex='%.*s',hex_length=%u)", bytes, hex_length, hex, hex_length); for (i = 0; i < hex_length; i++) { if (((nibble_high = hex_character_to_nibble[(unsigned)(character = hex[ i])]) == NA) || ((nibble_low = hex_character_to_nibble[(unsigned)(character = hex[++i])]) == NA)) { SXEL3(isprint(character) ? "%s%c'" : "%s\\x%02x'", "sxe_hex_to_bytes: Unexpected hex character '", hex[i]); goto SXE_EARLY_OUT; } bytes[(i - 1) / 2] = (nibble_high << 4) | nibble_low; } result = SXE_RETURN_OK; SXE_EARLY_OUT: SXER6("return result=%s", sxe_return_to_string(result)); return result; }
/** * Allocate and contruct a hash * * @param name = Name of the hash, used in diagnostics * @param element_count = Maximum number of elements in the hash * @param element_size = Size of each element in the hash in bytes * @param key_offset = Offset of start of key from start of element in bytes * @param key_size = Size of the key in bytes * @param options = SXE_HASH_OPTION_UNLOCKED | SXE_HASH_OPTION_LOCKED (single threaded or use locking) * + SXE_HASH_OPTION_PREHASHED | SXE_HASH_OPTION_LOOKUP3_HASH (key is prehashed or use lookup3) * * @return A pointer to an array of hash elements */ void * sxe_hash_new_plus(const char * name, unsigned element_count, unsigned element_size, unsigned key_offset, unsigned key_size, unsigned options) { SXE_HASH * hash; unsigned size; SXEE6("sxe_hash_new_plus(name=%s,element_count=%u,element_size=%u,key_offset=%u,key_size=%u,options=%u)", name, element_count, element_size, key_offset, key_size, options); size = sizeof(SXE_HASH) + sxe_pool_size(element_count, element_size, element_count + SXE_HASH_BUCKETS_RESERVED); SXEA1((hash = malloc(size)) != NULL, "Unable to allocate %u bytes of memory for hash %s", size, name); SXEL6("Base address of hash %s = %p", name, hash); /* Note: hash + 1 == pool base */ hash->pool = sxe_pool_construct(hash + 1, name, element_count, element_size, element_count + SXE_HASH_BUCKETS_RESERVED, options & SXE_HASH_OPTION_LOCKED ? SXE_POOL_OPTION_LOCKED : 0); hash->count = element_count; hash->size = element_size; hash->key_offset = key_offset; hash->key_size = key_size; hash->options = options; hash->hash_key = options & SXE_HASH_OPTION_LOOKUP3_HASH ? lookup3_hash : sxe_prehashed_key_hash; SXER6("return array=%p", hash->pool); return hash->pool; }
static void test_event_timeout(SXE_POOL_TCP * pool, void * info) { SXEE6("%s(pool=%s, info=%p)", __func__, SXE_POOL_TCP_GET_NAME(pool), info); SXE_UNUSED_ARGUMENT(pool); SXE_UNUSED_ARGUMENT(info); SXEA1(0, "test_event_timeout should never be called in this test"); SXER6("return"); }
static void test_case(const char * tapname, const char * request, unsigned count) { SXE * client; tap_ev event; tap_test_case_name(tapname); SXEA1((client = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close)) != NULL, "Failed to allocate client SXE"); SXEA1(sxe_connect(client, "127.0.0.1", SXE_LOCAL_PORT(listener)) == SXE_RETURN_OK, "Failed to connect to HTTPD"); #ifdef _WIN32 usleep(10000); /* Copied from test-errors.c and which is a TODO item */ #endif is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &event), "client_connect", "Got a client connected event"); is(tap_ev_arg(event, "this"), client, "It's the client"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_connect", "Got a server connected event"); test_sxe_send(client, request, strlen(request), client_sent, "client_sent", q_client, TEST_WAIT, &event); if (count == 2) { is_eq(test_tap_ev_queue_identifier_wait(q_httpd , TEST_WAIT, &event), "h_header", "HTTPD: header event (a)" ); is_strncmp(tap_ev_arg(event, "key" ), "Good" , SXE_LITERAL_LENGTH( "Good" ), "HTTPD: header was 'Good'" ); is_strncmp(tap_ev_arg(event, "value"), "Header" , SXE_LITERAL_LENGTH( "Header" ), "HTTPD: header value was 'Header'"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd , TEST_WAIT, &event), "h_header", "HTTPD: header event (b)" ); is_strncmp(tap_ev_arg(event, "key" ), "Another", SXE_LITERAL_LENGTH( "Another"), "HTTPD: header was 'Another'" ); is_strncmp(tap_ev_arg(event, "value"), "Foo" , SXE_LITERAL_LENGTH( "Foo" ), "HTTPD: header value was 'Foo'" ); } is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_respond", "HTTPD: respond event"); sxe_close(client); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_close", "HTTPD: close event"); }
SXE_RETURN sxe_mkpath(const char * path) { SXE_RETURN result = SXE_RETURN_ERROR_INTERNAL; char command[PATH_MAX + sizeof(MKDIR_COMMAND) + 1]; struct stat filestat; #ifdef _WIN32 unsigned command_length; unsigned i; #endif SXEA1(snprintf(command, sizeof(command), MKDIR_COMMAND " %s", path) >= 0, "Failed to format 'mkdir' command"); #ifdef _WIN32 /* Remove slash termination (tossers at MS don't implement stat correctly) */ command_length = strlen(command) - 1; if (command[command_length] == '/') { command[command_length] = '\0'; /* Coverage Exclusion - todo: win32 coverage */ } for (i = command_length - 1; i >= sizeof(MKDIR_COMMAND); i--) { if (command[i] == '/') { command[i] = '\\'; } } #endif SXEL6("sxe_mkpath(): command '%s'", command, &command[sizeof(MKDIR_COMMAND)]); if (stat(&command[sizeof(MKDIR_COMMAND)], &filestat) >= 0) { SXEL6("sxe_mkpath(): '%s' already exists", path); result = SXE_RETURN_OK; /* COVERAGE EXCLUSION - harmless, and only happens on windows */ goto SXE_EARLY_OUT; /* COVERAGE EXCLUSION - harmless, and only happens on windows */ } if (system(command) == 0) { result = SXE_RETURN_OK; } SXE_EARLY_OUT: return result; }
int main(int argc, char ** argv) { int fd; double start_time; unsigned count = 0; /* e.g. master=0, slaves=1, 2, 3, etc */ char * unique_memmap_path_and_file; /* e.g. /tmp/test-sxe-pool-mmap-pid-1234.bin */ char unique_memmap_path_and_file_master_buffer[PATH_MAX]; unsigned unique_memmap_path_and_file_master_buffer_used; unsigned id; unsigned * pool; unsigned * shared; size_t size; SXE_MMAP memmap; int child[TEST_CLIENT_INSTANCES]; SXE_POOL_WALKER walker; putenv(SXE_CAST_NOCONST(char *, "SXE_LOG_LEVEL_LIBSXE_LIB_SXE_POOL=5")); /* Set to 5 to suppress sxe-pool debug logging since this is kind of a stress test */ putenv(SXE_CAST_NOCONST(char *, "SXE_LOG_LEVEL_LIBSXE_LIB_SXE_LIST=5")); /* Set to 5 to suppress sxe-list debug logging since this is kind of a stress test */ if (argc > 1) { count = atoi(argv[1]); unique_memmap_path_and_file = argv[2] ; SXEL1("Instance %2u unique memmap path and file: %s", count, unique_memmap_path_and_file); sxe_mmap_open(&memmap, unique_memmap_path_and_file); shared = SXE_CAST(unsigned *, SXE_MMAP_ADDR(&memmap)); pool = sxe_pool_from_base(shared); SXEL6("Instance %2u mapped to shared pool // base=%p, pool=%p", count, shared, pool); do { usleep(10000 * count); id = sxe_pool_set_oldest_element_state(pool, TEST_STATE_FREE, TEST_STATE_CLIENT_TAKE); SXEA1(id != SXE_POOL_LOCK_NOT_TAKEN, "Got SXE_POOL_LOCK_NOT_TAKEN");; } while (id == SXE_POOL_NO_INDEX); SXEL6("Instance %2u got pool element %u", count, id); pool[id] = count; sxe_pool_set_indexed_element_state(pool, id, TEST_STATE_CLIENT_TAKE, TEST_STATE_CLIENT_DONE); sxe_mmap_close(&memmap); SXEL6("Instance %2u exiting", count); return 0; }
SXE_RETURN sha1_to_hex(SOPHOS_SHA1 * sha1, char * sha1_in_hex, unsigned sha1_in_hex_length) { SXE_RETURN result = SXE_RETURN_OK; SXEE6("(sha1=%08x%08x%08x%08x%08x,sha1_in_hex='%p',sha1_in_hex_length='%u'", sha1->word[4], sha1->word[3], sha1->word[2], sha1->word[1], sha1->word[0], sha1_in_hex, sha1_in_hex_length); SXEA1(sha1_in_hex_length == (SHA1_IN_HEX_LENGTH + 1), "Incorrect length of char * for sha1_to_hex(): '%u'", sha1_in_hex_length); snprintf(sha1_in_hex , 9, "%08x", htonl(sha1->word[0])); snprintf(sha1_in_hex + 8, 9, "%08x", htonl(sha1->word[1])); snprintf(sha1_in_hex + 16, 9, "%08x", htonl(sha1->word[2])); snprintf(sha1_in_hex + 24, 9, "%08x", htonl(sha1->word[3])); snprintf(sha1_in_hex + 32, 9, "%08x", htonl(sha1->word[4])); SXEL6("sha1_in_hex: '%.*s'", SXE_CAST(int, SHA1_IN_HEX_LENGTH), sha1_in_hex); SXER6("return %s", sxe_return_to_string(result)); return result; }
int main(void) { #if !TEST_DIRWATCH /* TODO: Implement sxe_dirwatch() on Windows */ /* TODO: Implement sxe_dirwatch() on Apple */ /* TODO: Implement sxe_dirwatch() on FreeBSD */ #else char tempdir1[] = "tmp-XXXXXX"; char tempdir2[] = "tmp-XXXXXX"; char tempdir3[] = "tmp-XXXXXX"; SXE_DIRWATCH dirwatch1; SXE_DIRWATCH dirwatch2; SXE_DIRWATCH dirwatch3; char fname[PATH_MAX]; tap_ev ev; plan_tests(28); sxe_register(1, 0); sxe_init(); /* We need to make a new temporary directory, because *everything* appears * to change willy-nilly during the build. The current directory has a * file that always changes. The /tmp directory always seems to have * spurious changes in it. */ SXEA1(mkdtemp(tempdir1), "Failed to create tempdir: %s", strerror(errno)); SXEA1(mkdtemp(tempdir2), "Failed to create tempdir: %s", strerror(errno)); SXEA1(mkdtemp(tempdir3), "Failed to create tempdir: %s", strerror(errno)); sxe_dirwatch_init(); sxe_dirwatch_init(); /* for coverage */ sxe_dirwatch_add(&dirwatch1, tempdir1, SXE_DIRWATCH_CREATED|SXE_DIRWATCH_MODIFIED|SXE_DIRWATCH_DELETED, test_dirwatch_event, (void *)1); sxe_dirwatch_add(&dirwatch2, tempdir2, SXE_DIRWATCH_MODIFIED, test_dirwatch_event, (void *)2); sxe_dirwatch_add(&dirwatch3, tempdir3, SXE_DIRWATCH_DELETED, test_dirwatch_event, (void *)3); sxe_dirwatch_start(); /* tempdir1: create, modify, delete */ { char rname[PATH_MAX]; int fd; snprintf(rname, sizeof rname, "%s/renamed", tempdir1); snprintf(fname, sizeof fname, "%s/created", tempdir1); fd = open(fname, O_CREAT|O_RDWR, S_IRWXU); write(fd, "Hello", 5); rename(fname, rname); unlink(rname); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), "created", "Got filename %s", fname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_CREATED, "Got flags=SXE_DIRWATCH_CREATED"); is(tap_ev_arg(ev, "user_data"), 1, "Got user_data=1 (%s)", tempdir1); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), "created", "Got filename %s", fname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_MODIFIED, "Got flags=SXE_DIRWATCH_MODIFIED"); is(tap_ev_arg(ev, "user_data"), 1, "Got user_data=1 (%s)", tempdir1); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), "created", "Got filename %s", fname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_DELETED, "Got flags=SXE_DIRWATCH_DELETED"); is(tap_ev_arg(ev, "user_data"), 1, "Got user_data=1 (%s)", tempdir1); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), "renamed", "Got filename %s", rname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_CREATED, "Got flags=SXE_DIRWATCH_CREATED"); is(tap_ev_arg(ev, "user_data"), 1, "Got user_data=1 (%s)", tempdir1); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), "renamed", "Got filename %s", rname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_DELETED, "Got flags=SXE_DIRWATCH_DELETED"); is(tap_ev_arg(ev, "user_data"), 1, "Got user_data=1 (%s)", tempdir1); } /* tempdir2: modified */ { const char *rel; int fd; snprintf(fname, sizeof fname, "%s/file.XXXXXX", tempdir2); SXEA1((rel = strchr(fname, '/')), "Didn't find '/' in %s", fname); rel++; fd = mkstemp(fname); write(fd, "Hello", 5); unlink(fname); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), rel, "Got filename %s", fname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_MODIFIED, "Got flags=SXE_DIRWATCH_MODIFIED"); is(tap_ev_arg(ev, "user_data"), 2, "Got user_data=2 (%s)", tempdir2); } /* tempdir3: deleted */ { const char *rel; int fd; snprintf(fname, sizeof fname, "%s/file.XXXXXX", tempdir3); SXEA1((rel = strchr(fname, '/')), "Didn't find '/' in %s", fname); rel++; fd = mkstemp(fname); unlink(fname); is_eq(test_tap_ev_identifier_wait(TEST_WAIT, &ev), "test_dirwatch_event", "Got a dirwatch event"); is_eq(tap_ev_arg(ev, "chfile"), rel, "Got filename %s", fname); is(tap_ev_arg(ev, "chflags"), SXE_DIRWATCH_DELETED, "Got flags=SXE_DIRWATCH_DELETED"); is(tap_ev_arg(ev, "user_data"), 3, "Got user_data=3 (%s)", tempdir3); } rmdir(tempdir1); rmdir(tempdir2); rmdir(tempdir3); sxe_dirwatch_stop(); #endif return exit_status(); }
int main(void) { SXE_HTTPD_REQUEST * request[TEST_BUFFER_COUNT]; SXE * client[TEST_BUFFER_COUNT]; tap_ev ev; SXE * listener; char * send_buffer; int i; SXEA1(send_buffer = malloc(TEST_SEND_BYTES), "Failed to allocate %u KB", TEST_SEND_BYTES); for (i = 0; i < TEST_SEND_BYTES; i++) { send_buffer[i] = 'A'; } tap_plan(33, TAP_FLAG_ON_FAILURE_EXIT, NULL); test_sxe_register_and_init(TEST_BUFFER_COUNT * 2 + 1); sxe_httpd_construct(&httpd, TEST_BUFFER_COUNT + 1, TEST_BUFFER_COUNT, TEST_BUFFER_SIZE, 0); SXE_HTTPD_SET_HANDLER(&httpd, respond, h_respond); SXEA1((listener = test_httpd_listen(&httpd, "0.0.0.0", 0)) != NULL, "sxe_httpd_listen failed"); tap_test_case_name("connecting 10 clients"); for (i = 0; i < TEST_BUFFER_COUNT; i++) { SXEA1((client[i] = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, NULL)) != NULL, "sxe_new_tcp failed"); sxe_connect(client[i], "127.0.0.1", SXE_LOCAL_PORT(listener)); #define TEST_GET "GET / HTTP/1.1\r\n\r\n" is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_connect", "client[%d] connected to HTTPD", i); TEST_SXE_SEND_LITERAL(client[i], TEST_GET, client_sent, q_client, TEST_WAIT, &ev); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_respond", "HTTPD[%d] respond event", i); request[i] = SXE_CAST_NOCONST(SXE_HTTPD_REQUEST *, tap_ev_arg(ev, "request")); } tap_test_case_name("response_copy_body_data() runs out"); { SXE_RETURN ret = SXE_RETURN_OK; sxe_httpd_response_start(request[0], 200, "OK"); /* When we copy body data, we try to immediately send each buffer. If * it succeeds, we may not actually run out of buffers, because as the * buffers are depleted they are freed again. Eventually, though, * we'll fill the kernel's TCP output buffers. */ for (i = 0; i < TEST_SEND_COUNT && ret == SXE_RETURN_OK; i++) { ret = sxe_httpd_response_copy_body_data(request[0], send_buffer, TEST_SEND_BYTES); } is(ret, SXE_RETURN_NO_UNUSED_ELEMENTS, "HTTPD: response ran out of buffers after sending %d bytes %d times", TEST_SEND_BYTES, i); /* NOTE: you get an assertion if you call sxe_httpd_response_end() after * we've run out of buffers, because the last valid buffer has been send, * and no other buffers are available, so request->out_buffer == NULL. Not * sure what to do in this case... I guess we could queue a zero-length * buffer? Although we're out of buffers... */ #if NOT_SURE_WHAT_TO_DO_HERE sxe_httpd_response_end(request[0], h_sent, NULL); #endif } tap_test_case_name("response_start() runs out of buffers"); { is(sxe_httpd_response_start(request[1], 200, "OK"), SXE_RETURN_NO_UNUSED_ELEMENTS, "response_start() ran out of buffers"); sxe_httpd_close(request[1]); sxe_close(client[1]); } tap_test_case_name("response_simple() runs out of buffers during response_start()"); { is(sxe_httpd_response_simple(request[2], NULL, NULL, 200, "OK", "", NULL), SXE_RETURN_NO_UNUSED_ELEMENTS, "response_simple() ran out of buffers"); sxe_httpd_close(request[2]); sxe_close(client[2]); } /* TODO: because there are as many buffers as there are clients, we should * be able to test all combinations of places where we can run out of * buffers. We just need to ensure that all clients now call * response_start(), so that all have a buffer allocated. Then we can do * things like call sxe_httpd_response_header() with enough headers to * fill up the buffer and grab another one, which will fail because there * are no more buffers free... as long as the send does not complete * immediately. Perhaps it's worth mocking send() so that it always * returns a blocking answer? */ sxe_httpd_close(request[0]); sxe_close(client[0]); return exit_status(); }
int main(void) { SXE_HTTPD httpd; SXE * client; SXE * client2; SXE * server; SXE * server2; tap_ev event; plan_tests(14); test_sxe_register_and_init(1000); sxe_httpd_construct(&httpd, 2, 10, 512, 0); SXE_HTTPD_SET_HANDLER(&httpd, connect, h_connect); SXE_HTTPD_SET_HANDLER(&httpd, request, h_request); SXE_HTTPD_SET_HANDLER(&httpd, close, h_close); ok((listener = test_httpd_listen(&httpd, "0.0.0.0", 0)) != NULL, "HTTPD listening"); /* Starts two connections, then make a new connection, the oldest will be reaped by the server */ tap_test_case_name("reap connections"); /* 1st connection */ SXEA1((client = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close)) != NULL, "Failed to allocate client SXE"); SXEA1(sxe_connect(client, "127.0.0.1", SXE_LOCAL_PORT(listener)) == SXE_RETURN_OK, "Failed to connect to HTTPD"); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &event), "client_connect", "Got 1st client connected event"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_connect", "Got 1st server connect event"); server = SXE_CAST(SXE *, tap_ev_arg(event, "this")); /* 1st client: send a complete request line */ TEST_SXE_SEND_LITERAL(client, "GET /good HTTP/1.1\r\n", client_sent, q_client, TEST_WAIT, &event); /* Waiting for 1st client request state "stable" on "STATE_HEADER" to make * sure there is no more state updates on this request object, then the following * usleep will guarantee the 1st connection is older than the 2nd one. */ is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_request", "Got 1st server request event"); is(tap_ev_arg(event, "this"), server, "It's the 1st server"); usleep(300000); /* 2nd connection, reaping happens, the 1st one got reaped */ SXEA1((client2 = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close)) != NULL, "Failed to allocate client SXE"); SXEA1(sxe_connect(client2, "127.0.0.1", SXE_LOCAL_PORT(listener)) == SXE_RETURN_OK, "Failed to connect to HTTPD"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_connect", "Got 2nd server connect event"); server2 = SXE_CAST(SXE *, tap_ev_arg(event, "this")); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_close", "Got a server close event"); is(tap_ev_arg(event, "this"), server, "It's the 1st server"); /* Pull these two arguments off in any order */ test_process_all_libev_events(); ok((event = tap_ev_queue_shift_next(q_client, "client_connect")) != NULL, "Got 2nd client connected event"); ok((event = tap_ev_queue_shift_next(q_client, "client_close")) != NULL, "Got a client close event"); is(tap_ev_arg(event, "this"), client, "It's the 1st client"); is(tap_ev_queue_length(q_httpd), 0, "No server events lurking"); is(tap_ev_queue_length(q_client), 0, "No client events lurking"); sxe_close(listener); return exit_status(); }