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