From 266ee3a1fe181ae38a548cdb8608cc2f7aac6bb7 Mon Sep 17 00:00:00 2001 From: Sahil Siddiq Date: Sun, 7 Jul 2024 12:55:34 +0530 Subject: [PATCH] tests: Add test rx/simple This adds a new test, rx/simple, which runs a simple rx client against a server process. It does not make use of rxgen-generated RPCs, but instead runs as a single stream of data on an rx call. The client creates a new connection to this service and sends a string. The server performs a simple transformation (rot13) and returns the new string back to the client. This commit adds the simple-client and simple-server programs, as well as the "simple-t" script test driver. These programs serve as a very simple example of using Rx, as well as a basic functionality test. Co-developed-by: Andrew Deason Change-Id: I78862ecb75a9bb3ccbfef049d11a95182c5e0278 Reviewed-on: https://gerrit.openafs.org/15780 Reviewed-by: Cheyenne Wills Tested-by: BuildBot Reviewed-by: Andrew Deason --- tests/TESTS | 1 + tests/rx/.gitignore | 2 + tests/rx/Makefile.in | 12 +++- tests/rx/simple-client.c | 133 ++++++++++++++++++++++++++++++++++++ tests/rx/simple-server.c | 141 +++++++++++++++++++++++++++++++++++++++ tests/rx/simple-t | 76 +++++++++++++++++++++ 6 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 tests/rx/simple-client.c create mode 100644 tests/rx/simple-server.c create mode 100755 tests/rx/simple-t diff --git a/tests/TESTS b/tests/TESTS index 1b03efa517..760f3f8a53 100644 --- a/tests/TESTS +++ b/tests/TESTS @@ -21,6 +21,7 @@ ptserver/pts-man rx/atomic rx/event rx/perf +rx/simple volser/vos-man volser/vos bucoord/backup-man diff --git a/tests/rx/.gitignore b/tests/rx/.gitignore index 230b5820df..48efbeeba6 100644 --- a/tests/rx/.gitignore +++ b/tests/rx/.gitignore @@ -1,2 +1,4 @@ /atomic-t /event-t +/simple-client +/simple-server diff --git a/tests/rx/Makefile.in b/tests/rx/Makefile.in index fe172e4693..891ab867f4 100644 --- a/tests/rx/Makefile.in +++ b/tests/rx/Makefile.in @@ -10,7 +10,10 @@ MODULE_CFLAGS = -I$(TOP_OBJDIR) LIBS = $(abs_top_builddir)/tests/common/libafstest_common.la \ $(abs_top_builddir)/src/rx/liboafs_rx.la -BINS = atomic-t event-t +SIMPLE_LIBS = $(TOP_LIBDIR)/libafsrpc.a \ + $(TOP_LIBDIR)/libafsutil.a + +BINS = atomic-t event-t simple-client simple-server all: $(BINS) @@ -19,6 +22,13 @@ atomic-t: atomic-t.o $(LIBS) event-t: event-t.o $(LIBS) $(LT_LDRULE_static) event-t.o $(LIBS) $(LIB_roken) $(XLIBS) + +simple-client: simple-client.o $(SIMPLE_LIBS) + $(LT_LDRULE_static) simple-client.o $(SIMPLE_LIBS) ${LIB_hcrypto} $(LIB_roken) $(XLIBS) + +simple-server: simple-server.o $(SIMPLE_LIBS) + $(LT_LDRULE_static) simple-server.o $(SIMPLE_LIBS) ${LIB_hcrypto} $(LIB_roken) $(XLIBS) + install: clean distclean: diff --git a/tests/rx/simple-client.c b/tests/rx/simple-client.c new file mode 100644 index 0000000000..ed9c8e2c29 --- /dev/null +++ b/tests/rx/simple-client.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 Sahil Siddiq . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR `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 AUTHOR 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 + +#include +#include + +static afs_uint32 +str2addr(char *str) +{ + afs_int32 addr = 0; + struct hostent *th = hostutil_GetHostByName(str); + if (th == NULL) { + errx(1, "Could not resolve host '%s'", str); + } + memcpy(&addr, th->h_addr, sizeof(addr)); + return addr; +} + +static afs_uint32 +str2int(const char *str) +{ + return strtoul(str, NULL, 10); +} + +static int +run_call(struct rx_connection *conn, char *message) +{ + struct rx_call *call; + afs_int32 nbytes = strlen(message); + afs_int32 nbytes_n; + char *recvbuf; + afs_int32 code = RX_PROTOCOL_ERROR; + + recvbuf = calloc(nbytes + 1, 1); + opr_Assert(recvbuf != NULL); + + call = rx_NewCall(conn); + opr_Assert(call != NULL); + + nbytes_n = htonl(nbytes); + if (rx_Write32(call, &nbytes_n) != sizeof(nbytes_n)) { + warnx("rx_Write32 failed"); + goto done; + } + + if (rx_Write(call, message, nbytes) != nbytes) { + warnx("rx_Write failed"); + goto done; + } + + if (rx_Read(call, recvbuf, nbytes) != nbytes) { + warnx("rx_Read failed"); + goto done; + } + + printf("%s\n", recvbuf); + + code = 0; + + done: + code = rx_EndCall(call, code); + if (code != 0) { + warnx("call aborted with code %d", code); + } + free(recvbuf); + return code; +} + +int +main(int argc, char **argv) +{ + afs_uint32 host; + afs_uint16 port; + afs_uint16 service_id; + char *message; + int code; + struct rx_connection *conn; + + setprogname(argv[0]); + + if (argc != 5) { + errx(1, "Usage: %s ", getprogname()); + } + + host = str2addr(argv[1]); + port = str2int(argv[2]); + service_id = str2int(argv[3]); + message = argv[4]; + + code = rx_Init(0); + if (code != 0) { + errx(1, "rx_Init failed with %d", code); + } + + conn = rx_NewConnection(host, htons(port), service_id, + rxnull_NewClientSecurityObject(), 0); + opr_Assert(conn != NULL); + + code = run_call(conn, message); + + rx_DestroyConnection(conn); + + return code; +} diff --git a/tests/rx/simple-server.c b/tests/rx/simple-server.c new file mode 100644 index 0000000000..6412d62d17 --- /dev/null +++ b/tests/rx/simple-server.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024 Sahil Siddiq . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR `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 AUTHOR 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 MAX_SIZE 16 + +/* Arbitrary error code constants. */ +#define ERROR_TOOBIG 201 + +static afs_uint32 +str2int(const char *str) +{ + return strtoul(str, NULL, 10); +} + +static void +rot13(char *buf, afs_int32 nbytes) +{ + int i; + for (i = 0; i < nbytes; i++) { + if ((buf[i] >= 'n' && buf[i] <= 'z') || + (buf[i] >= 'N' && buf[i] <= 'Z')) + { + buf[i] -= 13; + } else if ((buf[i] >= 'a' && buf[i] <= 'm') || + (buf[i] >= 'A' && buf[i] <= 'M')) + { + buf[i] += 13; + } + } +} + +static afs_int32 +rxsimple_ExecuteRequest(struct rx_call *call) +{ + afs_int32 nbytes; + afs_int32 nbytes_n; + afs_int32 code = RX_PROTOCOL_ERROR; + char buf[MAX_SIZE]; + + memset(buf, 0, sizeof(buf)); + + if (rx_Read32(call, &nbytes_n) != sizeof(nbytes_n)) { + warnx("rx_Read32 failed"); + goto done; + } + nbytes = ntohl(nbytes_n); + + if (nbytes > sizeof(buf)) { + warnx("nbytes too large: %d > %d", nbytes, (int)sizeof(buf)); + code = ERROR_TOOBIG; + goto done; + } + + if (rx_Read(call, buf, nbytes) != nbytes) { + warnx("rx_Read failed"); + goto done; + } + + rot13(buf, nbytes); + + if (rx_Write(call, buf, nbytes) != nbytes) { + warnx("rx_Write failed"); + goto done; + } + + code = 0; + + done: + return code; +} + +int +main(int argc, char **argv) +{ + afs_uint16 port; + afs_uint16 service_id; + afs_int32 code; + struct rx_service *service; + struct rx_securityClass *secobj; + + setprogname(argv[0]); + + if (argc != 3) { + errx(1, "Usage: %s ", getprogname()); + } + + port = str2int(argv[1]); + service_id = str2int(argv[2]); + + code = rx_Init(htons(port)); + if (code != 0) { + errx(1, "rx_Init failed with %d", code); + } + + secobj = rxnull_NewClientSecurityObject(); + service = rx_NewService(0, service_id, "rxsimple", &secobj, 1, + rxsimple_ExecuteRequest); + opr_Assert(service != NULL); + + rx_StartServer(0); + + printf("%s: Ready to receive calls\n", getprogname()); + + /* Close stdout to indicate that the server is ready to receive calls. */ + fclose(stdout); + + rx_ServerProc(NULL); + abort(); + + return 1; +} diff --git a/tests/rx/simple-t b/tests/rx/simple-t new file mode 100755 index 0000000000..11f7edb428 --- /dev/null +++ b/tests/rx/simple-t @@ -0,0 +1,76 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2024 Sahil Siddiq . +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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 AUTHOR `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 AUTHOR 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. + +use strict; +use warnings; +use lib $ENV{C_TAP_SOURCE} . "/tests-lib/perl5"; + +use afstest qw(obj_path); +use Test::More tests=>4; +use POSIX qw(:sys_wait_h :signal_h); + +my $port = 4000; +my $service = 1234; +my $server = obj_path("tests/rx/simple-server"); +my $client = obj_path("tests/rx/simple-client"); +my $server_pid; + +# Start up the server +$server_pid = open(my $server_fh, '-|', $server, $port, $service); +if (!defined($server_pid)) { + die("Failed to run $server: $!"); +} + +# Wait for the server to finish starting +while (my $line = <$server_fh>) { + chomp($line); + diag($line); +} + +# Server is now ready to receive calls + +pass("Started server"); + +# Start up a client, and run a test +my $message = 'Hello OpenAFS'; +my $expected = 'Uryyb BcraNSF'; +my $got = qx($client localhost $port $service "$message"); +chomp($got); + +is(0, $?, "Client ran successfully"); +is($expected, $got, "Rot13 performed successfully"); + +# Kill the server process +kill("TERM", $server_pid); + +close($server_fh); +my $ecode = ${^CHILD_ERROR_NATIVE}; +if (WIFSIGNALED($ecode) && WTERMSIG($ecode) == SIGTERM) { + pass("Server died with SIGTERM"); +} elsif (WIFSIGNALED($ecode)) { + fail("Server died with signal ".WTERMSIG($ecode)); +} else { + fail("Server exited with code". WEXITSTATUS($ecode)); +}