1/* $NetBSD: test-mini_inetd.c,v 1.1.1.1 2011/04/13 18:15:43 elric Exp $ */ 2 3/*********************************************************************** 4 * Copyright (c) 2009, Secure Endpoints Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * - Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 **********************************************************************/ 33 34#include <config.h> 35#include <krb5/roken.h> 36#include <stdio.h> 37#include <string.h> 38#include <stdlib.h> 39 40#define PORT 8013 41#define PORT_S "8013" 42 43char * prog = "Master"; 44int is_client = 0; 45 46static int 47get_address(int flags, struct addrinfo ** ret) 48{ 49 struct addrinfo ai; 50 int rv; 51 52 memset(&ai, 0, sizeof(ai)); 53 54 ai.ai_flags = flags | AI_NUMERICHOST; 55 ai.ai_family = AF_INET; 56 ai.ai_socktype = SOCK_STREAM; 57 ai.ai_protocol = PF_UNSPEC; 58 59 rv = getaddrinfo("127.0.0.1", PORT_S, &ai, ret); 60 if (rv) 61 warnx("getaddrinfo: %s", gai_strerror(rv)); 62 return rv; 63} 64 65static int 66get_connected_socket(rk_socket_t * s_ret) 67{ 68 struct addrinfo * ai = NULL; 69 int rv = 0; 70 rk_socket_t s = rk_INVALID_SOCKET; 71 72 rv = get_address(0, &ai); 73 if (rv) 74 return rv; 75 76 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 77 if (rk_IS_BAD_SOCKET(s)) { 78 rv = 1; 79 goto done; 80 } 81 82 rv = connect(s, ai->ai_addr, ai->ai_addrlen); 83 if (rk_IS_SOCKET_ERROR(rv)) 84 goto done; 85 86 *s_ret = s; 87 s = rk_INVALID_SOCKET; 88 rv = 0; 89 90 done: 91 if (!rk_IS_BAD_SOCKET(s)) 92 rk_closesocket(s); 93 94 if (ai) 95 freeaddrinfo(ai); 96 97 return (rv) ? rk_SOCK_ERRNO : 0; 98} 99 100const char * test_strings[] = { 101 "Hello", 102 "01234566789012345689012345678901234567890123456789", 103 "Another test", 104 "exit" 105}; 106 107static int 108test_simple_echo_client(void) 109{ 110 rk_socket_t s = rk_INVALID_SOCKET; 111 int rv; 112 char buf[81]; 113 int i; 114 115 fprintf(stderr, "[%s] Getting connected socket...", getprogname()); 116 rv = get_connected_socket(&s); 117 if (rv) { 118 fprintf(stderr, "\n[%s] get_connected_socket() failed (%s)\n", 119 getprogname(), strerror(rk_SOCK_ERRNO)); 120 return 1; 121 } 122 123 fprintf(stderr, "[%s] done\n", getprogname()); 124 125 for (i=0; i < sizeof(test_strings)/sizeof(test_strings[0]); i++) { 126 rv = send(s, test_strings[i], strlen(test_strings[i]), 0); 127 if (rk_IS_SOCKET_ERROR(rv)) { 128 fprintf(stderr, "[%s] send() failure (%s)\n", 129 getprogname(), strerror(rk_SOCK_ERRNO)); 130 rk_closesocket(s); 131 return 1; 132 } 133 134 rv = recv(s, buf, sizeof(buf), 0); 135 if (rk_IS_SOCKET_ERROR(rv)) { 136 fprintf (stderr, "[%s] recv() failure (%s)\n", 137 getprogname(), strerror(rk_SOCK_ERRNO)); 138 rk_closesocket(s); 139 return 1; 140 } 141 142 if (rv == 0) { 143 fprintf (stderr, "[%s] No data received\n", prog); 144 rk_closesocket(s); 145 return 1; 146 } 147 148 if (rv != strlen(test_strings[i])) { 149 fprintf (stderr, "[%s] Data length mismatch %d != %d\n", prog, rv, strlen(test_strings[i])); 150 rk_closesocket(s); 151 return 1; 152 } 153 } 154 155 fprintf (stderr, "[%s] Done\n", prog); 156 rk_closesocket(s); 157 return 0; 158} 159 160static int 161test_simple_echo_socket(void) 162{ 163 fprintf (stderr, "[%s] Process ID %d\n", prog, GetCurrentProcessId()); 164 fprintf (stderr, "[%s] Starting echo test with sockets\n", prog); 165 166 if (is_client) { 167 return test_simple_echo_client(); 168 } else { 169 170 rk_socket_t s = rk_INVALID_SOCKET; 171 172 fprintf (stderr, "[%s] Listening for connections...\n", prog); 173 mini_inetd(htons(PORT), &s); 174 if (rk_IS_BAD_SOCKET(s)) { 175 fprintf (stderr, "[%s] Connect failed (%s)\n", 176 getprogname(), strerror(rk_SOCK_ERRNO)); 177 } else { 178 fprintf (stderr, "[%s] Connected\n", prog); 179 } 180 181 { 182 char buf[81]; 183 int rv, srv; 184 185 while ((rv = recv(s, buf, sizeof(buf), 0)) != 0 && !rk_IS_SOCKET_ERROR(rv)) { 186 buf[rv] = 0; 187 fprintf(stderr, "[%s] Received [%s]\n", prog, buf); 188 189 /* simple echo */ 190 srv = send(s, buf, rv, 0); 191 if (srv != rv) { 192 if (rk_IS_SOCKET_ERROR(srv)) 193 fprintf(stderr, "[%s] send() error [%s]\n", 194 getprogname(), strerror(rk_SOCK_ERRNO)); 195 else 196 fprintf(stderr, "[%s] send() size mismatch %d != %d", 197 getprogname(), srv, rv); 198 } 199 200 if (!strcmp(buf, "exit")) { 201 fprintf(stderr, "[%s] Exiting...\n", prog); 202 shutdown(s, SD_SEND); 203 rk_closesocket(s); 204 return 0; 205 } 206 } 207 208 fprintf(stderr, "[%s] recv() failed (%s)\n", 209 getprogname(), 210 strerror(rk_SOCK_ERRNO)); 211 } 212 213 rk_closesocket(s); 214 } 215 216 return 1; 217} 218 219static int 220test_simple_echo(void) 221{ 222 fprintf (stderr, "[%s] Starting echo test\n", prog); 223 224 if (is_client) { 225 226 return test_simple_echo_client(); 227 228 } else { 229 230 fprintf (stderr, "[%s] Listening for connections...\n", prog); 231 mini_inetd(htons(PORT), NULL); 232 fprintf (stderr, "[%s] Connected\n", prog); 233 234 { 235 char buf[81]; 236 while (gets(buf)) { 237 fprintf(stderr, "[%s] Received [%s]\n", prog, buf); 238 239 if (!strcmp(buf, "exit")) 240 return 0; 241 242 /* simple echo */ 243 puts(buf); 244 } 245 246 fprintf(stderr, "[%s] gets() failed (%s)\n", prog, _strerror("gets")); 247 } 248 } 249 250 return 1; 251} 252 253static int 254do_client(void) 255{ 256 int rv = 0; 257 258 rk_SOCK_INIT(); 259 260 prog = "Client"; 261 is_client = 1; 262 263 fprintf(stderr, "Starting client...\n"); 264 265 rv = test_simple_echo_socket(); 266 267 rk_SOCK_EXIT(); 268 269 return rv; 270} 271 272static int 273do_server(void) 274{ 275 int rv = 0; 276 277 rk_SOCK_INIT(); 278 279 prog = "Server"; 280 281 fprintf(stderr, "Starting server...\n"); 282 283 rv = test_simple_echo_socket(); 284 285 rk_SOCK_EXIT(); 286 287 return rv; 288} 289 290static time_t 291wait_callback(void *p) 292{ 293 return (time_t)-1; 294} 295 296static int 297do_test(char * path) 298{ 299 intptr_t p_server; 300 intptr_t p_client; 301 int client_rv; 302 int server_rv; 303 304 p_server = _spawnl(_P_NOWAIT, path, path, "--server", NULL); 305 if (p_server <= 0) { 306 fprintf(stderr, "%s: %s", path, _strerror("Can't start server process")); 307 return 1; 308 } 309#ifdef _WIN32 310 /* On Windows, the _spawn*() functions return a process handle on 311 success. We need a process ID for use with 312 wait_for_process_timed(). */ 313 314 p_server = GetProcessId((HANDLE) p_server); 315#endif 316 fprintf(stderr, "Created server process ID %d\n", p_server); 317 318 p_client = _spawnl(_P_NOWAIT, path, path, "--client", NULL); 319 if (p_client <= 0) { 320 fprintf(stderr, "%s: %s", path, _strerror("Can't start client process")); 321 fprintf(stderr, "Waiting for server process to terminate ..."); 322 wait_for_process_timed(p_server, wait_callback, NULL, 5); 323 fprintf(stderr, "DONE\n"); 324 return 1; 325 } 326#ifdef _WIN32 327 p_client = GetProcessId((HANDLE) p_client); 328#endif 329 fprintf(stderr, "Created client process ID %d\n", p_client); 330 331 fprintf(stderr, "Waiting for client process to terminate ..."); 332 client_rv = wait_for_process_timed(p_client, wait_callback, NULL, 5); 333 if (SE_IS_ERROR(client_rv)) { 334 fprintf(stderr, "\nwait_for_process_timed() failed for client. rv=%d\n", client_rv); 335 } else { 336 fprintf(stderr, "DONE\n"); 337 } 338 339 fprintf(stderr, "Waiting for server process to terminate ..."); 340 server_rv = wait_for_process_timed(p_server, wait_callback, NULL, 5); 341 if (SE_IS_ERROR(server_rv)) { 342 fprintf(stderr, "\nwait_for_process_timed() failed for server. rv=%d\n", server_rv); 343 } else { 344 fprintf(stderr, "DONE\n"); 345 } 346 347 if (client_rv == 0 && server_rv == 0) { 348 fprintf(stderr, "PASS\n"); 349 return 0; 350 } else { 351 fprintf(stderr, "FAIL: Client rv=%d, Server rv=%d\n", client_rv, server_rv); 352 return 1; 353 } 354} 355 356int main(int argc, char ** argv) 357{ 358 setprogname(argv[0]); 359 360 if (argc == 2 && strcmp(argv[1], "--client") == 0) 361 return do_client(); 362 else if (argc == 2 && strcmp(argv[1], "--server") == 0) 363 return do_server(); 364 else if (argc == 1) 365 return do_test(argv[0]); 366 else { 367 printf ("%s: Test mini_inetd() function. Run with no arguments to start test\n", 368 argv[0]); 369 return 1; 370 } 371} 372