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