1 /* $OpenBSD: setsockopt2.c,v 1.5 2012/02/26 21:08:06 fgsch Exp $ */ 2 /* 3 * Federico G. Schwindt <fgsch@openbsd.org>, 2009. Public Domain. 4 */ 5 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <sys/wait.h> 9 #include <sys/time.h> 10 #include <netinet/in.h> 11 #include <err.h> 12 #include <fcntl.h> 13 #include <netdb.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <unistd.h> 17 #include "test.h" 18 19 /* resolution of the monotonic clock */ 20 struct timespec mono_res; 21 22 static void 23 alarm_handler(int sig) 24 { 25 _exit(NOTOK); 26 } 27 28 void 29 check_timeout(int s, int sec, struct timespec *to) 30 { 31 struct timespec t1, t2, e; 32 char buf[BUFSIZ]; 33 34 ASSERT(signal(SIGALRM, alarm_handler) != SIG_ERR); 35 CHECKe(alarm(sec)); 36 CHECKe(clock_gettime(CLOCK_MONOTONIC, &t1)); 37 ASSERT(read(s, &buf, sizeof(buf)) == -1); 38 CHECKe(clock_gettime(CLOCK_MONOTONIC, &t2)); 39 ASSERT(errno == EAGAIN); 40 timespecsub(&t2, &t1, &e); 41 42 /* 43 * verify that the difference between the duration and the 44 * timeout is less than the resolution of the clock 45 */ 46 if (timespeccmp(&e, to, <)) 47 timespecsub(to, &e, &t1); 48 else 49 timespecsub(&e, to, &t1); 50 ASSERT(timespeccmp(&t1, &mono_res, <=)); 51 } 52 53 static void * 54 sock_connect(void *arg) 55 { 56 struct sockaddr_in sin; 57 struct timeval to; 58 struct timespec ts; 59 pid_t child_pid; 60 int status; 61 int s, s2, s3; 62 63 CHECKe(clock_getres(CLOCK_MONOTONIC, &mono_res)); 64 CHECKe(s = socket(AF_INET, SOCK_STREAM, 0)); 65 CHECKe(s2 = dup(s)); 66 CHECKe(s3 = fcntl(s, F_DUPFD, s)); 67 bzero(&sin, sizeof(sin)); 68 sin.sin_family = AF_INET; 69 sin.sin_len = sizeof(sin); 70 sin.sin_port = htons(6544); 71 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 72 CHECKe(connect(s, (struct sockaddr *)&sin, sizeof(sin))); 73 to.tv_sec = 2; 74 to.tv_usec = 0.5 * 1e6; 75 TIMEVAL_TO_TIMESPEC(&to, &ts); 76 CHECKe(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to))); 77 CHECKe(child_pid = fork()); 78 if (child_pid == 0) { 79 to.tv_sec = 1; 80 to.tv_usec = 0.5 * 1e6; 81 TIMEVAL_TO_TIMESPEC(&to, &ts); 82 CHECKe(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to))); 83 check_timeout(s, 2, &ts); 84 check_timeout(s2, 2, &ts); 85 check_timeout(s3, 2, &ts); 86 return (NULL); 87 } 88 sleep(2); 89 ts.tv_sec = 1; /* the fd timeout was changed in the child */ 90 check_timeout(s, 2, &ts); 91 check_timeout(s2, 2, &ts); 92 check_timeout(s3, 2, &ts); 93 CHECKe(s2 = dup(s)); 94 CHECKe(s3 = fcntl(s, F_DUPFD, s)); 95 check_timeout(s2, 2, &ts); 96 check_timeout(s3, 2, &ts); 97 CHECKe(close(s)); 98 CHECKe(close(s2)); 99 CHECKe(close(s3)); 100 ASSERTe(wait(&status), == child_pid); 101 ASSERT(WIFEXITED(status)); 102 CHECKr(WEXITSTATUS(status)); 103 return (NULL); 104 } 105 106 static void * 107 sock_accept(void *arg) 108 { 109 pthread_t connect_thread; 110 struct sockaddr_in sin; 111 int s; 112 113 CHECKe(s = socket(AF_INET, SOCK_STREAM, 0)); 114 bzero(&sin, sizeof(sin)); 115 sin.sin_family = AF_INET; 116 sin.sin_len = sizeof(sin); 117 sin.sin_port = htons(6544); 118 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 119 CHECKe(bind(s, (struct sockaddr *)&sin, sizeof(sin))); 120 CHECKe(listen(s, 2)); 121 122 CHECKr(pthread_create(&connect_thread, NULL, sock_connect, NULL)); 123 CHECKr(pthread_join(connect_thread, NULL)); 124 return (NULL); 125 } 126 127 int 128 main(int argc, char **argv) 129 { 130 pthread_t accept_thread; 131 132 CHECKr(pthread_create(&accept_thread, NULL, sock_accept, NULL)); 133 CHECKr(pthread_join(accept_thread, NULL)); 134 SUCCEED; 135 } 136