aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/regression/netipx/spxloopback/Makefile12
-rw-r--r--tools/regression/netipx/spxloopback/spxloopback.c258
2 files changed, 270 insertions, 0 deletions
diff --git a/tools/regression/netipx/spxloopback/Makefile b/tools/regression/netipx/spxloopback/Makefile
new file mode 100644
index 000000000000..a5a47ae00ec4
--- /dev/null
+++ b/tools/regression/netipx/spxloopback/Makefile
@@ -0,0 +1,12 @@
+#
+# $FreeBSD$
+#
+
+PROG= spxloopback
+NO_MAN=
+
+DPADD= ${LIBIPX};
+LDADD= -lipx
+WARNS= 3
+
+.include <bsd.prog.mk>
diff --git a/tools/regression/netipx/spxloopback/spxloopback.c b/tools/regression/netipx/spxloopback/spxloopback.c
new file mode 100644
index 000000000000..9561cff699f0
--- /dev/null
+++ b/tools/regression/netipx/spxloopback/spxloopback.c
@@ -0,0 +1,258 @@
+/*-
+ * Copyright (c) 2006 Robert N. M. Watson
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$Exp $
+ */
+
+/*
+ * Simple netipx regression test that attempts to build an SPX stream socket
+ * pair, and send data twice over the stream, once in each direction.
+ * Purposefully pick a small packet length that should fit into the buffers
+ * at both ends, and therefore not result in a buffer deadlock.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netipx/ipx.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define IPX_ENDPOINT "0xbebe.1.0x8a13"
+#define PACKETLEN 128
+
+#if 0
+#define SPX_SUPPORTS_SENDTO_WITH_CONNECT
+#endif
+
+static void
+packet_fill(u_char *packet)
+{
+ int i;
+
+ for (i = 0; i < PACKETLEN; i++)
+ packet[i] = (i & 0xff);
+}
+
+static int
+packet_check(u_char *packet)
+{
+ int i;
+
+ for (i = 0; i < PACKETLEN; i++) {
+ if (packet[i] != (i & 0xff))
+ return (-1);
+ }
+ return (0);
+}
+
+#ifdef SPX_SUPPORTS_SENDTO_WITH_CONNECT
+static void
+my_sendto(int sock, const char *who, pid_t pid, struct sockaddr *sa,
+ socklen_t sa_len)
+{
+ u_char packet[PACKETLEN];
+ ssize_t len;
+ int error;
+
+ packet_fill(packet);
+ len = sendto(sock, packet, sizeof(packet), 0, sa, sa_len);
+ if (len < 0) {
+ error = errno;
+ (void)kill(pid, SIGTERM);
+ errno = error;
+ err(-1, "%s: sendto()", who);
+ }
+ if (len != sizeof(packet)) {
+ (void)kill(pid, SIGTERM);
+ errx(-1, "%s: sendto(): short send (%d length, %d sent)",
+ who, sizeof(packet), len);
+ }
+}
+#endif
+
+static void
+my_send(int sock, const char *who, pid_t pid)
+{
+ u_char packet[PACKETLEN];
+ ssize_t len;
+ int error;
+
+ packet_fill(packet);
+ len = send(sock, packet, sizeof(packet), 0);
+ if (len < 0) {
+ error = errno;
+ (void)kill(pid, SIGTERM);
+ errno = error;
+ err(-1, "%s: send()", who);
+ }
+ if (len != sizeof(packet)) {
+ (void)kill(pid, SIGTERM);
+ errx(-1, "%s: send(): short send (%d length, %d sent)", who,
+ sizeof(packet), len);
+ }
+}
+
+static void
+my_recv(int sock, const char *who, pid_t pid)
+{
+ u_char packet[PACKETLEN];
+ ssize_t len;
+ int error;
+
+ bzero(packet, sizeof(packet));
+ len = recv(sock, packet, sizeof(packet), 0);
+ if (len < 0) {
+ errno = error;
+ (void)kill(pid, SIGTERM);
+ errno = error;
+ err(-1, "%s: recv()", who);
+ }
+ if (len != sizeof(packet)) {
+ (void)kill(pid, SIGTERM);
+ errx(-1, "%s: recv(): got %d expected %d", who, len,
+ sizeof(packet));
+ }
+ if (packet_check(packet) < 0) {
+ (void)kill(pid, SIGTERM);
+ errx(-1, "%s: recv(): got bad data", who);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int error, sock_listen, sock_recv, sock_send;
+ struct sockaddr_ipx sipx_listen, sipx_send;
+ pid_t childpid, parentpid;
+
+ /*
+ * Socket to receive with.
+ */
+ sock_listen = socket(PF_IPX, SOCK_STREAM, 0);
+ if (sock_listen < 0)
+ err(-1, "sock_listen = socket(PF_IPX, SOCK_STREAM, 0)");
+
+ bzero(&sipx_listen, sizeof(sipx_listen));
+ sipx_listen.sipx_len = sizeof(sipx_listen);
+ sipx_listen.sipx_family = AF_IPX;
+ sipx_listen.sipx_addr = ipx_addr(IPX_ENDPOINT);
+
+ if (bind(sock_listen, (struct sockaddr *)&sipx_listen,
+ sizeof(sipx_listen)) < 0)
+ err(-1, "bind(sock_listen)");
+
+ if (listen(sock_listen, -1) < 0)
+ err(-1, "listen(sock_listen)");
+
+ parentpid = getpid();
+
+ childpid = fork();
+ if (childpid < 0)
+ err(-1, "fork()");
+
+ if (childpid == 0) {
+ /*
+ * The child: accept connections and process data on them.
+ */
+ while (1) {
+ sock_recv = accept(sock_listen, NULL, NULL);
+ if (sock_recv < 0) {
+ warn("accept()");
+ continue;
+ }
+
+ my_recv(sock_recv, "listener", parentpid);
+ my_send(sock_recv, "listener", parentpid);
+
+ close(sock_recv);
+ }
+ } else {
+ /*
+ * The parent: connect, send data, receive it back, and exit;
+ * build two connections, once using a full connect() API
+ * call, and the second using sendto().
+ */
+
+ /*
+ * Socket to send with.
+ */
+ sock_send = socket(PF_IPX, SOCK_STREAM, 0);
+ if (sock_send < 0) {
+ error = errno;
+ (void)kill(childpid, SIGTERM);
+ errno = error;
+ err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)");
+ }
+
+ bzero(&sipx_send, sizeof(sipx_send));
+ sipx_send.sipx_len = sizeof(sipx_send);
+ sipx_send.sipx_family = AF_IPX;
+ sipx_send.sipx_addr = ipx_addr(IPX_ENDPOINT);
+
+ if (connect(sock_send, (struct sockaddr *)&sipx_send,
+ sizeof(sipx_send)) < 0) {
+ error = errno;
+ (void)kill(childpid, SIGTERM);
+ errno = error;
+ err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)");
+ }
+
+ my_send(sock_send, "connector", childpid);
+ my_recv(sock_send, "connector", childpid);
+
+ close(sock_send);
+
+#ifdef SPX_SUPPORTS_SENDTO_WITH_CONNECT
+ sock_send = socket(PF_IPX, SOCK_STREAM, 0);
+ if (sock_send < 0) {
+ error = errno;
+ (void)kill(childpid, SIGTERM);
+ errno = error;
+ err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)");
+ }
+
+ bzero(&sipx_send, sizeof(sipx_send));
+ sipx_send.sipx_len = sizeof(sipx_send);
+ sipx_send.sipx_family = AF_IPX;
+ sipx_send.sipx_addr = ipx_addr(IPX_ENDPOINT);
+
+ my_sendto(sock_send, "connector", childpid,
+ (struct sockaddr *)&sipx_send, sizeof(sipx_send));
+ my_recv(sock_send, "connector", childpid);
+
+ close(sock_send);
+#endif
+
+ (void)kill(childpid, SIGTERM);
+ }
+
+ return (0);
+}