]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/xnu_quick_test/socket_tests.c
xnu-1228.0.2.tar.gz
[apple/xnu.git] / tools / tests / xnu_quick_test / socket_tests.c
1 /*
2 * socket_tests.c
3 * xnu_quick_test
4 *
5 * Created by Jerry Cottingham on 4/12/05.
6 * Copyright 2005 Apple Computer Inc. All rights reserved.
7 *
8 */
9
10 #include "tests.h"
11 #include <poll.h>
12
13 extern char g_target_path[ PATH_MAX ];
14
15 /* **************************************************************************************************************
16 * Test accept, bind, connect, listen, socket, recvmsg, sendmsg, recvfrom, sendto, getpeername, getsockname
17 * system calls.
18 * WARNING - I don't do networking - this should get a good look from a networking stud.
19 * **************************************************************************************************************
20 */
21 int socket_tests( void * the_argp )
22 {
23 int my_err, my_status, my_len;
24 pid_t my_pid, my_wait_pid;
25 int my_socket_fd = -1;
26 int my_accepted_socket = -1;
27 char * my_parent_pathp = NULL;
28 char * my_child_pathp = NULL;
29 socklen_t my_accept_len;
30 struct sockaddr *my_sockaddr;
31 ssize_t my_result;
32 off_t my_current_offset;
33 char my_parent_socket_name[sizeof(struct sockaddr) + 64];
34 char my_child_socket_name[sizeof(struct sockaddr) + 64];
35 char my_accept_buffer[sizeof(struct sockaddr) + 64];
36
37 /* generate 2 names for binding to the sockets (one socket in the parent and one in the child) */
38 my_parent_pathp = (char *) malloc( 128 );
39 if ( my_parent_pathp == NULL ) {
40 printf( "malloc failed with error %d - \"%s\" \n", errno, strerror( errno) );
41 goto test_failed_exit;
42 }
43 my_child_pathp = (char *) malloc( 128 );
44 if ( my_child_pathp == NULL ) {
45 printf( "malloc failed with error %d - \"%s\" \n", errno, strerror( errno) );
46 goto test_failed_exit;
47 }
48
49 *my_parent_pathp = 0x00;
50 strcat( my_parent_pathp, "/tmp/" );
51
52 /* get a unique name for our testing */
53 my_err = create_random_name( my_parent_pathp, 0 );
54 if ( my_err != 0 ) {
55 goto test_failed_exit;
56 }
57 strcpy( my_child_pathp, my_parent_pathp );
58 strcat( my_parent_pathp, "p" ); /* append 'p' to mean "parent" */
59 strcat( my_child_pathp, "c" ); /* append 'c' to mean "child" */
60
61 memset( &my_parent_socket_name[0], 0, sizeof(my_parent_socket_name) );
62 memset( &my_child_socket_name[0], 0, sizeof(my_child_socket_name) );
63
64 /* use unique names we generated in /tmp/ */
65 my_sockaddr = (struct sockaddr *) &my_parent_socket_name[0];
66 my_len = sizeof(*my_sockaddr) - sizeof(my_sockaddr->sa_data) + strlen(my_parent_pathp);
67 my_sockaddr->sa_len = my_len;
68 my_sockaddr->sa_family = AF_UNIX;
69 strcpy( &my_sockaddr->sa_data[0], my_parent_pathp );
70
71 my_sockaddr = (struct sockaddr *) &my_child_socket_name[0];
72 my_len = sizeof(*my_sockaddr) - sizeof(my_sockaddr->sa_data) + strlen(my_child_pathp);
73 my_sockaddr->sa_len = my_len;
74 my_sockaddr->sa_family = AF_UNIX;
75 strcpy( &my_sockaddr->sa_data[0], my_child_pathp );
76
77 /* set up socket for parent side */
78 my_socket_fd = socket( AF_UNIX, SOCK_STREAM, 0 );
79 if ( my_socket_fd == -1 ) {
80 printf( "socket call in parent failed with error %d - \"%s\" \n", errno, strerror( errno) );
81 goto test_failed_exit;
82 }
83 my_sockaddr = (struct sockaddr *) &my_parent_socket_name[0];
84 my_err = bind( my_socket_fd, my_sockaddr, my_sockaddr->sa_len );
85 if ( my_err == -1 ) {
86 printf( "bind call in child failed with error %d - \"%s\" \n", errno, strerror( errno) );
87 goto test_failed_exit;
88 }
89
90 /* test getsockname */
91 my_sockaddr = (struct sockaddr *) &my_accept_buffer[0];
92 my_accept_len = sizeof(my_accept_buffer);
93 my_err = getsockname( my_socket_fd, my_sockaddr, &my_accept_len );
94 if ( my_err == -1 ) {
95 printf( "getsockname call in child failed with error %d - \"%s\" \n", errno, strerror( errno) );
96 goto test_failed_exit;
97 }
98 if ( my_sockaddr->sa_family != SOCK_STREAM ) {
99 printf( "getsockname test failed - did not get correct socket name data \n" );
100 goto test_failed_exit;
101 }
102
103 /* make sure we can't seek on a socket */
104 my_current_offset = lseek( my_socket_fd, 0, SEEK_CUR );
105 if ( my_current_offset != -1 ) {
106 printf( "lseek on socket should fail but did not \n" );
107 goto test_failed_exit;
108 }
109
110 /*
111 * spin off a child process that we communicate with via sockets.
112 */
113 my_pid = fork( );
114 if ( my_pid == -1 ) {
115 printf( "fork failed with errno %d - %s \n", errno, strerror( errno ) );
116 goto test_failed_exit;
117 }
118 if ( my_pid == 0 ) {
119 /*
120 * child process - open a socket and use it to talk to our parent.
121 */
122 int my_child_fd = -1;
123 struct msghdr my_msghdr;
124 struct iovec my_iov;
125 char my_buffer[128];
126
127 my_child_fd = socket( AF_UNIX, SOCK_STREAM, 0 );
128 if ( my_child_fd == -1 ) {
129 printf( "socket call in child failed with error %d - \"%s\" \n", errno, strerror( errno) );
130 exit( -1 );
131 }
132
133 my_sockaddr = (struct sockaddr *) &my_child_socket_name[0];
134 my_err = bind( my_child_fd, my_sockaddr, my_sockaddr->sa_len );
135 if ( my_err == -1 ) {
136 close( my_child_fd );
137 printf( "bind call in child failed with error %d - \"%s\" \n", errno, strerror( errno) );
138 exit( -1 );
139 }
140 sleep(2);
141
142 /* connect to socket in our parent */
143 my_sockaddr = (struct sockaddr *) &my_parent_socket_name[0];
144 my_err = connect( my_child_fd, my_sockaddr, my_sockaddr->sa_len );
145 if ( my_err == -1 ) {
146 close( my_child_fd );
147 printf( "connect call in child failed with error %d - \"%s\" \n", errno, strerror( errno) );
148 exit( -1 );
149 }
150
151 /* get some data from the child via socket and test socket peer data */
152 {
153 socklen_t my_buffer_len;
154 struct sockaddr * my_sockaddr;
155 char my_parent_buffer[256];
156
157 my_sockaddr = (struct sockaddr *) &my_parent_buffer[0];
158 my_buffer_len = sizeof(my_parent_buffer);
159 my_err = getpeername( my_child_fd, my_sockaddr, &my_buffer_len );
160 if ( my_err == -1 ) {
161 printf( "getpeername call in parent failed with error %d - \"%s\" \n", errno, strerror( errno) );
162 goto test_failed_exit;
163 }
164
165 /* test results - should be sa_family == SOCK_STREAM and name should match my_child_pathp */
166 if ( my_sockaddr->sa_family != SOCK_STREAM ) {
167 printf( "getpeername test failed - did not get correct peer data \n" );
168 goto test_failed_exit;
169 }
170 }
171
172 my_buffer[0] = 'j';
173 my_iov.iov_base = &my_buffer[0];
174 my_iov.iov_len = 1;
175
176 my_sockaddr = (struct sockaddr *) &my_parent_socket_name[0];
177 my_msghdr.msg_name = my_sockaddr;
178 my_msghdr.msg_namelen = my_sockaddr->sa_len;
179 my_msghdr.msg_iov = &my_iov;
180 my_msghdr.msg_iovlen = 1;
181 my_msghdr.msg_control = NULL;
182 my_msghdr.msg_controllen = 0;
183 my_msghdr.msg_flags = 0;
184
185 my_result = sendmsg( my_child_fd, &my_msghdr, 0 );
186 if ( my_result == -1 ) {
187 printf( "sendmsg failed with error %d - \"%s\" \n", errno, strerror( errno) );
188 close( my_child_fd );
189 exit( -1 );
190 }
191
192 #if 1
193 /* get data from our parent */
194 my_result = recvfrom( my_child_fd, &my_buffer[0], 1,
195 MSG_WAITALL, NULL, NULL );
196 if ( my_result == -1 ) {
197 printf( "recvfrom failed with error %d - \"%s\" \n", errno, strerror( errno) );
198 close( my_child_fd );
199 exit( -1 );
200 }
201
202 /* verify that we got the correct message from our child */
203 if ( my_buffer[0] != 'e' ) {
204 printf( "test failed - did not get correct data from child \n" );
205 close( my_child_fd );
206 exit( -1 );
207 }
208 #endif
209
210 /* tell parent we're done */
211 my_result = write( my_child_fd, "all done", 8 );
212 if ( my_result == -1 ) {
213 close( my_child_fd );
214 exit( -1 );
215 }
216
217 close( my_child_fd );
218 exit(0);
219 }
220
221 /*
222 * parent process - listen for connection requests
223 */
224 my_err = listen( my_socket_fd, 10 );
225 if ( my_err == -1 ) {
226 printf( "listen call in parent failed with error %d - \"%s\" \n", errno, strerror( errno) );
227 goto test_failed_exit;
228 }
229
230 /* accept connection from child */
231 my_sockaddr = (struct sockaddr *) &my_accept_buffer[0];
232 my_accepted_socket = accept( my_socket_fd, my_sockaddr, &my_accept_len );
233 if ( my_accepted_socket == -1 ) {
234 printf( "accept call in parent failed with error %d - \"%s\" \n", errno, strerror( errno) );
235 goto test_failed_exit;
236 }
237
238 /* get some data from the child via socket and test socket peer data */
239 {
240 //socklen_t my_buffer_len;
241 struct msghdr my_msghdr;
242 struct iovec my_iov;
243 char my_parent_buffer[128];
244
245 my_parent_buffer[0] = 'x';
246 my_iov.iov_base = &my_parent_buffer[0];
247 my_iov.iov_len = 1;
248
249 my_msghdr.msg_name = &my_accept_buffer[0];
250 my_msghdr.msg_namelen = my_accept_len;
251 my_msghdr.msg_iov = &my_iov;
252 my_msghdr.msg_iovlen = 1;
253 my_msghdr.msg_control = NULL;
254 my_msghdr.msg_controllen = 0;
255 my_msghdr.msg_flags = 0;
256
257 my_result = recvmsg( my_accepted_socket, &my_msghdr, MSG_WAITALL );
258 if ( my_result == -1 ) {
259 printf( "recvmsg failed with error %d - \"%s\" \n", errno, strerror( errno) );
260 goto test_failed_exit;
261 }
262
263 /* verify that we got the correct message from our child */
264 if ( my_parent_buffer[0] != 'j' ) {
265 printf( "test failed - did not get correct data from child \n" );
266 goto test_failed_exit;
267 }
268
269 #if 1
270 /* now send some data to our child */
271 my_parent_buffer[0] = 'e';
272 my_sockaddr = (struct sockaddr *) &my_child_socket_name[0];
273 my_result = sendto( my_accepted_socket, &my_parent_buffer[0], 1, 0, my_sockaddr,
274 my_sockaddr->sa_len );
275 if ( my_result == -1 ) {
276 printf( "sendto failed with error %d - \"%s\" \n", errno, strerror( errno) );
277 goto test_failed_exit;
278 }
279 #endif
280
281 /* see if child is done */
282 bzero( (void *)&my_parent_buffer[0], sizeof(my_parent_buffer) );
283 my_result = read( my_accepted_socket, &my_parent_buffer[0], sizeof(my_parent_buffer) );
284 if ( my_result == -1 ) {
285 printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) );
286 goto test_failed_exit;
287 }
288 if ( strcmp( "all done", &my_parent_buffer[0] ) != 0 ) {
289 printf( "read wrong message from child \n" );
290 goto test_failed_exit;
291 }
292 }
293
294 /* wait for child to exit */
295 my_wait_pid = wait4( my_pid, &my_status, 0, NULL );
296 if ( my_wait_pid == -1 ) {
297 printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) );
298 goto test_failed_exit;
299 }
300
301 if ( WIFEXITED( my_status ) && WEXITSTATUS( my_status ) != 0 ) {
302 goto test_failed_exit;
303 }
304
305 my_err = 0;
306 goto test_passed_exit;
307
308 test_failed_exit:
309 my_err = -1;
310
311 test_passed_exit:
312 if ( my_socket_fd != -1 )
313 close( my_socket_fd );
314 if ( my_accepted_socket != -1 )
315 close( my_accepted_socket );
316 if ( my_parent_pathp != NULL ) {
317 remove( my_parent_pathp );
318 free( my_parent_pathp );
319 }
320 if ( my_child_pathp != NULL ) {
321 remove( my_child_pathp );
322 free( my_child_pathp );
323 }
324 return( my_err );
325 }
326
327 /* **************************************************************************************************************
328 * Test fsync, getsockopt, poll, select, setsockopt, socketpair system calls.
329 * **************************************************************************************************************
330 */
331 int socket2_tests( void * the_argp )
332 {
333 int my_err, my_status;
334 int my_sockets[ 2 ] = {-1, -1};
335 pid_t my_pid, my_wait_pid;
336 ssize_t my_count;
337 socklen_t my_socklen;
338 struct timeval * my_tvp;
339 struct timeval my_orig_tv;
340 char my_buffer[ 32 ];
341
342 my_err = socketpair( AF_UNIX, SOCK_STREAM, 0, &my_sockets[0] );
343 if ( my_err == -1 ) {
344 printf( "socketpair failed with errno %d - %s \n", errno, strerror( errno ) );
345 goto test_failed_exit;
346 }
347
348 /* test getsockopt and setsockopt */
349 my_socklen = sizeof( my_buffer );
350 my_err = getsockopt( my_sockets[0], SOL_SOCKET, SO_TYPE, &my_buffer[0], &my_socklen);
351 if ( my_err == -1 ) {
352 printf( "getsockopt - SO_TYPE - failed with errno %d - %s \n", errno, strerror( errno ) );
353 goto test_failed_exit;
354 }
355 if ( SOCK_STREAM != *((int *)&my_buffer[0]) ) {
356 printf( "getsockopt returned incorrect socket type \n" );
357 goto test_failed_exit;
358 }
359
360 /* get and set receive timeout */
361 my_socklen = sizeof( my_buffer );
362 my_err = getsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_buffer[0], &my_socklen);
363 if ( my_err == -1 ) {
364 printf( "getsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) );
365 goto test_failed_exit;
366 }
367 my_tvp = (struct timeval *) &my_buffer[0];
368 my_orig_tv.tv_sec = my_tvp->tv_sec;
369 my_orig_tv.tv_usec = my_tvp->tv_usec;
370
371 my_tvp->tv_sec += 60;
372 my_err = setsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_buffer[0], sizeof(struct timeval) );
373 if ( my_err == -1 ) {
374 printf( "setsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) );
375 goto test_failed_exit;
376 }
377
378 /* verify we set it */
379 my_socklen = sizeof( my_buffer );
380 my_err = getsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_buffer[0], &my_socklen);
381 if ( my_err == -1 ) {
382 printf( "getsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) );
383 goto test_failed_exit;
384 }
385 my_tvp = (struct timeval *) &my_buffer[0];
386 if ( my_tvp->tv_sec != (my_orig_tv.tv_sec + 60) || my_tvp->tv_usec != my_orig_tv.tv_usec ) {
387 printf( "setsockopt - SO_RCVTIMEO - did not set correct timeval \n" );
388 goto test_failed_exit;
389 }
390
391 /* set back to original receive timeout */
392 my_err = setsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_orig_tv, sizeof(struct timeval) );
393 if ( my_err == -1 ) {
394 printf( "setsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) );
395 goto test_failed_exit;
396 }
397
398 /* test fsync - should fail when used with a socket fd */
399 errno = 0;
400 my_err = fsync( my_sockets[0] );
401 if ( my_err == -1 && errno != ENOTSUP ) {
402 printf( "fsync failed with errno %d - %s \n", errno, strerror( errno ) );
403 goto test_failed_exit;
404 }
405 else if ( my_err != -1 ) {
406 printf( "fsync should have failed with errno ENOTSUP \n" );
407 goto test_failed_exit;
408 }
409
410 /*
411 * spin off a child process that we will talk to via our socketpair.
412 */
413 my_pid = fork( );
414 if ( my_pid == -1 ) {
415 printf( "fork failed with errno %d - %s \n", errno, strerror( errno ) );
416 goto test_failed_exit;
417 }
418 if ( my_pid == 0 ) {
419 /*
420 * child process - tell parent we are ready to go.
421 */
422 char my_buffer[ 32 ];
423 struct pollfd my_pollfd;
424
425 my_count = write( my_sockets[1], "r", 1 );
426 if ( my_count == -1 ) {
427 printf( "write call failed. got errno %d - %s. \n", errno, strerror( errno ) );
428 exit( -1 );
429 }
430
431 /* test select by using it to wait for message from parent */
432 for ( ;; ) {
433 fd_set my_read_set;
434 struct timeval my_timeout;
435
436 FD_ZERO( &my_read_set );
437 FD_SET( my_sockets[1], &my_read_set );
438 timerclear( &my_timeout );
439 my_timeout.tv_sec = 1;
440
441 /* check to see if we are done, if no message is ready after a second
442 * return and try again...
443 */
444 my_err = select( (my_sockets[1] + 1), &my_read_set, NULL, NULL, &my_timeout );
445 if ( my_err == -1 ) {
446 printf( "select call failed with error %d - \"%s\" \n", errno, strerror( errno) );
447 exit( -1 );
448 }
449 else if ( my_err > 0 ) {
450 /* we're done */
451 break;
452 }
453 }
454
455 /* test poll too */
456 my_pollfd.fd = my_sockets[1];
457 my_pollfd.events = (POLLIN | POLLPRI);
458 my_pollfd.revents = 0;
459 my_err = poll( &my_pollfd, 1, 500 );
460 if ( my_err == -1 ) {
461 printf( "poll call failed with error %d - \"%s\" \n", errno, strerror( errno) );
462 exit( -1 );
463 }
464 /* should be ready for read */
465 if ( (my_pollfd.revents & POLLIN) == 0 ) {
466 printf( "poll should have returned ready for read \n" );
467 exit( -1 );
468 }
469
470 my_count = read( my_sockets[1], &my_buffer[0], sizeof(my_buffer) );
471 if ( my_count == -1 ) {
472 printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) );
473 exit( -1 );
474 }
475 if ( my_buffer[0] != 'd' ) {
476 printf( "read call on socket failed to get \"all done\" message \n" );
477 exit( -1 );
478 }
479
480 exit(0);
481 }
482
483 /*
484 * parent process - wait for child to spin up
485 */
486 my_count = read( my_sockets[0], &my_buffer[0], sizeof(my_buffer) );
487 if ( my_count == -1 ) {
488 printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) );
489 goto test_failed_exit;
490 }
491 if ( my_buffer[0] != 'r' ) {
492 printf( "read call on socket failed to get \"ready to go message\" \n" );
493 goto test_failed_exit;
494 }
495
496 /* tell child we're done */
497 write( my_sockets[0], "d", 1 );
498
499 my_wait_pid = wait4( my_pid, &my_status, 0, NULL );
500 if ( my_wait_pid == -1 ) {
501 printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) );
502 goto test_failed_exit;
503 }
504
505 /* wait4 should return our child's pid when it exits */
506 if ( my_wait_pid != my_pid ) {
507 printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid );
508 goto test_failed_exit;
509 }
510
511 if ( WIFEXITED( my_status ) && WEXITSTATUS( my_status ) != 0 ) {
512 printf( "wait4 returned wrong exit status - 0x%02X \n", my_status );
513 goto test_failed_exit;
514 }
515
516 my_err = 0;
517 goto test_passed_exit;
518
519 test_failed_exit:
520 my_err = -1;
521
522 test_passed_exit:
523 if ( my_sockets[0] != -1 )
524 close( my_sockets[0] );
525 if ( my_sockets[1] != -1 )
526 close( my_sockets[1] );
527 return( my_err );
528 }
529