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 16 * (1024 * 1024) 50 51static void 52packet_fill(u_char *packet) 53{ 54 int i; 55 56 for (i = 0; i < PACKETLEN; i++) 57 packet[i] = (i & 0xff); 58} 59 60static int 61packet_check(u_char *packet, size_t totlen, ssize_t len) 62{ 63 size_t i; 64 65 for (i = totlen; i < totlen + len; i++) { 66 if (packet[i] != (i & 0xff)) 67 return (-1); 68 } 69 return (0); 70} 71 72static void 73my_send(int sock, const char *who, pid_t pid) 74{ 75 u_char packet[PACKETLEN]; 76 ssize_t len; 77 size_t totlen; 78 int error; 79 80 totlen = 0; 81 packet_fill(packet); 82 while (totlen < PACKETLEN) { 83 len = send(sock, packet + totlen, PACKETLEN - totlen, 0); 84 if (len < 0) { 85 error = errno; 86 (void)kill(pid, SIGTERM); 87 errno = error; 88 err(-1, "%s: send()", who); 89 } 90 if (len == 0) { 91 (void)kill(pid, SIGTERM); 92 errx(-1, "%s: send(): EOF", who); 93 } 94 totlen += len; 95 } 96} 97 98static void 99my_recv(int sock, const char *who, pid_t pid) 100{ 101 u_char packet[PACKETLEN]; 102 ssize_t len; 103 size_t totlen; 104 int error; 105 106 totlen = 0; 107 bzero(packet, sizeof(packet)); 108 while (totlen < PACKETLEN) { 109 len = recv(sock, packet + totlen, sizeof(packet) - totlen, 0); 110 if (len < 0) { 111 errno = error; 112 (void)kill(pid, SIGTERM); 113 errno = error; 114 err(-1, "%s: recv()", who); 115 } 116 if (len == 0) { 117 (void)kill(pid, SIGTERM); 118 errx(-1, "%s: recv(): EOF", who); 119 } 120 if (packet_check(packet, totlen, len) < 0) { 121 (void)kill(pid, SIGTERM); 122 errx(-1, "%s: recv(): got bad data", who); 123 } 124 totlen += len; 125 } 126} 127 128int 129main(int argc, char *argv[]) 130{ 131 int error, sock_listen, sock_recv, sock_send; 132 struct sockaddr_ipx sipx_listen, sipx_send; 133 pid_t childpid, parentpid; 134 135 /* 136 * Socket to receive with. 137 */ 138 sock_listen = socket(PF_IPX, SOCK_STREAM, 0); 139 if (sock_listen < 0) 140 err(-1, "sock_listen = socket(PF_IPX, SOCK_STREAM, 0)"); 141 142 bzero(&sipx_listen, sizeof(sipx_listen)); 143 sipx_listen.sipx_len = sizeof(sipx_listen); 144 sipx_listen.sipx_family = AF_IPX; 145 sipx_listen.sipx_addr = ipx_addr(IPX_ENDPOINT); 146 147 if (bind(sock_listen, (struct sockaddr *)&sipx_listen, 148 sizeof(sipx_listen)) < 0) 149 err(-1, "bind(sock_listen)"); 150 151 if (listen(sock_listen, -1) < 0) 152 err(-1, "listen(sock_listen)"); 153 154 parentpid = getpid(); 155 156 childpid = fork(); 157 if (childpid < 0) 158 err(-1, "fork()"); 159 160 if (childpid == 0) { 161 /* 162 * The child: accept connections and process data on them. 163 */ 164 while (1) { 165 sock_recv = accept(sock_listen, NULL, NULL); 166 if (sock_recv < 0) { 167 warn("accept()"); 168 continue; 169 } 170 171 my_recv(sock_recv, "listener", parentpid); 172 my_send(sock_recv, "listener", parentpid); 173 174 close(sock_recv); 175 } 176 } else { 177 /* 178 * The parent: connect, send data, receive it back, and exit; 179 * build two connections, once using a full connect() API 180 * call, and the second using sendto(). 181 */ 182 183 /* 184 * Socket to send with. 185 */ 186 sock_send = socket(PF_IPX, SOCK_STREAM, 0); 187 if (sock_send < 0) { 188 error = errno; 189 (void)kill(childpid, SIGTERM); 190 errno = error; 191 err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)"); 192 } 193 194 bzero(&sipx_send, sizeof(sipx_send)); 195 sipx_send.sipx_len = sizeof(sipx_send); 196 sipx_send.sipx_family = AF_IPX; 197 sipx_send.sipx_addr = ipx_addr(IPX_ENDPOINT); 198 199 if (connect(sock_send, (struct sockaddr *)&sipx_send, 200 sizeof(sipx_send)) < 0) { 201 error = errno; 202 (void)kill(childpid, SIGTERM); 203 errno = error; 204 err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)"); 205 } 206 207 my_send(sock_send, "connector", childpid); 208 my_recv(sock_send, "connector", childpid); 209 210 close(sock_send); 211 212#ifdef SPX_SUPPORTS_SENDTO_WITH_CONNECT 213 sock_send = socket(PF_IPX, SOCK_STREAM, 0); 214 if (sock_send < 0) { 215 error = errno; 216 (void)kill(childpid, SIGTERM); 217 errno = error; 218 err(-1, "sock_send = socket(PF_IPX, SOCK_STREAM, 0)"); 219 } 220 221 bzero(&sipx_send, sizeof(sipx_send)); 222 sipx_send.sipx_len = sizeof(sipx_send); 223 sipx_send.sipx_family = AF_IPX; 224 sipx_send.sipx_addr = ipx_addr(IPX_ENDPOINT); 225 226 my_sendto(sock_send, "connector", childpid, 227 (struct sockaddr *)&sipx_send, sizeof(sipx_send)); 228 my_recv(sock_send, "connector", childpid); 229 230 close(sock_send); 231#endif 232 233 (void)kill(childpid, SIGTERM); 234 } 235 236 return (0); 237} 238