1 /* $NetBSD: test-mini_inetd.c,v 1.2 2017/01/28 21:31:50 christos 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
43 char * prog = "Master";
44 int is_client = 0;
45
46 static int
get_address(int flags,struct addrinfo ** ret)47 get_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
65 static int
get_connected_socket(rk_socket_t * s_ret)66 get_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
100 const char * test_strings[] = {
101 "Hello",
102 "01234566789012345689012345678901234567890123456789",
103 "Another test",
104 "exit"
105 };
106
107 static int
test_simple_echo_client(void)108 test_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
160 static int
test_simple_echo_socket(void)161 test_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
219 static int
test_simple_echo(void)220 test_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
253 static int
do_client(void)254 do_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
272 static int
do_server(void)273 do_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
290 static time_t
wait_callback(void * p)291 wait_callback(void *p)
292 {
293 return (time_t)-1;
294 }
295
296 static int
do_test(char * path)297 do_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
main(int argc,char ** argv)356 int 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