1 /* $NetBSD: test_server.c,v 1.2 2021/09/01 06:12:50 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by James Browning, Gabe Coffland, Alex Gavin, and Solomon Ritzow. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: test_server.c,v 1.2 2021/09/01 06:12:50 christos Exp $"); 34 35 #include <sys/socket.h> 36 #include <unistd.h> 37 #include <netdb.h> 38 #include <stdint.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <errno.h> 42 #include <stdlib.h> 43 #include <syslog.h> 44 45 #define CHECK(expr) do {\ 46 if ((expr) == -1) {\ 47 syslog(LOG_ERR, "Error at %s:%d: %s", \ 48 __FILE__, __LINE__, \ 49 strerror(errno));\ 50 exit(EXIT_FAILURE);\ 51 }\ 52 } while(0); 53 54 static void stream_nowait_service(void); 55 static void stream_wait_service(void); 56 static void dgram_wait_service(void); 57 58 int 59 main(int argc, char **argv) 60 { 61 62 openlog("inetd_test_server", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 63 64 if (argc < 3) { 65 syslog(LOG_ERR, "Invalid arg count"); 66 exit(EXIT_FAILURE); 67 } 68 69 /* Run the correct service according to the args */ 70 if (strcmp(argv[1], "dgram") == 0) { 71 if (strcmp(argv[2], "wait") == 0) { 72 dgram_wait_service(); 73 } else { 74 syslog(LOG_ERR, "Invalid arg %s", argv[2]); 75 exit(EXIT_FAILURE); 76 } 77 } else if (strcmp(argv[1], "stream") == 0) { 78 if (strcmp(argv[2], "wait") == 0) { 79 stream_wait_service(); 80 } else if (strcmp(argv[2], "nowait") == 0) { 81 stream_nowait_service(); 82 } else { 83 syslog(LOG_ERR, "Invalid arg %s", argv[2]); 84 exit(EXIT_FAILURE); 85 } 86 } else { 87 syslog(LOG_ERR, "Invalid args %s %s", argv[1], argv[2]); 88 exit(EXIT_FAILURE); 89 } 90 return 0; 91 } 92 93 static void 94 stream_nowait_service(void) 95 { 96 ssize_t count; 97 char buffer[10]; 98 CHECK(count = recv(0, buffer, sizeof(buffer), 0)); 99 syslog(LOG_WARNING, "Received stream/nowait message \"%.*s\"\n", 100 (int)count, buffer); 101 CHECK(send(1, buffer, (size_t)count, 0)); 102 } 103 104 static void 105 stream_wait_service(void) 106 { 107 struct sockaddr_storage addr; 108 ssize_t count; 109 int fd; 110 socklen_t addr_len; 111 char buffer[10]; 112 113 CHECK(fd = accept(0, (struct sockaddr*)&addr, &addr_len)); 114 CHECK(count = recv(fd, buffer, sizeof(buffer), 0)); 115 syslog(LOG_WARNING, "Received stream/wait message \"%.*s\"\n", 116 (int)count, buffer); 117 CHECK(send(fd, buffer, (size_t)count, 0)); 118 CHECK(shutdown(fd, SHUT_RDWR)); 119 CHECK(close(fd)); 120 } 121 122 static void 123 dgram_wait_service(void) 124 { 125 char buffer[256]; 126 char name[NI_MAXHOST]; 127 struct sockaddr_storage addr; 128 129 struct iovec store = { 130 .iov_base = &buffer, 131 .iov_len = sizeof(buffer) 132 }; 133 struct msghdr header = { 134 .msg_name = &addr, 135 .msg_namelen = sizeof(struct sockaddr_storage), 136 .msg_iov = &store, 137 .msg_iovlen = 1 138 /* scatter/gather and control info is null */ 139 }; 140 ssize_t count; 141 142 /* Peek so service can still get the packet */ 143 CHECK(count = recvmsg(0, &header, 0)); 144 145 CHECK(sendto(1, buffer, (size_t)count, 0, 146 (struct sockaddr*)(&addr), addr.ss_len)); 147 148 int error = getnameinfo((struct sockaddr*)&addr, 149 addr.ss_len, name, NI_MAXHOST, 150 NULL, 0, NI_NUMERICHOST); 151 152 if (error) { 153 syslog(LOG_ERR, "getnameinfo error: %s\n", gai_strerror(error)); 154 exit(EXIT_FAILURE); 155 } 156 syslog(LOG_WARNING, "Received dgram/wait message \"%.*s\" from %s\n", 157 (int)count, buffer, name); 158 } 159