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 
43 char * prog = "Master";
44 int is_client = 0;
45 
46 static int
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
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
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
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
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
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
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
291 wait_callback(void *p)
292 {
293     return (time_t)-1;
294 }
295 
296 static int
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 
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