summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rw-r--r--opentracker.c2
-rw-r--r--tests/syscount.c144
-rw-r--r--tests/t_event.c37
4 files changed, 190 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 3ce127e..2e52367 100644
--- a/Makefile
+++ b/Makefile
@@ -110,6 +110,12 @@ $(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS)
110check: $(TESTBIN) $(BINARY) 110check: $(TESTBIN) $(BINARY)
111 ./$(TESTBIN) 111 ./$(TESTBIN)
112 112
113$(TESTBIN).poll: $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS)
114 $(CC) -o $@ $(CFLAGS_test) -DOT_EVENT_FORCE_POLL $(TEST_SOURCES) $(TEST_UNITS)
115
116check-poll: $(TESTBIN).poll
117 ./$(TESTBIN).poll ot_event
118
113# The same unit tests under the sanitizers. Use clang over $(CC) because the 119# The same unit tests under the sanitizers. Use clang over $(CC) because the
114# two toolchains do not check the same things 120# two toolchains do not check the same things
115# Override CC_sanitize to use another compiler. 121# Override CC_sanitize to use another compiler.
@@ -153,13 +159,14 @@ check-tsan: opentracker.tsan
153# Everything, cheapest first, so a quick failure comes back quickly. 159# Everything, cheapest first, so a quick failure comes back quickly.
154check-all: 160check-all:
155 $(MAKE) check 161 $(MAKE) check
162 $(MAKE) check-poll
156 $(MAKE) check-sanitize 163 $(MAKE) check-sanitize
157 $(MAKE) check-integration 164 $(MAKE) check-integration
158 $(MAKE) check-tsan 165 $(MAKE) check-tsan
159 166
160.PHONY: all check check-sanitize check-integration check-tsan check-all clean install 167.PHONY: all check check-poll check-sanitize check-integration check-tsan check-all clean install
161 168
162BINARIES=opentracker opentracker.debug opentracker.integration opentracker.tsan proxy proxy.debug $(TESTBIN) $(TESTBIN).sanitize 169BINARIES=opentracker opentracker.debug opentracker.integration opentracker.tsan proxy proxy.debug $(TESTBIN) $(TESTBIN).sanitize $(TESTBIN).poll
163 170
164clean: 171clean:
165 rm -rf $(BINARIES) $(BINARIES:=.dSYM) *.o *~ 172 rm -rf $(BINARIES) $(BINARIES:=.dSYM) *.o *~
diff --git a/opentracker.c b/opentracker.c
index 6160696..b54327a 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -199,8 +199,6 @@ static void handle_accept(const int64_t serversocket, struct ot_workstruct *ws)
199 199
200 while ((sock = socket_accept(serversocket, ip, &port)) != -1) { 200 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
201 201
202 socket_set_blocking((int)sock, 0);
203
204 if (!(cookie = (struct http_data *)calloc(1, sizeof(struct http_data)))) { 202 if (!(cookie = (struct http_data *)calloc(1, sizeof(struct http_data)))) {
205 close((int)sock); 203 close((int)sock);
206 continue; 204 continue;
diff --git a/tests/syscount.c b/tests/syscount.c
new file mode 100644
index 0000000..ec45c15
--- /dev/null
+++ b/tests/syscount.c
@@ -0,0 +1,144 @@
1/* Counts the system calls a run makes, by standing in front of libc.
2
3 cc -O2 -shared -fPIC -o syscount.so tests/syscount.c -ldl
4 LD_PRELOAD=./syscount.so ./opentracker -f conf (DYLD_INSERT_LIBRARIES on macOS)
5
6 The tally goes to stderr when the process exits. Reading the source tells
7 you which calls a path should make; this tells you which it does make,
8 which is not always the same thing. */
9
10#define _GNU_SOURCE
11#include <dlfcn.h>
12#include <stdarg.h>
13#include <stdatomic.h>
14#include <stdio.h>
15#include <sys/socket.h>
16#include <sys/types.h>
17#include <unistd.h>
18
19#ifdef __linux__
20#include <sys/epoll.h>
21#endif
22
23#define COUNTER(name) static _Atomic long g_##name
24#define BUMP(name) atomic_fetch_add_explicit(&g_##name, 1, memory_order_relaxed)
25#define REPORT(name) fprintf(stderr, " %-14s %10ld\n", #name, atomic_load(&g_##name))
26
27COUNTER(accept);
28COUNTER(accept4);
29COUNTER(read);
30COUNTER(write);
31COUNTER(close);
32COUNTER(fcntl);
33COUNTER(recvfrom);
34COUNTER(sendto);
35COUNTER(epoll_ctl);
36COUNTER(epoll_wait);
37
38typedef int (*fn_accept)(int, struct sockaddr *, socklen_t *);
39typedef int (*fn_accept4)(int, struct sockaddr *, socklen_t *, int);
40typedef ssize_t (*fn_read)(int, void *, size_t);
41typedef ssize_t (*fn_write)(int, const void *, size_t);
42typedef int (*fn_close)(int);
43typedef int (*fn_fcntl)(int, int, ...);
44typedef ssize_t (*fn_recvfrom)(int, void *, size_t, int, struct sockaddr *, socklen_t *);
45typedef ssize_t (*fn_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
46
47static fn_accept real_accept;
48static fn_accept4 real_accept4;
49static fn_read real_read;
50static fn_write real_write;
51static fn_close real_close;
52static fn_fcntl real_fcntl;
53static fn_recvfrom real_recvfrom;
54static fn_sendto real_sendto;
55
56/* Resolving lazily keeps the library out of the way until something is
57 actually called, which matters because dlsym itself allocates */
58#define WRAP(name) \
59 if (!real_##name) \
60 real_##name = (fn_##name)dlsym(RTLD_NEXT, #name); \
61 BUMP(name)
62
63int accept(int s, struct sockaddr *addr, socklen_t *len) {
64 WRAP(accept);
65 return real_accept(s, addr, len);
66}
67
68#ifdef SOCK_NONBLOCK
69int accept4(int s, struct sockaddr *addr, socklen_t *len, int flags) {
70 WRAP(accept4);
71 return real_accept4(s, addr, len, flags);
72}
73#endif
74
75ssize_t read(int fd, void *buf, size_t count) {
76 WRAP(read);
77 return real_read(fd, buf, count);
78}
79
80ssize_t write(int fd, const void *buf, size_t count) {
81 WRAP(write);
82 return real_write(fd, buf, count);
83}
84
85int close(int fd) {
86 WRAP(close);
87 return real_close(fd);
88}
89
90int fcntl(int fd, int cmd, ...) {
91 va_list args;
92 long arg;
93
94 va_start(args, cmd);
95 arg = va_arg(args, long);
96 va_end(args);
97 WRAP(fcntl);
98 return real_fcntl(fd, cmd, arg);
99}
100
101ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) {
102 WRAP(recvfrom);
103 return real_recvfrom(s, buf, len, flags, from, fromlen);
104}
105
106ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) {
107 WRAP(sendto);
108 return real_sendto(s, buf, len, flags, to, tolen);
109}
110
111#ifdef __linux__
112typedef int (*fn_epoll_ctl)(int, int, int, struct epoll_event *);
113typedef int (*fn_epoll_wait)(int, struct epoll_event *, int, int);
114static fn_epoll_ctl real_epoll_ctl;
115static fn_epoll_wait real_epoll_wait;
116
117int epoll_ctl(int ep, int op, int fd, struct epoll_event *ev) {
118 WRAP(epoll_ctl);
119 return real_epoll_ctl(ep, op, fd, ev);
120}
121
122int epoll_wait(int ep, struct epoll_event *events, int max, int timeout) {
123 WRAP(epoll_wait);
124 return real_epoll_wait(ep, events, max, timeout);
125}
126#endif
127
128__attribute__((destructor)) static void report(void) {
129 fprintf(stderr, "\n system calls this run\n");
130 REPORT(accept);
131#ifdef SOCK_NONBLOCK
132 REPORT(accept4);
133#endif
134 REPORT(read);
135 REPORT(write);
136 REPORT(close);
137 REPORT(fcntl);
138 REPORT(recvfrom);
139 REPORT(sendto);
140#ifdef __linux__
141 REPORT(epoll_ctl);
142 REPORT(epoll_wait);
143#endif
144}
diff --git a/tests/t_event.c b/tests/t_event.c
index 5509f19..ad3948f 100644
--- a/tests/t_event.c
+++ b/tests/t_event.c
@@ -4,6 +4,7 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#include <fcntl.h>
7#include <string.h> 8#include <string.h>
8#include <sys/socket.h> 9#include <sys/socket.h>
9#include <sys/time.h> 10#include <sys/time.h>
@@ -205,6 +206,41 @@ static void case_unknown_descriptor(void) {
205 CHECK_INT(event_del(4096), -1); 206 CHECK_INT(event_del(4096), -1);
206} 207}
207 208
209/* event_close exists so that the mechanisms which drop a closed descriptor
210 by themselves are not asked to do it twice. The one that keeps its own
211 list has to be told, and forgetting would leave the entry there to be
212 reported for ever, so what is checked here is the silence afterwards. */
213static void case_close_takes_it_out(void) {
214 int other[2], closed, count, i, strays = 0;
215
216 test_case("a closed descriptor is gone from the set and really closed");
217 pair_open();
218 CHECK(sv[0] != -1);
219 CHECK_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, other), 0);
220 CHECK_INT(event_add(sv[0], EVENT_IN, 1), 0);
221 CHECK_INT(event_add(other[0], EVENT_IN, 2), 0);
222
223 closed = sv[0];
224 CHECK_INT(event_close(closed), 0);
225 sv[0] = -1;
226 CHECK_INT(fcntl(closed, F_GETFD), -1);
227
228 /* The survivor is made ready so the wait has something to come back with,
229 and anything left over from the closed one shows up beside it */
230 CHECK_INT((int)write(other[1], "x", 1), 1);
231 count = event_wait(ready, EVENTS, 200);
232 CHECK(count >= 1);
233 for (i = 0; i < count; ++i)
234 if (ready[i].fd != other[0])
235 ++strays;
236 CHECK_INT(strays, 0);
237
238 event_del(other[0]);
239 close(other[0]);
240 close(other[1]);
241 pair_close();
242}
243
208void test_event(void) { 244void test_event(void) {
209 CHECK_INT(event_init(), 0); 245 CHECK_INT(event_init(), 0);
210 CHECK(event_mechanism() != NULL); 246 CHECK(event_mechanism() != NULL);
@@ -217,6 +253,7 @@ void test_event(void) {
217 case_delete_from_the_middle(); 253 case_delete_from_the_middle();
218 case_timeout(); 254 case_timeout();
219 case_unknown_descriptor(); 255 case_unknown_descriptor();
256 case_close_takes_it_out();
220 257
221 event_deinit(); 258 event_deinit();
222} 259}