/*********************************************************************** * Copyright (c) 2009, Secure Endpoints Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ #include #include #include #include #include #define PORT 8013 #define PORT_S "8013" char * prog = "Master"; int is_client = 0; static int get_address(int flags, struct addrinfo ** ret) { struct addrinfo ai; int rv; memset(&ai, 0, sizeof(ai)); ai.ai_flags = flags | AI_NUMERICHOST; ai.ai_family = AF_INET; ai.ai_socktype = SOCK_STREAM; ai.ai_protocol = PF_UNSPEC; rv = getaddrinfo("127.0.0.1", PORT_S, &ai, ret); if (rv) warnx("getaddrinfo: %s", gai_strerror(rv)); return rv; } static int get_connected_socket(rk_socket_t * s_ret) { struct addrinfo * ai = NULL; int rv = 0; rk_socket_t s = rk_INVALID_SOCKET; rv = get_address(0, &ai); if (rv) return rv; s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (rk_IS_BAD_SOCKET(s)) { rv = 1; goto done; } rv = connect(s, ai->ai_addr, ai->ai_addrlen); if (rk_IS_SOCKET_ERROR(rv)) goto done; *s_ret = s; s = rk_INVALID_SOCKET; rv = 0; done: if (!rk_IS_BAD_SOCKET(s)) rk_closesocket(s); if (ai) freeaddrinfo(ai); return (rv) ? rk_SOCK_ERRNO : 0; } const char * test_strings[] = { "Hello", "01234566789012345689012345678901234567890123456789", "Another test", "exit" }; static int test_simple_echo_client(void) { rk_socket_t s = rk_INVALID_SOCKET; int rv; char buf[81]; int i; fprintf(stderr, "[%s] Getting connected socket...", getprogname()); rv = get_connected_socket(&s); if (rv) { fprintf(stderr, "\n[%s] get_connected_socket() failed (%s)\n", getprogname(), strerror(rk_SOCK_ERRNO)); return 1; } fprintf(stderr, "[%s] done\n", getprogname()); for (i=0; i < sizeof(test_strings)/sizeof(test_strings[0]); i++) { rv = send(s, test_strings[i], strlen(test_strings[i]), 0); if (rk_IS_SOCKET_ERROR(rv)) { fprintf(stderr, "[%s] send() failure (%s)\n", getprogname(), strerror(rk_SOCK_ERRNO)); rk_closesocket(s); return 1; } rv = recv(s, buf, sizeof(buf), 0); if (rk_IS_SOCKET_ERROR(rv)) { fprintf (stderr, "[%s] recv() failure (%s)\n", getprogname(), strerror(rk_SOCK_ERRNO)); rk_closesocket(s); return 1; } if (rv == 0) { fprintf (stderr, "[%s] No data received\n", prog); rk_closesocket(s); return 1; } if (rv != strlen(test_strings[i])) { fprintf (stderr, "[%s] Data length mismatch %d != %d\n", prog, rv, strlen(test_strings[i])); rk_closesocket(s); return 1; } } fprintf (stderr, "[%s] Done\n", prog); rk_closesocket(s); return 0; } static int test_simple_echo_socket(void) { fprintf (stderr, "[%s] Process ID %d\n", prog, GetCurrentProcessId()); fprintf (stderr, "[%s] Starting echo test with sockets\n", prog); if (is_client) { return test_simple_echo_client(); } else { rk_socket_t s = rk_INVALID_SOCKET; fprintf (stderr, "[%s] Listening for connections...\n", prog); mini_inetd(htons(PORT), &s); if (rk_IS_BAD_SOCKET(s)) { fprintf (stderr, "[%s] Connect failed (%s)\n", getprogname(), strerror(rk_SOCK_ERRNO)); } else { fprintf (stderr, "[%s] Connected\n", prog); } { char buf[81]; int rv, srv; while ((rv = recv(s, buf, sizeof(buf), 0)) != 0 && !rk_IS_SOCKET_ERROR(rv)) { buf[rv] = 0; fprintf(stderr, "[%s] Received [%s]\n", prog, buf); /* simple echo */ srv = send(s, buf, rv, 0); if (srv != rv) { if (rk_IS_SOCKET_ERROR(srv)) fprintf(stderr, "[%s] send() error [%s]\n", getprogname(), strerror(rk_SOCK_ERRNO)); else fprintf(stderr, "[%s] send() size mismatch %d != %d", getprogname(), srv, rv); } if (!strcmp(buf, "exit")) { fprintf(stderr, "[%s] Exiting...\n", prog); shutdown(s, SD_SEND); rk_closesocket(s); return 0; } } fprintf(stderr, "[%s] recv() failed (%s)\n", getprogname(), strerror(rk_SOCK_ERRNO)); } rk_closesocket(s); } return 1; } static int test_simple_echo(void) { fprintf (stderr, "[%s] Starting echo test\n", prog); if (is_client) { return test_simple_echo_client(); } else { fprintf (stderr, "[%s] Listening for connections...\n", prog); mini_inetd(htons(PORT), NULL); fprintf (stderr, "[%s] Connected\n", prog); { char buf[81]; while (gets(buf)) { fprintf(stderr, "[%s] Received [%s]\n", prog, buf); if (!strcmp(buf, "exit")) return 0; /* simple echo */ puts(buf); } fprintf(stderr, "[%s] gets() failed (%s)\n", prog, _strerror("gets")); } } return 1; } static int do_client(void) { int rv = 0; rk_SOCK_INIT(); prog = "Client"; is_client = 1; fprintf(stderr, "Starting client...\n"); rv = test_simple_echo_socket(); rk_SOCK_EXIT(); return rv; } static int do_server(void) { int rv = 0; rk_SOCK_INIT(); prog = "Server"; fprintf(stderr, "Starting server...\n"); rv = test_simple_echo_socket(); rk_SOCK_EXIT(); return rv; } static time_t wait_callback(void *p) { return (time_t)-1; } static int do_test(char * path) { intptr_t p_server; intptr_t p_client; int client_rv; int server_rv; p_server = _spawnl(_P_NOWAIT, path, path, "--server", NULL); if (p_server <= 0) { fprintf(stderr, "%s: %s", path, _strerror("Can't start server process")); return 1; } #ifdef _WIN32 /* On Windows, the _spawn*() functions return a process handle on success. We need a process ID for use with wait_for_process_timed(). */ p_server = GetProcessId((HANDLE) p_server); #endif fprintf(stderr, "Created server process ID %d\n", p_server); p_client = _spawnl(_P_NOWAIT, path, path, "--client", NULL); if (p_client <= 0) { fprintf(stderr, "%s: %s", path, _strerror("Can't start client process")); fprintf(stderr, "Waiting for server process to terminate ..."); wait_for_process_timed(p_server, wait_callback, NULL, 5); fprintf(stderr, "DONE\n"); return 1; } #ifdef _WIN32 p_client = GetProcessId((HANDLE) p_client); #endif fprintf(stderr, "Created client process ID %d\n", p_client); fprintf(stderr, "Waiting for client process to terminate ..."); client_rv = wait_for_process_timed(p_client, wait_callback, NULL, 5); if (SE_IS_ERROR(client_rv)) { fprintf(stderr, "\nwait_for_process_timed() failed for client. rv=%d\n", client_rv); } else { fprintf(stderr, "DONE\n"); } fprintf(stderr, "Waiting for server process to terminate ..."); server_rv = wait_for_process_timed(p_server, wait_callback, NULL, 5); if (SE_IS_ERROR(server_rv)) { fprintf(stderr, "\nwait_for_process_timed() failed for server. rv=%d\n", server_rv); } else { fprintf(stderr, "DONE\n"); } if (client_rv == 0 && server_rv == 0) { fprintf(stderr, "PASS\n"); return 0; } else { fprintf(stderr, "FAIL: Client rv=%d, Server rv=%d\n", client_rv, server_rv); return 1; } } int main(int argc, char ** argv) { setprogname(argv[0]); if (argc == 2 && strcmp(argv[1], "--client") == 0) return do_client(); else if (argc == 2 && strcmp(argv[1], "--server") == 0) return do_server(); else if (argc == 1) return do_test(argv[0]); else { printf ("%s: Test mini_inetd() function. Run with no arguments to start test\n", argv[0]); return 1; } }