]>
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 | 213 | /* sendfile test. Open libsystem, set up some headers, and send it */ |
6d2010ae A |
214 | struct sf_hdtr my_sf_hdtr; |
215 | int my_libsys_fd; | |
216 | off_t my_libsys_len; | |
217 | ||
218 | my_libsys_fd = open("/usr/lib/libSystem.dylib", O_RDONLY, 0644); | |
219 | if (my_libsys_fd < 0) { | |
220 | printf( "test failed - could not open /usr/lib/libSystem.dylib\n" ); | |
221 | close ( my_child_fd ); | |
222 | exit ( -1 ); | |
223 | } | |
b0d623f7 | 224 | |
6d2010ae A |
225 | my_libsys_len = 7+2; /* 2 bytes of header */ |
226 | my_buffer[0] = 's'; | |
227 | my_iov[0].iov_base = &my_buffer[0]; | |
228 | my_iov[0].iov_len = 1; | |
229 | my_buffer[1] = 'e'; | |
230 | my_iov[1].iov_base = &my_buffer[1]; | |
231 | my_iov[1].iov_len = 1; | |
232 | my_buffer[2] = 'n'; | |
233 | my_iov[2].iov_base = &my_buffer[2]; | |
234 | my_iov[2].iov_len = 1; | |
235 | my_buffer[3] = 'd'; | |
236 | my_iov[3].iov_base = &my_buffer[3]; | |
237 | my_iov[3].iov_len = 1; | |
238 | ||
239 | my_sf_hdtr.headers = &my_iov[0]; | |
240 | my_sf_hdtr.hdr_cnt = 2; | |
241 | my_sf_hdtr.trailers = &my_iov[2]; | |
242 | my_sf_hdtr.trl_cnt = 2; | |
b0d623f7 | 243 | |
6d2010ae A |
244 | my_result = sendfile(my_libsys_fd, my_child_fd, 3, &my_libsys_len, &my_sf_hdtr, 0); |
245 | if (my_result < 0 || my_libsys_len != 11) { | |
246 | printf( "sendfile failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
247 | close( my_child_fd ); | |
248 | exit( -1 ); | |
249 | } | |
b0d623f7 | 250 | |
6d2010ae A |
251 | my_result = close ( my_libsys_fd ); |
252 | if ( my_libsys_fd < 0 ) { | |
253 | printf ( "close failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
254 | close ( my_child_fd ); | |
255 | exit ( -1 ); | |
256 | } | |
b0d623f7 | 257 | |
2d21ac55 A |
258 | /* tell parent we're done */ |
259 | my_result = write( my_child_fd, "all done", 8 ); | |
260 | if ( my_result == -1 ) { | |
261 | close( my_child_fd ); | |
262 | exit( -1 ); | |
263 | } | |
264 | ||
265 | close( my_child_fd ); | |
266 | exit(0); | |
267 | } | |
268 | ||
269 | /* | |
270 | * parent process - listen for connection requests | |
271 | */ | |
272 | my_err = listen( my_socket_fd, 10 ); | |
273 | if ( my_err == -1 ) { | |
274 | printf( "listen call in parent failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
275 | goto test_failed_exit; | |
276 | } | |
277 | ||
278 | /* accept connection from child */ | |
279 | my_sockaddr = (struct sockaddr *) &my_accept_buffer[0]; | |
280 | my_accepted_socket = accept( my_socket_fd, my_sockaddr, &my_accept_len ); | |
281 | if ( my_accepted_socket == -1 ) { | |
282 | printf( "accept call in parent failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
283 | goto test_failed_exit; | |
284 | } | |
285 | ||
286 | /* get some data from the child via socket and test socket peer data */ | |
287 | { | |
288 | //socklen_t my_buffer_len; | |
289 | struct msghdr my_msghdr; | |
290 | struct iovec my_iov; | |
291 | char my_parent_buffer[128]; | |
292 | ||
293 | my_parent_buffer[0] = 'x'; | |
294 | my_iov.iov_base = &my_parent_buffer[0]; | |
295 | my_iov.iov_len = 1; | |
296 | ||
297 | my_msghdr.msg_name = &my_accept_buffer[0]; | |
298 | my_msghdr.msg_namelen = my_accept_len; | |
299 | my_msghdr.msg_iov = &my_iov; | |
300 | my_msghdr.msg_iovlen = 1; | |
301 | my_msghdr.msg_control = NULL; | |
302 | my_msghdr.msg_controllen = 0; | |
303 | my_msghdr.msg_flags = 0; | |
304 | ||
305 | my_result = recvmsg( my_accepted_socket, &my_msghdr, MSG_WAITALL ); | |
306 | if ( my_result == -1 ) { | |
307 | printf( "recvmsg failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
308 | goto test_failed_exit; | |
309 | } | |
310 | ||
311 | /* verify that we got the correct message from our child */ | |
312 | if ( my_parent_buffer[0] != 'j' ) { | |
313 | printf( "test failed - did not get correct data from child \n" ); | |
314 | goto test_failed_exit; | |
315 | } | |
316 | ||
317 | #if 1 | |
318 | /* now send some data to our child */ | |
319 | my_parent_buffer[0] = 'e'; | |
320 | my_sockaddr = (struct sockaddr *) &my_child_socket_name[0]; | |
321 | my_result = sendto( my_accepted_socket, &my_parent_buffer[0], 1, 0, my_sockaddr, | |
322 | my_sockaddr->sa_len ); | |
323 | if ( my_result == -1 ) { | |
324 | printf( "sendto failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
325 | goto test_failed_exit; | |
326 | } | |
327 | #endif | |
328 | ||
6d2010ae | 329 | size_t neededBytes = 11; |
b0d623f7 | 330 | |
6d2010ae A |
331 | /* Check for sendfile output */ |
332 | bzero( (void *)&my_parent_buffer[0], sizeof(my_parent_buffer) ); | |
333 | while (neededBytes > 0) { | |
334 | my_result = read( my_accepted_socket, &my_parent_buffer[11-neededBytes], neededBytes ); | |
335 | if ( my_result == -1 ) { | |
336 | printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
b0d623f7 | 337 | goto test_failed_exit; |
6d2010ae A |
338 | } else if (my_result == 0) { |
339 | break; | |
b0d623f7 | 340 | } |
6d2010ae A |
341 | neededBytes -= my_result; |
342 | } | |
343 | ||
344 | if ( neededBytes > 0 ) { | |
345 | printf( "read call returned %ld bytes instead of 11\n", 11 - neededBytes ); | |
346 | goto test_failed_exit; | |
347 | } | |
b0d623f7 | 348 | |
6d2010ae A |
349 | if ( ! (my_parent_buffer[0] == 's' && my_parent_buffer[1] == 'e' && my_parent_buffer[9] == 'n' && my_parent_buffer[10] == 'd') ) { |
350 | printf( "read wrong sendfile message from child \n" ); | |
351 | goto test_failed_exit; | |
b0d623f7 A |
352 | } |
353 | ||
b0d623f7 A |
354 | |
355 | /* see if child is done. bzero so that string is NUL terminated */ | |
2d21ac55 A |
356 | bzero( (void *)&my_parent_buffer[0], sizeof(my_parent_buffer) ); |
357 | my_result = read( my_accepted_socket, &my_parent_buffer[0], sizeof(my_parent_buffer) ); | |
358 | if ( my_result == -1 ) { | |
359 | printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
360 | goto test_failed_exit; | |
361 | } | |
362 | if ( strcmp( "all done", &my_parent_buffer[0] ) != 0 ) { | |
363 | printf( "read wrong message from child \n" ); | |
364 | goto test_failed_exit; | |
365 | } | |
366 | } | |
367 | ||
368 | /* wait for child to exit */ | |
369 | my_wait_pid = wait4( my_pid, &my_status, 0, NULL ); | |
370 | if ( my_wait_pid == -1 ) { | |
371 | printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) ); | |
372 | goto test_failed_exit; | |
373 | } | |
374 | ||
375 | if ( WIFEXITED( my_status ) && WEXITSTATUS( my_status ) != 0 ) { | |
376 | goto test_failed_exit; | |
377 | } | |
378 | ||
379 | my_err = 0; | |
380 | goto test_passed_exit; | |
381 | ||
382 | test_failed_exit: | |
383 | my_err = -1; | |
384 | ||
385 | test_passed_exit: | |
386 | if ( my_socket_fd != -1 ) | |
387 | close( my_socket_fd ); | |
388 | if ( my_accepted_socket != -1 ) | |
389 | close( my_accepted_socket ); | |
390 | if ( my_parent_pathp != NULL ) { | |
391 | remove( my_parent_pathp ); | |
b0d623f7 | 392 | vm_deallocate(mach_task_self(), (vm_address_t)my_parent_pathp, 128); |
2d21ac55 A |
393 | } |
394 | if ( my_child_pathp != NULL ) { | |
395 | remove( my_child_pathp ); | |
b0d623f7 | 396 | vm_deallocate(mach_task_self(), (vm_address_t)my_child_pathp, 128); |
2d21ac55 A |
397 | } |
398 | return( my_err ); | |
399 | } | |
400 | ||
401 | /* ************************************************************************************************************** | |
402 | * Test fsync, getsockopt, poll, select, setsockopt, socketpair system calls. | |
403 | * ************************************************************************************************************** | |
404 | */ | |
405 | int socket2_tests( void * the_argp ) | |
406 | { | |
407 | int my_err, my_status; | |
408 | int my_sockets[ 2 ] = {-1, -1}; | |
409 | pid_t my_pid, my_wait_pid; | |
410 | ssize_t my_count; | |
411 | socklen_t my_socklen; | |
412 | struct timeval * my_tvp; | |
413 | struct timeval my_orig_tv; | |
414 | char my_buffer[ 32 ]; | |
415 | ||
416 | my_err = socketpair( AF_UNIX, SOCK_STREAM, 0, &my_sockets[0] ); | |
417 | if ( my_err == -1 ) { | |
418 | printf( "socketpair failed with errno %d - %s \n", errno, strerror( errno ) ); | |
419 | goto test_failed_exit; | |
420 | } | |
421 | ||
422 | /* test getsockopt and setsockopt */ | |
423 | my_socklen = sizeof( my_buffer ); | |
424 | my_err = getsockopt( my_sockets[0], SOL_SOCKET, SO_TYPE, &my_buffer[0], &my_socklen); | |
425 | if ( my_err == -1 ) { | |
426 | printf( "getsockopt - SO_TYPE - failed with errno %d - %s \n", errno, strerror( errno ) ); | |
427 | goto test_failed_exit; | |
428 | } | |
429 | if ( SOCK_STREAM != *((int *)&my_buffer[0]) ) { | |
430 | printf( "getsockopt returned incorrect socket type \n" ); | |
431 | goto test_failed_exit; | |
432 | } | |
433 | ||
434 | /* get and set receive timeout */ | |
435 | my_socklen = sizeof( my_buffer ); | |
436 | my_err = getsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_buffer[0], &my_socklen); | |
437 | if ( my_err == -1 ) { | |
438 | printf( "getsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) ); | |
439 | goto test_failed_exit; | |
440 | } | |
441 | my_tvp = (struct timeval *) &my_buffer[0]; | |
442 | my_orig_tv.tv_sec = my_tvp->tv_sec; | |
443 | my_orig_tv.tv_usec = my_tvp->tv_usec; | |
444 | ||
445 | my_tvp->tv_sec += 60; | |
446 | my_err = setsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_buffer[0], sizeof(struct timeval) ); | |
447 | if ( my_err == -1 ) { | |
448 | printf( "setsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) ); | |
449 | goto test_failed_exit; | |
450 | } | |
451 | ||
452 | /* verify we set it */ | |
453 | my_socklen = sizeof( my_buffer ); | |
454 | my_err = getsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_buffer[0], &my_socklen); | |
455 | if ( my_err == -1 ) { | |
456 | printf( "getsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) ); | |
457 | goto test_failed_exit; | |
458 | } | |
459 | my_tvp = (struct timeval *) &my_buffer[0]; | |
460 | if ( my_tvp->tv_sec != (my_orig_tv.tv_sec + 60) || my_tvp->tv_usec != my_orig_tv.tv_usec ) { | |
461 | printf( "setsockopt - SO_RCVTIMEO - did not set correct timeval \n" ); | |
462 | goto test_failed_exit; | |
463 | } | |
464 | ||
465 | /* set back to original receive timeout */ | |
466 | my_err = setsockopt( my_sockets[0], SOL_SOCKET, SO_RCVTIMEO, &my_orig_tv, sizeof(struct timeval) ); | |
467 | if ( my_err == -1 ) { | |
468 | printf( "setsockopt - SO_RCVTIMEO - failed with errno %d - %s \n", errno, strerror( errno ) ); | |
469 | goto test_failed_exit; | |
470 | } | |
471 | ||
472 | /* test fsync - should fail when used with a socket fd */ | |
473 | errno = 0; | |
474 | my_err = fsync( my_sockets[0] ); | |
475 | if ( my_err == -1 && errno != ENOTSUP ) { | |
476 | printf( "fsync failed with errno %d - %s \n", errno, strerror( errno ) ); | |
477 | goto test_failed_exit; | |
478 | } | |
479 | else if ( my_err != -1 ) { | |
480 | printf( "fsync should have failed with errno ENOTSUP \n" ); | |
481 | goto test_failed_exit; | |
482 | } | |
483 | ||
484 | /* | |
485 | * spin off a child process that we will talk to via our socketpair. | |
486 | */ | |
487 | my_pid = fork( ); | |
488 | if ( my_pid == -1 ) { | |
489 | printf( "fork failed with errno %d - %s \n", errno, strerror( errno ) ); | |
490 | goto test_failed_exit; | |
491 | } | |
492 | if ( my_pid == 0 ) { | |
493 | /* | |
494 | * child process - tell parent we are ready to go. | |
495 | */ | |
496 | char my_buffer[ 32 ]; | |
497 | struct pollfd my_pollfd; | |
498 | ||
499 | my_count = write( my_sockets[1], "r", 1 ); | |
500 | if ( my_count == -1 ) { | |
501 | printf( "write call failed. got errno %d - %s. \n", errno, strerror( errno ) ); | |
502 | exit( -1 ); | |
503 | } | |
504 | ||
505 | /* test select by using it to wait for message from parent */ | |
506 | for ( ;; ) { | |
507 | fd_set my_read_set; | |
508 | struct timeval my_timeout; | |
509 | ||
510 | FD_ZERO( &my_read_set ); | |
511 | FD_SET( my_sockets[1], &my_read_set ); | |
512 | timerclear( &my_timeout ); | |
513 | my_timeout.tv_sec = 1; | |
514 | ||
515 | /* check to see if we are done, if no message is ready after a second | |
516 | * return and try again... | |
517 | */ | |
518 | my_err = select( (my_sockets[1] + 1), &my_read_set, NULL, NULL, &my_timeout ); | |
519 | if ( my_err == -1 ) { | |
520 | printf( "select call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
521 | exit( -1 ); | |
522 | } | |
523 | else if ( my_err > 0 ) { | |
524 | /* we're done */ | |
525 | break; | |
526 | } | |
527 | } | |
528 | ||
529 | /* test poll too */ | |
530 | my_pollfd.fd = my_sockets[1]; | |
531 | my_pollfd.events = (POLLIN | POLLPRI); | |
532 | my_pollfd.revents = 0; | |
533 | my_err = poll( &my_pollfd, 1, 500 ); | |
534 | if ( my_err == -1 ) { | |
535 | printf( "poll call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
536 | exit( -1 ); | |
537 | } | |
538 | /* should be ready for read */ | |
539 | if ( (my_pollfd.revents & POLLIN) == 0 ) { | |
540 | printf( "poll should have returned ready for read \n" ); | |
541 | exit( -1 ); | |
542 | } | |
543 | ||
544 | my_count = read( my_sockets[1], &my_buffer[0], sizeof(my_buffer) ); | |
545 | if ( my_count == -1 ) { | |
546 | printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
547 | exit( -1 ); | |
548 | } | |
549 | if ( my_buffer[0] != 'd' ) { | |
550 | printf( "read call on socket failed to get \"all done\" message \n" ); | |
551 | exit( -1 ); | |
552 | } | |
553 | ||
554 | exit(0); | |
555 | } | |
556 | ||
557 | /* | |
558 | * parent process - wait for child to spin up | |
559 | */ | |
560 | my_count = read( my_sockets[0], &my_buffer[0], sizeof(my_buffer) ); | |
561 | if ( my_count == -1 ) { | |
562 | printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
563 | goto test_failed_exit; | |
564 | } | |
565 | if ( my_buffer[0] != 'r' ) { | |
566 | printf( "read call on socket failed to get \"ready to go message\" \n" ); | |
567 | goto test_failed_exit; | |
568 | } | |
569 | ||
570 | /* tell child we're done */ | |
571 | write( my_sockets[0], "d", 1 ); | |
572 | ||
573 | my_wait_pid = wait4( my_pid, &my_status, 0, NULL ); | |
574 | if ( my_wait_pid == -1 ) { | |
575 | printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) ); | |
576 | goto test_failed_exit; | |
577 | } | |
578 | ||
579 | /* wait4 should return our child's pid when it exits */ | |
580 | if ( my_wait_pid != my_pid ) { | |
581 | printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid ); | |
582 | goto test_failed_exit; | |
583 | } | |
584 | ||
585 | if ( WIFEXITED( my_status ) && WEXITSTATUS( my_status ) != 0 ) { | |
586 | printf( "wait4 returned wrong exit status - 0x%02X \n", my_status ); | |
587 | goto test_failed_exit; | |
588 | } | |
589 | ||
590 | my_err = 0; | |
591 | goto test_passed_exit; | |
592 | ||
593 | test_failed_exit: | |
594 | my_err = -1; | |
595 | ||
596 | test_passed_exit: | |
597 | if ( my_sockets[0] != -1 ) | |
598 | close( my_sockets[0] ); | |
599 | if ( my_sockets[1] != -1 ) | |
600 | close( my_sockets[1] ); | |
601 | return( my_err ); | |
602 | } | |
603 |