Add test for mini_inetd()
This commit is contained in:

committed by
Love Hornquist Astrand

parent
170e8158cb
commit
c0600f525c
360
lib/roken/test-mini_inetd.c
Normal file
360
lib/roken/test-mini_inetd.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/***********************************************************************
|
||||
* 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 <config.h>
|
||||
#include <roken.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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) {
|
||||
fprintf(stderr, "[%s] getaddrinfo: %s", prog, gai_strerror(rv));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
get_connected_socket(SOCKET * s_ret)
|
||||
{
|
||||
struct addrinfo * ai = NULL;
|
||||
int rv = 0;
|
||||
SOCKET s = INVALID_SOCKET;
|
||||
|
||||
rv = get_address(0, &ai);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (IS_BAD_SOCKET(s)) {
|
||||
rv = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rv = connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
if (IS_SOCKET_ERROR(rv))
|
||||
goto done;
|
||||
|
||||
*s_ret = s;
|
||||
s = INVALID_SOCKET;
|
||||
rv = 0;
|
||||
|
||||
done:
|
||||
if (!IS_BAD_SOCKET(s))
|
||||
closesocket(s);
|
||||
|
||||
if (ai)
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return (rv)?SOCK_ERRNO: 0;
|
||||
}
|
||||
|
||||
const char * test_strings[] = {
|
||||
"Hello",
|
||||
"01234566789012345689012345678901234567890123456789",
|
||||
"Another test",
|
||||
"exit"
|
||||
};
|
||||
|
||||
static int
|
||||
test_simple_echo_client(void)
|
||||
{
|
||||
SOCKET s = INVALID_SOCKET;
|
||||
int rv;
|
||||
char buf[81];
|
||||
int i;
|
||||
|
||||
fprintf (stderr, "[%s] Getting connected socket...", prog);
|
||||
rv = get_connected_socket(&s);
|
||||
if (rv) {
|
||||
fprintf(stderr, "\n[%s] get_connected_socket() failed (%s)\n", prog, strerror(SOCK_ERRNO));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf (stderr, "[%s] done\n", prog);
|
||||
|
||||
for (i=0; i < sizeof(test_strings)/sizeof(test_strings[0]); i++) {
|
||||
rv = send(s, test_strings[i], strlen(test_strings[i]), 0);
|
||||
if (IS_SOCKET_ERROR(rv)) {
|
||||
fprintf (stderr, "[%s] send() failure (%s)\n", prog, strerror(SOCK_ERRNO));
|
||||
closesocket(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rv = recv(s, buf, sizeof(buf), 0);
|
||||
if (IS_SOCKET_ERROR(rv)) {
|
||||
fprintf (stderr, "[%s] recv() failure (%s)\n", prog, strerror(SOCK_ERRNO));
|
||||
closesocket(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
fprintf (stderr, "[%s] No data received\n", prog);
|
||||
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]));
|
||||
closesocket(s);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "[%s] Done\n", prog);
|
||||
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 {
|
||||
|
||||
SOCKET s = INVALID_SOCKET;
|
||||
|
||||
fprintf (stderr, "[%s] Listening for connections...\n", prog);
|
||||
mini_inetd(htons(PORT), &s);
|
||||
if (IS_BAD_SOCKET(s)) {
|
||||
fprintf (stderr, "[%s] Connect failed (%s)\n", prog, strerror(SOCK_ERRNO));
|
||||
} else {
|
||||
fprintf (stderr, "[%s] Connected\n", prog);
|
||||
}
|
||||
|
||||
{
|
||||
char buf[81];
|
||||
int rv, srv;
|
||||
|
||||
while ((rv = recv(s, buf, sizeof(buf), 0)) != 0 && !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 (IS_SOCKET_ERROR(srv))
|
||||
fprintf(stderr, "[%s] send() error [%s]\n", prog, strerror(SOCK_ERRNO));
|
||||
else
|
||||
fprintf(stderr, "[%s] send() size mismatch %d != %d", prog, srv, rv);
|
||||
}
|
||||
|
||||
if (!strcmp(buf, "exit")) {
|
||||
fprintf(stderr, "[%s] Exiting...\n", prog);
|
||||
shutdown(s, SD_SEND);
|
||||
closesocket(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "[%s] recv() failed (%s)\n", prog, strerror(SOCK_ERRNO));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
SOCK_INIT;
|
||||
|
||||
prog = "Client";
|
||||
is_client = 1;
|
||||
|
||||
fprintf(stderr, "Starting client...\n");
|
||||
|
||||
rv = test_simple_echo_socket();
|
||||
|
||||
SOCK_EXIT;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
do_server(void)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
SOCK_INIT;
|
||||
|
||||
prog = "Server";
|
||||
|
||||
fprintf(stderr, "Starting server...\n");
|
||||
|
||||
rv = test_simple_echo_socket();
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user