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"); }
int main(void) { TEST_SHA1 sha1_expected; TEST_SHA1 sha1_got; char hex_buffer[sizeof(SHA1_HEX)]; unsigned val = 0; plan_tests(15); is(sxe_hex_to_unsigned("0", 2), 0, "'0':2 -> 0"); is(sxe_hex_to_unsigned("face", 4), 0xface, "'face':4 -> 0xface"); is(sxe_hex_to_unsigned("B00B", 2), 0xb0, "'B00B':2 -> 0xb0"); is(sxe_hex_to_unsigned("XXXX", 4), SXE_UNSIGNED_MAXIMUM, "'XXXX':4 -> 0x%x (SXE_UNSIGNED_MAXIMUM)", sxe_hex_to_unsigned("XXXX", 4)); is(sxe_valid_hex_to_unsigned("0a", 2, &val), SXE_RETURN_OK, "0a is valid hex"); is(val, 10, "0a hex is 10 decimal"); is(sxe_valid_hex_to_unsigned("F45C6AC6", 8, &val), SXE_RETURN_OK, "F45C6AC6 is valid hex"); is(val, 4099697350, "F45C6AC6 hex is 4099697350 decimal"); is(sxe_valid_hex_to_unsigned("ZZ", 2, &val), SXE_RETURN_ERROR_INTERNAL, "ZZ is not valid hex"); ok(sxe_hex_to_bytes((unsigned char *)&sha1_got, "goofy goober", 12) != SXE_RETURN_OK, "Conversion from hex 'goofy goober' to bytes failed"); is(sxe_hex_to_bytes((unsigned char *)&sha1_got, SHA1_HEX, 40), SXE_RETURN_OK, "Conversion from hex '%s' to bytes succeeded", SHA1_HEX); memcpy(&sha1_expected, sxe_sha1_expected_bytes, sizeof(sha1_expected)); if (memcmp(&sha1_got, &sha1_expected, sizeof(TEST_SHA1)) == 0) { pass( "bytes are as expected"); } else { SXEL1("Expected:"); SXED1(&sha1_expected, sizeof(sha1_expected)); SXEL1("Got:"); SXED1(&sha1_got, sizeof(sha1_got)); fail( "bytes are not as expected"); } tap_test_case_name("sxe_hex_from_bytes"); hex_buffer[sizeof(hex_buffer) - 1] = 0xBE; is(sxe_hex_from_bytes(hex_buffer, sxe_sha1_expected_bytes, sizeof(sxe_sha1_expected_bytes)), hex_buffer, "Returns hex buffer"); is_strncmp(hex_buffer, SHA1_HEX, SXE_LITERAL_LENGTH(SHA1_HEX), "SHA1 converted to hex as expected"); is((unsigned char)hex_buffer[sizeof(hex_buffer) - 1], 0xBE, "Guard byte is intact"); return exit_status(); }
int main(void) { int i, j, k = 0, len, set, hop; setvbuf(stdout, NULL, _IOLBF, 0); plan_tests(1 + nffstests + nshltests + 5 + 128); XMM ones = (__v2di){-1, -1}; ok(xm_same(xm_ones, ones), "xm_ones produces FFFF...FFFF"); for (i = 0; i < nffstests; ++i) { int act = findbit_1((uint8_t*)&ffstestv[i].inp, sizeof(XMM)); ok(act == ffstestv[i].exp, "test %d: act:%d exp:%d", i, act, ffstestv[i].exp); } for (i = 0; i < nshltests; ++i) { char acts[99]; XMM act = xm_shl(shltestv[0].exp, shltestv[i].nbits); xm_llx(act, acts); ok(0xFFFF == xm_same(act, shltestv[i].exp), "shl %d: %s", shltestv[i].nbits, acts); } XMM bitz = { 1,8 }; int iact = xm_ffs(bitz); ok(iact == 0, "xm_ffs(bitz) = %d", iact); iact = xm_fls(bitz); ok(iact == 67, "xm_fls(bitz) = %d", iact); bitz = _mm_setzero_si128(); iact = xm_ffs(bitz); ok(iact == -1, "xm_ffs(zero) = %d", iact); iact = xm_fls(bitz); ok(iact == -1, "xm_fls(zero) = %d", iact); XMM stuff = (__v2di) { 0x07BB01426C62272EULL, 0x6295C58D62B82175ULL }; char str[48]; xm_str(stuff, str); is_strncmp(str, "2E,27,62,6C,42,01,BB,07-75,21,B8,62,8D,C5,95,62", 48, "xm_str"); XMM one = { 1, 0 }, hibit = xm_shl_177(one); for (i = 0; i < 128; ++i) { int pos = xm_ffs(xm_or(xm_shl(one, i), hibit)); ok(pos == i, "xm_ffs(xm_shl(one,%d)) = %d", i, pos); } # define CMPSIZE 100000000L char *x = malloc(CMPSIZE), *y = malloc(CMPSIZE); memcpy(x, y, CMPSIZE); for (len = 20; len <= CMPSIZE; len *= 4) { for (i = 1; i < 17; i += i) { for (j = 1; j < 17; j += j) { for (set = 1; set < 2; set++) { char *a, *b; double t0 = tick(); for (hop = CMPSIZE / len, a = x, b = y; hop; --hop, a += len, b += len) a[i+len-17] ^= set, k += cmpxm(a+i, b+j, len-17), a[i+len-17] ^= set; double t1 = tick(); for (hop = CMPSIZE / len, a = x, b = y; hop; --hop, a += len, b += len) { _mm_prefetch(a+i+448, _MM_HINT_NTA); _mm_prefetch(b+j+448, _MM_HINT_NTA); a[i+len-17] ^= set, k += memcmp(a+i, b+j, len-17), a[i+len-17] ^= set; } double t2 = tick(); printf("%9d %2d %2d %d %4.1f\n", len, i, j, set, (t2 - t1)/(t1 - t0)); } } } } if (!k) puts(""); return exit_status(); }
static void test_five_headers(void) { SXE_HTTP_MESSAGE message; unsigned line_len; tap_test_case_name("Five Headers - Normal Long Normal Long-With-Continuations Normal"); max_buffer_size = 70; memset(message_headers, 0, sizeof(message_headers)); snprintf(message_headers, sizeof(message_headers), "\r\n%s: %s\r\n%s: %s\r\n%s: %s\r\n%s: %s\r\n CONTINUE_LINE1\r\n\tCONTINUE_LINE2\r\n%s: %s\r\n\r\n", HEADER(1), VALUE(1), HEADER(2), LONG_VALUE(2), HEADER(333), VALUE(3333), LONG_HEADER(4), VALUE(4), HEADER(55), VALUE(5)); sxe_http_message_construct(&message, message_headers, max_buffer_size); line_len = strlen(message_headers); diag("Five Headers: The header is %u bytes, the max buffer size is %u bytes", line_len, max_buffer_size); is(sxe_http_message_parse_next_line_element(&message, SXE_HTTP_LINE_ELEMENT_TYPE_END_OF_LINE), SXE_RETURN_END_OF_FILE, "Parsed message request line"); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_OK, "Get header 1"); is(message.ignore_length, 0, "No ignore"); is(message.ignore_length, 0, "Ignore length is 0"); is_strncmp(sxe_http_message_get_header_name(&message), HEADER(1), strlen(HEADER(1)), "Name is " HEADER(1)); is(sxe_http_message_get_header_name_length(&message), strlen(HEADER(1)), "Name length is %u", (unsigned)strlen(HEADER(1))); is_strncmp(sxe_http_message_get_header_value(&message), VALUE(1), strlen(VALUE(1)), "Value is " VALUE(1)); is(sxe_http_message_get_header_value_length(&message), strlen(VALUE(1)), "Value length is %u", (unsigned)strlen(VALUE(1))); /* Don't do any consume since last sxe_http_message_parse_next_header() returns OK */ is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header"); is(message.ignore_length, 0, "No ignore"); /* 21 == 2 + strlen(HEADER(1)) + 2 + strlen(VALUE(1)) + 2 */ is(sxe_http_message_consume_parsed_headers(&message), 21, "Consuming the request line and header 1"); /* Simulate sxe_buf_consume() */ memmove(message_headers, &message_headers[21], sizeof(message_headers) - 21); diag("Five Headers: Consumed 21 bytes"); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header"); is(sxe_http_message_consume_parsed_headers(&message), 0, "Buffer is full"); /* Start ignoring */ memmove(message_headers, &message_headers[max_buffer_size], sizeof(message_headers) - max_buffer_size); diag("Five Headers: Consumed %u bytes", max_buffer_size); message.ignore_line = 1; sxe_http_message_increase_buffer_length(&message, max_buffer_size); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header"); is(message.ignore_line, 0, "Ignore buffer flag is clear, since found the end of long header 2"); /* 55 = strlen(HEADER(2)) + 2 + strlen(LONG_VALUE(2)) + 2 - 70 */ is(message.ignore_length, 55, "Ignore length is right"); memmove(message_headers, &message_headers[55], sizeof(message_headers) - 55); diag("Five Headers: Consumed 55 bytes"); sxe_http_message_increase_buffer_length(&message, max_buffer_size); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_OK, "Get normal header 3"); is(message.ignore_length, 0, "No ignore"); is_strncmp(sxe_http_message_get_header_name(&message), HEADER(333), strlen(HEADER(333)), "Name is " HEADER(333)); is(sxe_http_message_get_header_name_length(&message), strlen(HEADER(333)), "Name length is %u", (unsigned)strlen(HEADER(333))); is_strncmp(sxe_http_message_get_header_value(&message), VALUE(3333), strlen(VALUE(3333)), "Value is " VALUE(3333)); is(sxe_http_message_get_header_value_length(&message), strlen(VALUE(3333)), "Value length is %u", (unsigned)strlen(VALUE(3333))); /* Don't do any consume since last sxe_http_message_parse_next_header() returns OK */ is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header"); is(message.ignore_length, 0, "No ignore"); /* 24 == strlen(HEADER(333)) + 2 + strlen(VALUE(3333)) + 2 */ is(sxe_http_message_consume_parsed_headers(&message), 24, "Consuming the header 3"); /* Simulate sxe_buf_consume() */ memmove(message_headers, &message_headers[24], sizeof(message_headers) - 24); diag("Five Headers: Consumed 24 bytes"); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header"); is(sxe_http_message_consume_parsed_headers(&message), 0, "Buffer is full"); /* Start ignoring */ memmove(message_headers, &message_headers[max_buffer_size], sizeof(message_headers) - max_buffer_size); diag("Five Headers: Consumed %u bytes", max_buffer_size); message.ignore_line = 1; sxe_http_message_increase_buffer_length(&message, max_buffer_size); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header 4"); is(message.ignore_line, 1, "Ignore buffer flag is set, the end of long header 4 not found yet"); /* 55 = strlen(HEADER(2)) + 2 + strlen(LONG_VALUE(2)) + 2 - 70 */ is(message.ignore_length, max_buffer_size, "Ignore length is right"); memmove(message_headers, &message_headers[max_buffer_size], sizeof(message_headers) - max_buffer_size); diag("Five Headers: Consumed %u bytes", max_buffer_size); /* 41 = 351(line_len) - 21 - 55 - 24 - 3 * 210 */ sxe_http_message_increase_buffer_length(&message, 41); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_WARN_WOULD_BLOCK, "Get long header 4"); is(message.ignore_line, 0, "Ignore buffer flag is set, the end of long header 4 not found yet"); /* 19 = strlen("\r\n\tCONTINUE_LINE2\r\n") */ is(message.ignore_length, 19, "Ignore length is right"); memmove(message_headers, &message_headers[19], sizeof(message_headers) - 19); diag("Five Headers: Consumed 19 bytes, the left part of long header 4"); /* 22 = 41 - 19 */ sxe_http_message_increase_buffer_length(&message, 22); is(sxe_http_message_parse_next_header(&message), SXE_RETURN_OK, "Get the header 5"); is(message.ignore_line, 0, "Ignore buffer flag is clear"); is(message.ignore_length, 0, "Ignore length is 0"); is_strncmp(sxe_http_message_get_header_name(&message), HEADER(55), strlen(HEADER(55)), "Name is " HEADER(55)); is(sxe_http_message_get_header_name_length(&message), strlen(HEADER(55)), "Name length is %u", (unsigned)strlen(HEADER(55))); is_strncmp(sxe_http_message_get_header_value(&message), VALUE(5), strlen(VALUE(5)), "Value is " VALUE(5)); is(sxe_http_message_get_header_value_length(&message), strlen(VALUE(5)), "Value length is %u", (unsigned)strlen(VALUE(5))); /* Don't do any consume since last sxe_http_message_parse_next_header() returns OK */ is(sxe_http_message_parse_next_header(&message), SXE_RETURN_END_OF_FILE, "Get long header"); /* 22 = strlen("HEADER-55: VALUE_5\r\n\r\n") */ is(sxe_http_message_consume_parsed_headers(&message), 22, "Consumed the rest of 22 bytes which are header 5 and eof"); }
static void log_line(SXE_LOG_LEVEL level, char * line) { char buf[256]; if (line[strlen(line) - 1] != '\n') { fail("Expected 0x0a at end of line, not 0x%02x", line[strlen(line) - 1]); exit(1); } line[strlen(line) - 1] = '\0'; switch (test_state) { case 0: is(level, SXE_LOG_LEVEL_TRACE, "Line was logged at TRACE level"); is_strncmp(&line[strlen(line) - strlen(entering)], entering, strlen(entering), "Test line 0 contains '%s': '%s'", entering, line); break; case 1: ok(strstr(line, __FILE__) != NULL, "Test line 1 includes file name '%s': '%s'", __FILE__, line); break; case 2: is_strncmp(&line[strlen(line) - strlen(logging)], logging, strlen(logging), "Test line 2 ends with '%s': '%s'", logging, line); is_strncmp(&line[strlen(line) - strlen(logging) - strlen(idlevin)], idlevin, strlen(idlevin), "Test line 2 has id 99, level 6 and indent 2"); break; case 3: ok(strstr(line, dumpdata) != NULL, "Test line 3 contains '%s'", dumpdata); ok(strstr(line, dumphex) != NULL, "Test line 3 contains hex '%s'", dumphex); break; case 4: is_strncmp(&line[strlen(line) - strlen(exiting)], exiting, strlen(exiting), "Test line 4 ends with '%s': '%s'", exiting, line); break; case 5: strcpy(buf, "} // "); strcat(buf, SXE_FILE); ok(strstr(line, buf) != NULL, "Test line 5 includes end of block with file name '%s': '%s'", buf, line); break; case 6: is(strlen(line), TEST_MAX_LINE, "Very long log line truncated"); is_eq(&line[TEST_MAX_LINE - 2], "..", "Truncation indicator found"); break; case 7: is(strlen(line), TEST_MAX_LINE, "Very long entry line truncated"); break; case 8: ok(strstr(line, __FILE__) != NULL, "Test line 8 includes file name '%s': '%s'", __FILE__, line); break; case 9: is_eq(&line[strlen(line) - strlen(escaped)], escaped, "Test line 9 ends with '%.*s': '%s'", (int)strlen(escaped) - 1, escaped, line); break; case 10: is(strlen(line), TEST_MAX_LINE, "Line of 300 backspaces escaped and truncated"); break; case 11: /* Doesn't crash */ break; case 12: is(level, SXE_LOG_LEVEL_FATAL, "Assertions are logged at level FATAL"); ok((strstr(line, "ERROR: assertion 'this != &self' failed at test/test-sxe-log.c") != NULL) || (strstr(line, "ERROR: assertion 'this != &self' failed at libsxe/lib-sxe-log/test/test-sxe-log.c") != NULL) || (strstr(line, "ERROR: assertion 'this != &self' failed at ../libsxe/lib-sxe-log/test/test-sxe-log.c") != NULL), "Assertion line includes expected stringized test: '%s'", line); #ifdef WINDOWS_NT diag("info: You can expect and ignore a message saying:"); diag(" > This application has requested the Runtime to terminate it in an unusual way."); diag(" > Please contact the application's support team for more information."); #endif break; default: diag("Unexpected test sequence number %u.\n", test_state); exit(1); } test_state++; }
int main(void) { SXE_HTTPD httpd; SXE_HTTPD_REQUEST * request; tap_ev ev; SXE * listener; SXE * c; SXE * c2; char buffer[1024]; tap_plan(24, TAP_FLAG_ON_FAILURE_EXIT, NULL); test_sxe_register_and_init(12); sxe_httpd_construct(&httpd, 3, 10, 512, 0); SXE_HTTPD_SET_HANDLER(&httpd, connect, h_connect); SXE_HTTPD_SET_HANDLER(&httpd, request, h_request); SXE_HTTPD_SET_HANDLER(&httpd, header, h_header); SXE_HTTPD_SET_HANDLER(&httpd, eoh, h_eoh); SXE_HTTPD_SET_HANDLER(&httpd, body, h_body); SXE_HTTPD_SET_HANDLER(&httpd, respond, h_respond); SXE_HTTPD_SET_HANDLER(&httpd, close, h_close); listener = test_httpd_listen(&httpd, "0.0.0.0", 0); c = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, NULL); sxe_connect(c, "127.0.0.1", SXE_LOCAL_PORT(listener)); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_connect", "1st Client connected to HTTPD"); TEST_SXE_SEND_LITERAL(c, "POST /this/is/a/URL HTTP/1.1\r\nContent-Length: 10\r\n\r\n12345678\r\n", client_sent, q_client, TEST_WAIT, &ev); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_connect", "HTTPD: connected"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_request", "HTTPD: new request"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_header", "HTTPD: header event"); is_strncmp(tap_ev_arg(ev, "key"), "Content-Length", SXE_LITERAL_LENGTH("Content-Length"), "HTTPD: header was 'Connect'"); is_strncmp(tap_ev_arg(ev, "value"), "10", SXE_LITERAL_LENGTH("10"), "HTTPD: header value was 'whatever'"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_eoh", "HTTPD: eoh (end of headers) event"); test_ev_queue_wait_read(q_httpd, TEST_WAIT, &ev, NULL, "h_body", buffer, 10, "HTTPD body handler"); is_strncmp(buffer, "12345678\r\n", SXE_LITERAL_LENGTH("12345678\r\n"), "HTTPD: read correct body"); /* httpd is still in "req_response" state */ is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_respond", "HTTPD: respond event"); /* Extra data from client, e.g., "content-length" is wrong and shorter than real packet */ TEST_SXE_SEND_LITERAL(c, "AB", client_sent, q_client, TEST_WAIT, &ev); /* Send another valid request again, the connection is in "sink" mode now, data will get ignored */ TEST_SXE_SEND_LITERAL(c, "POST /this/is/a/URL HTTP/1.1\r\nContent-Length: 10\r\n\r\n12345678\r\n", client_sent, q_client, TEST_WAIT, &ev); test_process_all_libev_events(); /* In sink mode, no more httpd events */ is(tap_ev_queue_length(q_httpd), 0, "No lurking httpd events"); /* New client connection should not be affected */ c2 = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close); sxe_connect(c2, "127.0.0.1", SXE_LOCAL_PORT(listener)); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_connect", "2nd Client connected to HTTPD"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_connect", "HTTPD: connected"); TEST_SXE_SEND_LITERAL(c2, "GET /simple HTTP/1.1\r\n\r\n", client_sent, q_client, TEST_WAIT, &ev); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_request", "HTTPD: new request"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_eoh", "HTTPD: eoh (end of headers) event"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_respond", "HTTPD: respond event"); request = (SXE_HTTPD_REQUEST *)(long)tap_ev_arg(ev, "request"); sxe_httpd_response_simple(request, h_sent, NULL, 200, "OK", NULL, "Connection", "close", NULL); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_sent", "HTTPD: finished responding"); sxe_close(request->sxe); #define TEST_200_CLOSE_RESPONSE "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 0\r\n\r\n" test_ev_queue_wait_read(q_client, TEST_WAIT, &ev, c2, "client_read", buffer, SXE_LITERAL_LENGTH(TEST_200_CLOSE_RESPONSE), "client"); is_strncmp(buffer, TEST_200_CLOSE_RESPONSE, SXE_LITERAL_LENGTH(TEST_200_CLOSE_RESPONSE), "GET response is a 200 OK with close"); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_close", "Got a client close event"); return exit_status(); }