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