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