]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - tools/regression/netipx/spxloopback/spxloopback.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / tools / regression / netipx / spxloopback / spxloopback.c
1 /*-
2  * Copyright (c) 2006 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$Exp $
27  */
28
29 /*
30  * Simple netipx regression test that attempts to build an SPX stream socket
31  * pair, and send data twice over the stream, once in each direction.
32  * Purposefully pick a small packet length that should fit into the buffers
33  * at both ends, and therefore not result in a buffer deadlock.
34  */
35
36 #include <sys/types.h>
37 #include <sys/socket.h>
38
39 #include <netipx/ipx.h>
40
41 #include <err.h>
42 #include <errno.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #define IPX_ENDPOINT    "0xbebe.1.0x8a13"
49 #define PACKETLEN       128
50
51 #if 0
52 #define SPX_SUPPORTS_SENDTO_WITH_CONNECT
53 #endif
54
55 static void
56 packet_fill(u_char *packet)
57 {
58         int i;
59
60         for (i = 0; i < PACKETLEN; i++)
61                 packet[i] = (i & 0xff);
62 }
63
64 static int
65 packet_check(u_char *packet)
66 {
67         int i;
68
69         for (i = 0; i < PACKETLEN; i++) {
70                 if (packet[i] != (i & 0xff))
71                         return (-1);
72         }
73         return (0);
74 }
75
76 #ifdef SPX_SUPPORTS_SENDTO_WITH_CONNECT
77 static void
78 my_sendto(int sock, const char *who, pid_t pid, struct sockaddr *sa,
79     socklen_t sa_len)
80 {
81         u_char packet[PACKETLEN];
82         ssize_t len;
83         int error;
84
85         packet_fill(packet);
86         len = sendto(sock, packet, sizeof(packet), 0, sa, sa_len);
87         if (len < 0) {
88                 error = errno;
89                 (void)kill(pid, SIGTERM);
90                 errno = error;
91                 err(-1, "%s: sendto()", who);
92         }
93         if (len != sizeof(packet)) {
94                 (void)kill(pid, SIGTERM);
95                 errx(-1, "%s: sendto(): short send (%d length, %d sent)",
96                     who, sizeof(packet), len);
97         }
98 }
99 #endif
100
101 static void
102 my_send(int sock, const char *who, pid_t pid)
103 {
104         u_char packet[PACKETLEN];
105         ssize_t len;
106         int error;
107
108         packet_fill(packet);
109         len = send(sock, packet, sizeof(packet), 0);
110         if (len < 0) {
111                 error = errno;
112                 (void)kill(pid, SIGTERM);
113                 errno = error;
114                 err(-1, "%s: send()", who);
115         }
116         if (len != sizeof(packet)) {
117                 (void)kill(pid, SIGTERM);
118                 errx(-1, "%s: send(): short send (%d length, %d sent)", who,
119                     sizeof(packet), len);
120         }
121 }
122
123 static void
124 my_recv(int sock, const char *who, pid_t pid)
125 {
126         u_char packet[PACKETLEN];
127         ssize_t len;
128         int error;
129
130         bzero(packet, sizeof(packet));
131         len = recv(sock, packet, sizeof(packet), 0);
132         if (len < 0) {
133                 errno = error;
134                 (void)kill(pid, SIGTERM);
135                 errno = error;
136                 err(-1, "%s: recv()", who);
137         }
138         if (len != sizeof(packet)) {
139                 (void)kill(pid, SIGTERM);
140                 errx(-1, "%s: recv(): got %d expected %d", who, len,
141                     sizeof(packet));
142         }
143         if (packet_check(packet) < 0) {
144                 (void)kill(pid, SIGTERM);
145                 errx(-1, "%s: recv(): got bad data", who);
146         }
147 }
148
149 int
150 main(int argc, char *argv[])
151 {
152         int error, sock_listen, sock_recv, sock_send;
153         struct sockaddr_ipx sipx_listen, sipx_send;
154         pid_t childpid, parentpid;
155
156         /*
157          * Socket to receive with.
158          */
159         sock_listen = socket(PF_IPX, SOCK_STREAM, 0);
160         if (sock_listen < 0)
161                 err(-1, "sock_listen = socket(PF_IPX, SOCK_STREAM, 0)");
162
163         bzero(&sipx_listen, sizeof(sipx_listen));
164         sipx_listen.sipx_len = sizeof(sipx_listen);
165         sipx_listen.sipx_family = AF_IPX;
166         sipx_listen.sipx_addr = ipx_addr(IPX_ENDPOINT);
167
168         if (bind(sock_listen, (struct sockaddr *)&sipx_listen,
169             sizeof(sipx_listen)) < 0)
170                 err(-1, "bind(sock_listen)");
171
172         if (listen(sock_listen, -1) < 0)
173                 err(-1, "listen(sock_listen)");
174
175         parentpid = getpid();
176
177         childpid = fork();
178         if (childpid < 0)
179                 err(-1, "fork()");
180
181         if (childpid == 0) {
182                 /*
183                  * The child: accept connections and process data on them.
184                  */
185                 while (1) {
186                         sock_recv = accept(sock_listen, NULL, NULL);
187                         if (sock_recv < 0) {
188                                 warn("accept()");
189                                 continue;
190                         }
191
192                         my_recv(sock_recv, "listener", parentpid);
193                         my_send(sock_recv, "listener", parentpid);
194
195                         close(sock_recv);
196                 }
197         } else {
198                 /*
199                  * The parent: connect, send data, receive it back, and exit;
200                  * build two connections, once using a full connect() API
201                  * call, and the second using sendto().
202                  */
203
204                 /*
205                  * Socket to send with.
206                  */
207                 sock_send = socket(PF_IPX, SOCK_STREAM, 0);
208                 if (sock_send < 0) {
209                         error = errno;
210                         (void)kill(childpid, SIGTERM);
211                         errno = error;
212                         err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)");
213                 }
214
215                 bzero(&sipx_send, sizeof(sipx_send));
216                 sipx_send.sipx_len = sizeof(sipx_send);
217                 sipx_send.sipx_family = AF_IPX;
218                 sipx_send.sipx_addr = ipx_addr(IPX_ENDPOINT);
219
220                 if (connect(sock_send, (struct sockaddr *)&sipx_send,
221                     sizeof(sipx_send)) < 0) {
222                         error = errno;
223                         (void)kill(childpid, SIGTERM);
224                         errno = error;
225                         err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)");
226                 }
227
228                 my_send(sock_send, "connector", childpid);
229                 my_recv(sock_send, "connector", childpid);
230
231                 close(sock_send);
232
233 #ifdef SPX_SUPPORTS_SENDTO_WITH_CONNECT
234                 sock_send = socket(PF_IPX, SOCK_STREAM, 0);
235                 if (sock_send < 0) {
236                         error = errno;
237                         (void)kill(childpid, SIGTERM);
238                         errno = error;
239                         err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)");
240                 }
241
242                 bzero(&sipx_send, sizeof(sipx_send));
243                 sipx_send.sipx_len = sizeof(sipx_send);
244                 sipx_send.sipx_family = AF_IPX;
245                 sipx_send.sipx_addr = ipx_addr(IPX_ENDPOINT);
246
247                 my_sendto(sock_send, "connector", childpid,
248                     (struct sockaddr *)&sipx_send, sizeof(sipx_send));
249                 my_recv(sock_send, "connector", childpid);
250
251                 close(sock_send);
252 #endif
253
254                 (void)kill(childpid, SIGTERM);
255         }
256
257         return (0);
258 }