xio: rename xio to ioops and reduce its includes
[netsniff-ng.git] / ct_server.c
blob565eb1f83ce221b294edd0e1325d3521c9d31a90
1 /*
2 * curvetun - the cipherspace wormhole creator
3 * Part of the netsniff-ng project
4 * Copyright 2011 Daniel Borkmann <daniel@netsniff-ng.org>,
5 * Subject to the GPL, version 2.
6 */
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <pthread.h>
16 #include <syslog.h>
17 #include <signal.h>
18 #include <netdb.h>
19 #include <stdint.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22 #include <netinet/udp.h>
23 #include <sys/poll.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/wait.h>
27 #include <sys/epoll.h>
28 #include <arpa/inet.h>
29 #include <linux/if_tun.h>
31 #include "die.h"
32 #include "xutils.h"
33 #include "ioops.h"
34 #include "xmalloc.h"
35 #include "curvetun.h"
36 #include "curve.h"
37 #include "ioexact.h"
38 #include "corking.h"
39 #include "cpus.h"
40 #include "built_in.h"
41 #include "ct_usermgmt.h"
42 #include "cpusched.h"
43 #include "trie.h"
45 struct parent_info {
46 int efd;
47 int refd;
48 int tunfd;
49 int ipv4;
50 int udp;
53 struct worker_struct {
54 pthread_t trid;
55 int efd[2];
56 unsigned int cpu;
57 struct parent_info parent;
58 int (*handler)(int fd, const struct worker_struct *ws,
59 char *buff, size_t len);
60 struct curve25519_struct *c;
63 static struct worker_struct *threadpool = NULL;
65 static int auth_log = 1;
67 extern volatile sig_atomic_t sigint;
69 static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
70 char *buff, size_t len) __pure;
71 static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
72 char *buff, size_t len) __pure;
73 static int handler_udp(int fd, const struct worker_struct *ws,
74 char *buff, size_t len) __pure;
75 static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws,
76 char *buff, size_t len) __pure;
77 static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws,
78 char *buff, size_t len) __pure;
79 static int handler_tcp(int fd, const struct worker_struct *ws,
80 char *buff, size_t len) __pure;
81 ssize_t handler_tcp_read(int fd, char *buff, size_t len);
82 static void *worker(void *self) __pure;
84 static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
85 char *buff, size_t len)
87 int dfd, keep = 1;
88 char *cbuff;
89 ssize_t rlen, err, clen;
90 struct ct_proto *hdr;
91 struct curve25519_proto *p;
92 struct sockaddr_storage naddr;
93 socklen_t nlen;
94 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
96 if (!buff || len <= off)
97 return 0;
99 memset(buff, 0, len);
100 while ((rlen = read(fd, buff + off, len - off)) > 0) {
101 dfd = -1; nlen = 0; p = NULL;
103 memset(&naddr, 0, sizeof(naddr));
105 hdr = (struct ct_proto *) buff;
106 memset(hdr, 0, sizeof(*hdr));
107 hdr->flags = 0;
109 trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr,
110 (size_t *) &nlen);
111 if (unlikely(dfd < 0 || nlen == 0)) {
112 memset(buff, 0, len);
113 continue;
116 err = get_user_by_sockaddr(&naddr, nlen, &p);
117 if (unlikely(err || !p)) {
118 memset(buff, 0, len);
119 continue;
122 clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
123 crypto_box_zerobytes), (rlen +
124 crypto_box_zerobytes), (unsigned char **)
125 &cbuff);
126 if (unlikely(clen <= 0)) {
127 memset(buff, 0, len);
128 continue;
131 hdr->payload = htons((uint16_t) clen);
133 set_udp_cork(dfd);
135 sendto(dfd, hdr, sizeof(struct ct_proto), 0, (struct sockaddr *)
136 &naddr, nlen);
137 sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr, nlen);
139 set_udp_uncork(dfd);
141 memset(buff, 0, len);
144 return keep;
147 static void handler_udp_notify_close(int fd, struct sockaddr_storage *addr)
149 struct ct_proto hdr;
151 memset(&hdr, 0, sizeof(hdr));
152 hdr.flags |= PROTO_FLAG_EXIT;
153 hdr.payload = 0;
155 sendto(fd, &hdr, sizeof(hdr), 0, (struct sockaddr *) addr,
156 sizeof(*addr));
159 static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
160 char *buff, size_t len)
162 int keep = 1;
163 char *cbuff;
164 ssize_t rlen, err, clen;
165 struct ct_proto *hdr;
166 struct curve25519_proto *p;
167 struct sockaddr_storage naddr;
168 socklen_t nlen = sizeof(naddr);
170 if (!buff || !len)
171 return 0;
173 memset(&naddr, 0, sizeof(naddr));
174 while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr,
175 &nlen)) > 0) {
176 p = NULL;
178 hdr = (struct ct_proto *) buff;
180 if (unlikely(rlen < sizeof(struct ct_proto)))
181 goto close;
182 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
183 goto close;
184 if (unlikely(ntohs(hdr->payload) == 0))
185 goto close;
186 if (hdr->flags & PROTO_FLAG_EXIT) {
187 close:
188 remove_user_by_sockaddr(&naddr, nlen);
189 trie_addr_remove_addr(&naddr, nlen);
190 handler_udp_notify_close(fd, &naddr);
192 return keep;
194 if (hdr->flags & PROTO_FLAG_INIT) {
195 syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
196 "from remote end!\n");
198 if (unlikely(rlen - sizeof(*hdr) <
199 sizeof(struct username_struct)))
200 goto close;
202 err = try_register_user_by_sockaddr(ws->c,
203 buff + sizeof(struct ct_proto),
204 rlen - sizeof(struct ct_proto),
205 &naddr, nlen, auth_log);
206 if (unlikely(err))
207 goto close;
209 goto next;
212 err = get_user_by_sockaddr(&naddr, nlen, &p);
213 if (unlikely(err || !p))
214 goto close;
216 clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
217 sizeof(struct ct_proto),
218 rlen - sizeof(struct ct_proto),
219 (unsigned char **) &cbuff, NULL);
220 if (unlikely(clen <= 0))
221 goto close;
223 cbuff += crypto_box_zerobytes;
224 clen -= crypto_box_zerobytes;
226 err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
227 fd, &naddr, nlen);
228 if (unlikely(err))
229 goto next;
231 err = write(ws->parent.tunfd, cbuff, clen);
232 next:
233 nlen = sizeof(naddr);
234 memset(&naddr, 0, sizeof(naddr));
237 return keep;
240 static int handler_udp(int fd, const struct worker_struct *ws,
241 char *buff, size_t len)
243 int ret = 0;
245 if (fd == ws->parent.tunfd)
246 ret = handler_udp_tun_to_net(fd, ws, buff, len);
247 else
248 ret = handler_udp_net_to_tun(fd, ws, buff, len);
250 return ret;
253 static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws,
254 char *buff, size_t len)
256 int dfd, keep = 1;
257 char *cbuff;
258 ssize_t rlen, err, clen;
259 struct ct_proto *hdr;
260 struct curve25519_proto *p;
261 socklen_t nlen;
262 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
264 if (!buff || len <= off)
265 return 0;
267 memset(buff, 0, len);
268 while ((rlen = read(fd, buff + off, len - off)) > 0) {
269 dfd = -1; p = NULL;
271 hdr = (struct ct_proto *) buff;
272 memset(hdr, 0, sizeof(*hdr));
273 hdr->flags = 0;
275 trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, NULL,
276 (size_t *) &nlen);
277 if (unlikely(dfd < 0)) {
278 memset(buff, 0, len);
279 continue;
282 err = get_user_by_socket(dfd, &p);
283 if (unlikely(err || !p)) {
284 memset(buff, 0, len);
285 continue;
288 clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
289 crypto_box_zerobytes), (rlen +
290 crypto_box_zerobytes), (unsigned char **)
291 &cbuff);
292 if (unlikely(clen <= 0)) {
293 memset(buff, 0, len);
294 continue;
297 hdr->payload = htons((uint16_t) clen);
299 set_tcp_cork(dfd);
301 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
302 write_exact(dfd, cbuff, clen, 0);
304 set_tcp_uncork(dfd);
306 memset(buff, 0, len);
309 return keep;
312 ssize_t handler_tcp_read(int fd, char *buff, size_t len)
314 ssize_t rlen;
315 struct ct_proto *hdr = (struct ct_proto *) buff;
317 if (!buff || !len)
318 return 0;
320 /* May exit on EAGAIN if 0 Byte read */
321 rlen = read_exact(fd, buff, sizeof(struct ct_proto), 1);
322 if (rlen < 0)
323 return rlen;
324 if (unlikely(ntohs(hdr->payload) > len - sizeof(struct ct_proto))) {
325 errno = ENOMEM;
326 return 1; /* Force server to close connection */
329 /* May not exit on EAGAIN if 0 Byte read */
330 rlen = read_exact(fd, buff + sizeof(struct ct_proto),
331 ntohs(hdr->payload), 0);
332 if (rlen < 0)
333 return rlen;
335 return sizeof(struct ct_proto) + rlen;
338 static void handler_tcp_notify_close(int fd)
340 struct ct_proto hdr;
342 memset(&hdr, 0, sizeof(hdr));
343 hdr.flags |= PROTO_FLAG_EXIT;
344 hdr.payload = 0;
346 if (write(fd, &hdr, sizeof(hdr))) { ; }
349 static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws,
350 char *buff, size_t len)
352 int keep = 1, count = 0;
353 char *cbuff;
354 ssize_t rlen, err, clen;
355 struct ct_proto *hdr;
356 struct curve25519_proto *p;
358 if (!buff || !len)
359 return 0;
361 while ((rlen = handler_tcp_read(fd, buff, len)) > 0) {
362 p = NULL;
364 hdr = (struct ct_proto *) buff;
366 if (unlikely(rlen < sizeof(struct ct_proto)))
367 goto close;
368 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
369 goto close;
370 if (unlikely(ntohs(hdr->payload) == 0))
371 goto close;
372 if (hdr->flags & PROTO_FLAG_EXIT) {
373 close:
374 remove_user_by_socket(fd);
375 trie_addr_remove(fd);
376 handler_tcp_notify_close(fd);
377 rlen = write(ws->parent.efd, &fd, sizeof(fd));
379 keep = 0;
380 return keep;
382 if (hdr->flags & PROTO_FLAG_INIT) {
383 syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
384 "from remote end!\n");
386 if (unlikely(rlen - sizeof(*hdr) <
387 sizeof(struct username_struct)))
388 goto close;
390 err = try_register_user_by_socket(ws->c,
391 buff + sizeof(struct ct_proto),
392 rlen - sizeof(struct ct_proto),
393 fd, auth_log);
394 if (unlikely(err))
395 goto close;
397 continue;
400 err = get_user_by_socket(fd, &p);
401 if (unlikely(err || !p))
402 continue;
404 clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
405 sizeof(struct ct_proto),
406 rlen - sizeof(struct ct_proto),
407 (unsigned char **) &cbuff, NULL);
408 if (unlikely(clen <= 0))
409 continue;
411 cbuff += crypto_box_zerobytes;
412 clen -= crypto_box_zerobytes;
414 err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
415 fd, NULL, 0);
416 if (unlikely(err))
417 continue;
419 err = write(ws->parent.tunfd, cbuff, clen);
421 count++;
422 if (count == 10) {
423 write_exact(ws->efd[1], &fd, sizeof(fd), 1);
424 /* Read later next data and let others process */
425 return keep;
429 return keep;
432 static int handler_tcp(int fd, const struct worker_struct *ws,
433 char *buff, size_t len)
435 int ret = 0;
437 if (fd == ws->parent.tunfd)
438 ret = handler_tcp_tun_to_net(fd, ws, buff, len);
439 else
440 ret = handler_tcp_net_to_tun(fd, ws, buff, len);
442 return ret;
445 static void *worker(void *self)
447 int fd, old_state;
448 ssize_t ret;
449 size_t blen = TUNBUFF_SIZ; //FIXME
450 const struct worker_struct *ws = self;
451 struct pollfd fds;
452 char *buff;
454 fds.fd = ws->efd[0];
455 fds.events = POLLIN;
457 curve25519_alloc_or_maybe_die(ws->c);
459 buff = xmalloc_aligned(blen, 64);
461 syslog(LOG_INFO, "curvetun thread on CPU%u up!\n", ws->cpu);
463 pthread_cleanup_push(xfree_func, ws->c);
464 pthread_cleanup_push(curve25519_free, ws->c);
465 pthread_cleanup_push(xfree_func, buff);
467 while (likely(!sigint)) {
468 poll(&fds, 1, -1);
469 if ((fds.revents & POLLIN) != POLLIN)
470 continue;
472 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
474 while ((ret = read_exact(ws->efd[0], &fd, sizeof(fd), 1)) > 0) {
475 if (ret != sizeof(fd)) {
476 sched_yield();
477 continue;
480 ret = ws->handler(fd, ws, buff, blen);
481 if (ret)
482 write_exact(ws->parent.refd, &fd, sizeof(fd), 1);
485 pthread_setcancelstate(old_state, NULL);
488 syslog(LOG_INFO, "curvetun thread on CPU%u down!\n", ws->cpu);
490 pthread_cleanup_pop(1);
491 pthread_cleanup_pop(1);
492 pthread_cleanup_pop(1);
494 pthread_exit((void *) ((long) ws->cpu));
497 static void thread_spawn_or_panic(unsigned int cpus, int efd, int refd,
498 int tunfd, int ipv4, int udp)
500 int i, ret;
501 cpu_set_t cpuset;
502 unsigned int threads;
504 threads = cpus * THREADS_PER_CPU;
506 for (i = 0; i < threads; ++i) {
507 CPU_ZERO(&cpuset);
508 threadpool[i].cpu = i % cpus;
509 CPU_SET(threadpool[i].cpu, &cpuset);
511 ret = pipe2(threadpool[i].efd, O_NONBLOCK);
512 if (ret < 0)
513 syslog_panic("Cannot create event socket!\n");
515 threadpool[i].c = xmalloc_aligned(sizeof(*threadpool[i].c), 64);
516 threadpool[i].parent.efd = efd;
517 threadpool[i].parent.refd = refd;
518 threadpool[i].parent.tunfd = tunfd;
519 threadpool[i].parent.ipv4 = ipv4;
520 threadpool[i].parent.udp = udp;
521 threadpool[i].handler = udp ? handler_udp : handler_tcp;
523 ret = pthread_create(&threadpool[i].trid, NULL,
524 worker, &threadpool[i]);
525 if (ret < 0)
526 syslog_panic("Thread creation failed!\n");
528 ret = pthread_setaffinity_np(threadpool[i].trid,
529 sizeof(cpuset), &cpuset);
530 if (ret < 0)
531 syslog_panic("Thread CPU migration failed!\n");
533 pthread_detach(threadpool[i].trid);
536 sleep(1);
539 static void thread_finish(unsigned int cpus)
541 int i;
542 unsigned int threads;
544 threads = cpus * THREADS_PER_CPU;
546 for (i = 0; i < threads; ++i) {
547 while (pthread_join(threadpool[i].trid, NULL) < 0)
550 close(threadpool[i].efd[0]);
551 close(threadpool[i].efd[1]);
555 int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log)
557 int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i;
558 unsigned int cpus = 0, threads, udp_cpu = 0;
559 ssize_t ret;
560 struct epoll_event *events;
561 struct addrinfo hints, *ahead, *ai;
563 auth_log = !!log;
564 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
566 syslog(LOG_INFO, "curvetun server booting!\n");
567 syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n");
569 parse_userfile_and_generate_user_store_or_die(home);
571 memset(&hints, 0, sizeof(hints));
572 hints.ai_family = PF_UNSPEC;
573 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
574 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
575 hints.ai_flags = AI_PASSIVE;
577 ret = getaddrinfo(NULL, port, &hints, &ahead);
578 if (ret < 0)
579 syslog_panic("Cannot get address info!\n");
581 for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) {
582 lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
583 if (lfd < 0)
584 continue;
585 if (ai->ai_family == AF_INET6) {
586 #ifdef IPV6_V6ONLY
587 ret = set_ipv6_only(lfd);
588 if (ret < 0) {
589 close(lfd);
590 lfd = -1;
591 continue;
593 #else
594 close(lfd);
595 lfd = -1;
596 continue;
597 #endif /* IPV6_V6ONLY */
600 set_reuseaddr(lfd);
601 set_mtu_disc_dont(lfd);
603 ret = bind(lfd, ai->ai_addr, ai->ai_addrlen);
604 if (ret < 0) {
605 close(lfd);
606 lfd = -1;
607 continue;
610 if (!udp) {
611 ret = listen(lfd, 5);
612 if (ret < 0) {
613 close(lfd);
614 lfd = -1;
615 continue;
619 if (ipv4 == -1) {
620 ipv4 = (ai->ai_family == AF_INET6 ? 0 :
621 (ai->ai_family == AF_INET ? 1 : -1));
624 syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s "
625 "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6,
626 udp ? "UDP" : "TCP", port);
627 syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is "
628 "IPv%d!\n", ipv4 ? 4 : 6);
631 freeaddrinfo(ahead);
633 if (lfd < 0 || ipv4 < 0)
634 syslog_panic("Cannot create socket!\n");
636 tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI);
638 pipe_or_die(efd, O_NONBLOCK);
639 pipe_or_die(refd, O_NONBLOCK);
641 set_nonblocking(lfd);
643 events = xzmalloc(MAX_EPOLL_SIZE * sizeof(*events));
644 for (i = 0; i < MAX_EPOLL_SIZE; ++i)
645 events[i].data.fd = -1;
647 kdpfd = epoll_create(MAX_EPOLL_SIZE);
648 if (kdpfd < 0)
649 syslog_panic("Cannot create socket!\n");
651 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd,
652 udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN);
653 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN);
654 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN);
655 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd,
656 EPOLLIN | EPOLLET | EPOLLONESHOT);
657 curfds = 4;
659 trie_init();
661 cpus = get_number_cpus_online();
662 threads = cpus * THREADS_PER_CPU;
663 if (!ispow2(threads))
664 syslog_panic("Thread number not power of two!\n");
666 threadpool = xzmalloc(sizeof(*threadpool) * threads);
667 thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp);
669 init_cpusched(threads);
671 register_socket(tunfd);
672 register_socket(lfd);
674 syslog(LOG_INFO, "curvetun up and running!\n");
676 while (likely(!sigint)) {
677 nfds = epoll_wait(kdpfd, events, curfds, -1);
678 if (nfds < 0) {
679 syslog(LOG_ERR, "epoll_wait error: %s\n",
680 strerror(errno));
681 break;
684 for (i = 0; i < nfds; ++i) {
685 if (unlikely(events[i].data.fd < 0))
686 continue;
688 if (events[i].data.fd == lfd && !udp) {
689 int ncpu;
690 char hbuff[256], sbuff[256];
691 struct sockaddr_storage taddr;
692 socklen_t tlen;
694 tlen = sizeof(taddr);
695 nfd = accept(lfd, (struct sockaddr *) &taddr,
696 &tlen);
697 if (nfd < 0) {
698 syslog(LOG_ERR, "accept error: %s\n",
699 strerror(errno));
700 continue;
703 if (curfds + 1 > MAX_EPOLL_SIZE) {
704 close(nfd);
705 continue;
708 curfds++;
710 ncpu = register_socket(nfd);
712 memset(hbuff, 0, sizeof(hbuff));
713 memset(sbuff, 0, sizeof(sbuff));
714 getnameinfo((struct sockaddr *) &taddr, tlen,
715 hbuff, sizeof(hbuff),
716 sbuff, sizeof(sbuff),
717 NI_NUMERICHOST | NI_NUMERICSERV);
719 syslog_maybe(auth_log, LOG_INFO, "New connection "
720 "from %s:%s (%d active client connections) - id %d on CPU%d",
721 hbuff, sbuff, curfds-4, nfd, ncpu);
723 set_nonblocking(nfd);
724 set_socket_keepalive(nfd);
725 set_tcp_nodelay(nfd);
726 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD,
727 nfd, EPOLLIN | EPOLLET | EPOLLONESHOT);
728 if (ret < 0) {
729 close(nfd);
730 curfds--;
731 continue;
733 } else if (events[i].data.fd == refd[0]) {
734 int fd_one;
736 ret = read_exact(refd[0], &fd_one,
737 sizeof(fd_one), 1);
738 if (ret != sizeof(fd_one) || fd_one <= 0)
739 continue;
741 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD,
742 fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT);
743 if (ret < 0) {
744 close(fd_one);
745 continue;
747 } else if (events[i].data.fd == efd[0]) {
748 int fd_del, test;
750 ret = read_exact(efd[0], &fd_del,
751 sizeof(fd_del), 1);
752 if (ret != sizeof(fd_del) || fd_del <= 0)
753 continue;
755 ret = read(fd_del, &test, sizeof(test));
756 if (ret < 0 && errno == EBADF)
757 continue;
759 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL,
760 fd_del, 0);
761 if (ret < 0) {
762 close(fd_del);
763 continue;
766 close(fd_del);
767 curfds--;
768 unregister_socket(fd_del);
770 syslog_maybe(auth_log, LOG_INFO, "Closed connection "
771 "with id %d (%d active client connections remain)\n", fd_del,
772 curfds-4);
773 } else {
774 int cpu, fd_work = events[i].data.fd;
776 if (!udp)
777 cpu = socket_to_cpu(fd_work);
778 else
779 udp_cpu = (udp_cpu + 1) & (threads - 1);
781 write_exact(threadpool[udp ? udp_cpu : cpu].efd[1],
782 &fd_work, sizeof(fd_work), 1);
787 syslog(LOG_INFO, "curvetun prepare shut down!\n");
789 close(lfd);
790 close(efd[0]);
791 close(efd[1]);
792 close(refd[0]);
793 close(refd[1]);
794 close(tunfd);
796 thread_finish(cpus);
798 xfree(threadpool);
799 xfree(events);
801 unregister_socket(lfd);
802 unregister_socket(tunfd);
804 destroy_cpusched();
806 trie_cleanup();
808 destroy_user_store();
810 syslog(LOG_INFO, "curvetun shut down!\n");
811 closelog();
813 return 0;