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