1 /***********************************************************************
2 * Copyright (c) 2009, Secure Endpoints Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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 **********************************************************************/
41 char * prog
= "Master";
45 get_address(int flags
, struct addrinfo
** ret
)
50 memset(&ai
, 0, sizeof(ai
));
52 ai
.ai_flags
= flags
| AI_NUMERICHOST
| AI_NUMERICSERV
;
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
);
59 warnx("getaddrinfo: %s", gai_strerror(rv
));
64 get_connected_socket(rk_socket_t
* s_ret
)
66 struct addrinfo
* ai
= NULL
;
68 rk_socket_t s
= rk_INVALID_SOCKET
;
70 rv
= get_address(0, &ai
);
74 s
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
75 if (rk_IS_BAD_SOCKET(s
)) {
80 rv
= connect(s
, ai
->ai_addr
, ai
->ai_addrlen
);
81 if (rk_IS_SOCKET_ERROR(rv
))
85 s
= rk_INVALID_SOCKET
;
89 if (!rk_IS_BAD_SOCKET(s
))
95 return (rv
) ? rk_SOCK_ERRNO
: 0;
98 const char * test_strings
[] = {
100 "01234566789012345689012345678901234567890123456789",
106 test_simple_echo_client(void)
108 rk_socket_t s
= rk_INVALID_SOCKET
;
113 fprintf(stderr
, "[%s] Getting connected socket...", getprogname());
114 rv
= get_connected_socket(&s
);
116 fprintf(stderr
, "\n[%s] get_connected_socket() failed (%s)\n",
117 getprogname(), strerror(rk_SOCK_ERRNO
));
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
));
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
));
141 fprintf (stderr
, "[%s] No data received\n", prog
);
146 if (rv
!= strlen(test_strings
[i
])) {
147 fprintf (stderr
, "[%s] Data length mismatch %d != %zu\n", prog
, rv
, strlen(test_strings
[i
]));
153 fprintf (stderr
, "[%s] Done\n", prog
);
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
);
165 return test_simple_echo_client();
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
));
176 fprintf (stderr
, "[%s] Connected\n", prog
);
183 while ((rv
= recv(s
, buf
, sizeof(buf
), 0)) != 0 && !rk_IS_SOCKET_ERROR(rv
)) {
185 fprintf(stderr
, "[%s] Received [%s]\n", prog
, buf
);
188 srv
= send(s
, buf
, rv
, 0);
190 if (rk_IS_SOCKET_ERROR(srv
))
191 fprintf(stderr
, "[%s] send() error [%s]\n",
192 getprogname(), strerror(rk_SOCK_ERRNO
));
194 fprintf(stderr
, "[%s] send() size mismatch %d != %d",
195 getprogname(), srv
, rv
);
198 if (strcmp(buf
, "exit") == 0) {
199 fprintf(stderr
, "[%s] Exiting...\n", prog
);
200 shutdown(s
, SD_SEND
);
206 fprintf(stderr
, "[%s] recv() failed (%s)\n",
208 strerror(rk_SOCK_ERRNO
));
218 test_simple_echo(void)
220 fprintf (stderr
, "[%s] Starting echo test\n", prog
);
224 return test_simple_echo_client();
228 fprintf (stderr
, "[%s] Listening for connections...\n", prog
);
229 mini_inetd(htons(PORT
), NULL
);
230 fprintf (stderr
, "[%s] Connected\n", prog
);
235 fprintf(stderr
, "[%s] Received [%s]\n", prog
, buf
);
237 if (strcmp(buf
, "exit") == 0)
244 fprintf(stderr
, "[%s] gets() failed (%s)\n", prog
, _strerror("gets"));
257 errx(1, "Failed to initialize sockets (%s)", strerror(rk_SOCK_ERRNO
));
262 fprintf(stderr
, "Starting client...\n");
264 rv
= test_simple_echo_socket();
277 errx(1, "Failed to initialize sockets (%s)", strerror(rk_SOCK_ERRNO
));
281 fprintf(stderr
, "Starting server...\n");
283 rv
= test_simple_echo_socket();
291 wait_callback(void *p
)
304 p_server
= _spawnl(_P_NOWAIT
, path
, path
, "--server", NULL
);
306 fprintf(stderr
, "%s: %s", path
, _strerror("Can't start server process"));
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(). */
314 p_server
= GetProcessId((HANDLE
) p_server
);
316 fprintf(stderr
, "Created server process ID %d\n", p_server
);
318 p_client
= _spawnl(_P_NOWAIT
, path
, path
, "--client", NULL
);
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");
327 p_client
= GetProcessId((HANDLE
) p_client
);
329 fprintf(stderr
, "Created client process ID %d\n", p_client
);
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
);
336 fprintf(stderr
, "DONE\n");
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
);
344 fprintf(stderr
, "DONE\n");
347 if (client_rv
== 0 && server_rv
== 0) {
348 fprintf(stderr
, "PASS\n");
351 fprintf(stderr
, "FAIL: Client rv=%d, Server rv=%d\n", client_rv
, server_rv
);
356 int main(int argc
, char ** argv
)
358 setprogname(argv
[0]);
360 if (argc
== 2 && strcmp(argv
[1], "--client") == 0)
362 else if (argc
== 2 && strcmp(argv
[1], "--server") == 0)
365 return do_test(argv
[0]);
367 printf ("%s: Test mini_inetd() function. Run with no arguments to start test\n",