clarify required conditions for attack
[detour.git] / common.c
1 // This file is basically utility functions from various places mashed together, including
2 // from my helper library libjh.
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <time.h>
8 #include <assert.h>
9 #include <sys/select.h>
10 #include <stdbool.h>
11 #include <errno.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <dirent.h>
16 #include <string.h>
17 #include <netdb.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <netinet/tcp.h>
21
22 #define JH_TCP_HINTS (&libjh_tcp_hints)
23 const struct addrinfo libjh_tcp_hints = {
24   .ai_flags = AI_ADDRCONFIG,
25   .ai_family = AF_UNSPEC,
26   .ai_socktype = SOCK_STREAM,
27   .ai_protocol = 0
28 };
29
30 int netopen_server(const char *node /*NULL for ANY*/, const char *service, const struct addrinfo *hints) {
31   struct addrinfo hints_;
32   if (hints == &libjh_tcp_hints) {
33     hints_ = *hints;
34     hints_.ai_flags |= AI_PASSIVE;
35     hints_.ai_flags &= ~AI_ADDRCONFIG;
36     hints = &hints_;
37   }
38
39   struct addrinfo *addrs;
40   int gai_res = getaddrinfo(node, service, hints, &addrs);
41   if (gai_res) return gai_res;
42
43   int s = socket(addrs[0].ai_family, addrs[0].ai_socktype, addrs[0].ai_protocol);
44   if (s == -1) goto err_socket;
45
46   if (bind(s, addrs[0].ai_addr, addrs[0].ai_addrlen)) goto err_bind_n_listen;
47   if (listen(s, 16)) goto err_bind_n_listen;
48
49   freeaddrinfo(addrs);
50   return s;
51
52 err_bind_n_listen:;
53   int errno_ = errno;
54   close(s);
55   errno = errno_;
56 err_socket:
57   freeaddrinfo(addrs);
58   return EAI_SYSTEM;
59 }
60
61 ssize_t read_nointr(int fd, void *buf, size_t count, int *last_res) {
62   errno = 0;
63   size_t done = 0;
64   while (done < count) {
65     ssize_t part_res = read(fd, buf+done, count-done);
66     if (part_res == -1 && errno == EINTR) continue;
67     if (part_res <= 0) {
68       if (last_res) *last_res = part_res;
69       if (done) return done;
70       return part_res;
71     }
72     done += part_res;
73   }
74   if (last_res) *last_res = 1;
75   return done;
76 }
77
78 void *slurp_fd(int fd, size_t *len_out) {
79   int errno_;
80   
81   size_t size_guess;
82   
83   struct stat st;
84   if (fstat(fd, &st) == 0) {
85     if (st.st_size > 0) {
86       size_guess = st.st_size;
87     }
88   }
89   
90   char *buf = NULL;
91   int done = 0;
92   
93   while (1) {
94     buf = realloc(buf, size_guess);
95     if (buf == NULL) return NULL;
96     int last_res;
97     ssize_t read_res = read_nointr(fd, buf+done, size_guess-done, &last_res);
98     if (last_res == -1) { errno_=errno; free(buf); errno=errno_; return NULL; }
99     done += read_res;
100     if (len_out) *len_out = done;
101     return buf;
102   }
103 }
104
105 void *slurp_file(char *path, size_t *len_out) {
106   int fd = open(path, O_RDONLY|O_CLOEXEC);
107   if (fd == -1) return NULL;
108   char *res = slurp_fd(fd, len_out);
109   int errno_ = errno;
110   close(fd);
111   errno = errno_;
112   return res;
113 }
114
115 time_t real_seconds(void) {
116   struct timespec t;
117   int s = clock_gettime(CLOCK_REALTIME, &t);
118   assert(s==0);
119   return t.tv_sec;
120 }
121
122 /* Subtract the `struct timeval' values X and Y,
123    storing the result in RESULT.
124    Return 1 if the difference is negative, otherwise 0. */
125 int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) {
126   /* Perform the carry for the later subtraction by updating y. */
127   if (x->tv_nsec < y->tv_nsec) {
128     int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
129     y->tv_nsec -= 1000000000 * nsec;
130     y->tv_sec += nsec;
131   }
132   if (x->tv_nsec - y->tv_nsec > 1000000000) {
133     int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
134     y->tv_nsec += 1000000000 * nsec;
135     y->tv_sec -= nsec;
136   }
137
138   /* Compute the time remaining to wait.
139      tv_usec is certainly positive. */
140   result->tv_sec = x->tv_sec - y->tv_sec;
141   result->tv_nsec = x->tv_nsec - y->tv_nsec;
142
143   /* Return 1 if result is negative. */
144   return x->tv_sec < y->tv_sec;
145 }
146
147 void sleep_until(time_t dst_sec) {
148   struct timespec dst;
149   dst.tv_sec = dst_sec;
150   dst.tv_nsec = 0;
151   while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dst, NULL)) /* nothing */;
152 }
153
154 time_t round_up(time_t t, int align) {
155   t = t - 1; /* counter bad +t for aligned things in last step */
156   t = t - t%align; /* round down to align */
157   t = t + align; /* add alignment to make it a round up */
158   return t;
159 }