trafgen: fixed '--in -' to work again with STDIN
[netsniff-ng-new.git] / curvetun_server.c
blobc1d547722e0ea57b3d892c31de3685ee393b6219
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 <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 "epoll2.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 "sock.h"
41 #include "built_in.h"
42 #include "curvetun_mgmt.h"
43 #include "cpusched.h"
44 #include "trie.h"
46 struct parent_info {
47 int efd;
48 int refd;
49 int tunfd;
50 int ipv4;
51 int udp;
54 struct worker_struct {
55 pthread_t trid;
56 int efd[2];
57 unsigned int cpu;
58 struct parent_info parent;
59 int (*handler)(int fd, const struct worker_struct *ws,
60 char *buff, size_t len);
61 struct curve25519_struct *c;
64 static struct worker_struct *threadpool = NULL;
66 static int auth_log = 1;
68 extern volatile sig_atomic_t sigint;
70 static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
71 char *buff, size_t len) __pure;
72 static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
73 char *buff, size_t len) __pure;
74 static int handler_udp(int fd, const struct worker_struct *ws,
75 char *buff, size_t len) __pure;
76 static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws,
77 char *buff, size_t len) __pure;
78 static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws,
79 char *buff, size_t len) __pure;
80 static int handler_tcp(int fd, const struct worker_struct *ws,
81 char *buff, size_t len) __pure;
82 ssize_t handler_tcp_read(int fd, char *buff, size_t len);
83 static void *worker(void *self) __pure;
85 static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
86 char *buff, size_t len)
88 int dfd, keep = 1;
89 char *cbuff;
90 ssize_t rlen, err, clen;
91 struct ct_proto *hdr;
92 struct curve25519_proto *p;
93 struct sockaddr_storage naddr;
94 socklen_t nlen;
95 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
97 if (!buff || len <= off)
98 return 0;
100 memset(buff, 0, len);
101 while ((rlen = read(fd, buff + off, len - off)) > 0) {
102 dfd = -1; nlen = 0; p = NULL;
104 memset(&naddr, 0, sizeof(naddr));
106 hdr = (struct ct_proto *) buff;
107 memset(hdr, 0, sizeof(*hdr));
108 hdr->flags = 0;
110 trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr,
111 (size_t *) &nlen);
112 if (unlikely(dfd < 0 || nlen == 0)) {
113 memset(buff, 0, len);
114 continue;
117 err = get_user_by_sockaddr(&naddr, nlen, &p);
118 if (unlikely(err || !p)) {
119 memset(buff, 0, len);
120 continue;
123 clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
124 crypto_box_zerobytes), (rlen +
125 crypto_box_zerobytes), (unsigned char **)
126 &cbuff);
127 if (unlikely(clen <= 0)) {
128 memset(buff, 0, len);
129 continue;
132 hdr->payload = htons((uint16_t) clen);
134 set_udp_cork(dfd);
136 sendto(dfd, hdr, sizeof(struct ct_proto), 0, (struct sockaddr *)
137 &naddr, nlen);
138 sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr, nlen);
140 set_udp_uncork(dfd);
142 memset(buff, 0, len);
145 return keep;
148 static void handler_udp_notify_close(int fd, struct sockaddr_storage *addr)
150 struct ct_proto hdr;
152 memset(&hdr, 0, sizeof(hdr));
153 hdr.flags |= PROTO_FLAG_EXIT;
154 hdr.payload = 0;
156 sendto(fd, &hdr, sizeof(hdr), 0, (struct sockaddr *) addr,
157 sizeof(*addr));
160 static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
161 char *buff, size_t len)
163 int keep = 1;
164 char *cbuff;
165 ssize_t rlen, err, clen;
166 struct ct_proto *hdr;
167 struct curve25519_proto *p;
168 struct sockaddr_storage naddr;
169 socklen_t nlen = sizeof(naddr);
171 if (!buff || !len)
172 return 0;
174 memset(&naddr, 0, sizeof(naddr));
175 while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr,
176 &nlen)) > 0) {
177 p = NULL;
179 hdr = (struct ct_proto *) buff;
181 if (unlikely(rlen < sizeof(struct ct_proto)))
182 goto close;
183 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
184 goto close;
185 if (unlikely(ntohs(hdr->payload) == 0))
186 goto close;
187 if (hdr->flags & PROTO_FLAG_EXIT) {
188 close:
189 remove_user_by_sockaddr(&naddr, nlen);
190 trie_addr_remove_addr(&naddr, nlen);
191 handler_udp_notify_close(fd, &naddr);
193 return keep;
195 if (hdr->flags & PROTO_FLAG_INIT) {
196 syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
197 "from remote end!\n");
199 if (unlikely(rlen - sizeof(*hdr) <
200 sizeof(struct username_struct)))
201 goto close;
203 err = try_register_user_by_sockaddr(ws->c,
204 buff + sizeof(struct ct_proto),
205 rlen - sizeof(struct ct_proto),
206 &naddr, nlen, auth_log);
207 if (unlikely(err))
208 goto close;
210 goto next;
213 err = get_user_by_sockaddr(&naddr, nlen, &p);
214 if (unlikely(err || !p))
215 goto close;
217 clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
218 sizeof(struct ct_proto),
219 rlen - sizeof(struct ct_proto),
220 (unsigned char **) &cbuff, NULL);
221 if (unlikely(clen <= 0))
222 goto close;
224 cbuff += crypto_box_zerobytes;
225 clen -= crypto_box_zerobytes;
227 err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
228 fd, &naddr, nlen);
229 if (unlikely(err))
230 goto next;
232 err = write(ws->parent.tunfd, cbuff, clen);
233 next:
234 nlen = sizeof(naddr);
235 memset(&naddr, 0, sizeof(naddr));
238 return keep;
241 static int handler_udp(int fd, const struct worker_struct *ws,
242 char *buff, size_t len)
244 int ret = 0;
246 if (fd == ws->parent.tunfd)
247 ret = handler_udp_tun_to_net(fd, ws, buff, len);
248 else
249 ret = handler_udp_net_to_tun(fd, ws, buff, len);
251 return ret;
254 static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws,
255 char *buff, size_t len)
257 int dfd, keep = 1;
258 char *cbuff;
259 ssize_t rlen, err, clen;
260 struct ct_proto *hdr;
261 struct curve25519_proto *p;
262 socklen_t nlen;
263 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
265 if (!buff || len <= off)
266 return 0;
268 memset(buff, 0, len);
269 while ((rlen = read(fd, buff + off, len - off)) > 0) {
270 dfd = -1; p = NULL;
272 hdr = (struct ct_proto *) buff;
273 memset(hdr, 0, sizeof(*hdr));
274 hdr->flags = 0;
276 trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, NULL,
277 (size_t *) &nlen);
278 if (unlikely(dfd < 0)) {
279 memset(buff, 0, len);
280 continue;
283 err = get_user_by_socket(dfd, &p);
284 if (unlikely(err || !p)) {
285 memset(buff, 0, len);
286 continue;
289 clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
290 crypto_box_zerobytes), (rlen +
291 crypto_box_zerobytes), (unsigned char **)
292 &cbuff);
293 if (unlikely(clen <= 0)) {
294 memset(buff, 0, len);
295 continue;
298 hdr->payload = htons((uint16_t) clen);
300 set_tcp_cork(dfd);
302 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
303 write_exact(dfd, cbuff, clen, 0);
305 set_tcp_uncork(dfd);
307 memset(buff, 0, len);
310 return keep;
313 ssize_t handler_tcp_read(int fd, char *buff, size_t len)
315 ssize_t rlen;
316 struct ct_proto *hdr = (struct ct_proto *) buff;
318 if (!buff || !len)
319 return 0;
321 /* May exit on EAGAIN if 0 Byte read */
322 rlen = read_exact(fd, buff, sizeof(struct ct_proto), 1);
323 if (rlen < 0)
324 return rlen;
325 if (unlikely(ntohs(hdr->payload) > len - sizeof(struct ct_proto))) {
326 errno = ENOMEM;
327 return 1; /* Force server to close connection */
330 /* May not exit on EAGAIN if 0 Byte read */
331 rlen = read_exact(fd, buff + sizeof(struct ct_proto),
332 ntohs(hdr->payload), 0);
333 if (rlen < 0)
334 return rlen;
336 return sizeof(struct ct_proto) + rlen;
339 static void handler_tcp_notify_close(int fd)
341 struct ct_proto hdr;
343 memset(&hdr, 0, sizeof(hdr));
344 hdr.flags |= PROTO_FLAG_EXIT;
345 hdr.payload = 0;
347 if (write(fd, &hdr, sizeof(hdr))) { ; }
350 static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws,
351 char *buff, size_t len)
353 int keep = 1, count = 0;
354 char *cbuff;
355 ssize_t rlen, err, clen;
356 struct ct_proto *hdr;
357 struct curve25519_proto *p;
359 if (!buff || !len)
360 return 0;
362 while ((rlen = handler_tcp_read(fd, buff, len)) > 0) {
363 p = NULL;
365 hdr = (struct ct_proto *) buff;
367 if (unlikely(rlen < sizeof(struct ct_proto)))
368 goto close;
369 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
370 goto close;
371 if (unlikely(ntohs(hdr->payload) == 0))
372 goto close;
373 if (hdr->flags & PROTO_FLAG_EXIT) {
374 close:
375 remove_user_by_socket(fd);
376 trie_addr_remove(fd);
377 handler_tcp_notify_close(fd);
378 rlen = write(ws->parent.efd, &fd, sizeof(fd));
380 keep = 0;
381 return keep;
383 if (hdr->flags & PROTO_FLAG_INIT) {
384 syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
385 "from remote end!\n");
387 if (unlikely(rlen - sizeof(*hdr) <
388 sizeof(struct username_struct)))
389 goto close;
391 err = try_register_user_by_socket(ws->c,
392 buff + sizeof(struct ct_proto),
393 rlen - sizeof(struct ct_proto),
394 fd, auth_log);
395 if (unlikely(err))
396 goto close;
398 continue;
401 err = get_user_by_socket(fd, &p);
402 if (unlikely(err || !p))
403 continue;
405 clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
406 sizeof(struct ct_proto),
407 rlen - sizeof(struct ct_proto),
408 (unsigned char **) &cbuff, NULL);
409 if (unlikely(clen <= 0))
410 continue;
412 cbuff += crypto_box_zerobytes;
413 clen -= crypto_box_zerobytes;
415 err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
416 fd, NULL, 0);
417 if (unlikely(err))
418 continue;
420 err = write(ws->parent.tunfd, cbuff, clen);
422 count++;
423 if (count == 10) {
424 write_exact(ws->efd[1], &fd, sizeof(fd), 1);
425 /* Read later next data and let others process */
426 return keep;
430 return keep;
433 static int handler_tcp(int fd, const struct worker_struct *ws,
434 char *buff, size_t len)
436 int ret = 0;
438 if (fd == ws->parent.tunfd)
439 ret = handler_tcp_tun_to_net(fd, ws, buff, len);
440 else
441 ret = handler_tcp_net_to_tun(fd, ws, buff, len);
443 return ret;
446 static void *worker(void *self)
448 int fd, old_state;
449 ssize_t ret;
450 size_t blen = TUNBUFF_SIZ; //FIXME
451 struct worker_struct *ws = self;
452 struct pollfd fds;
453 char *buff;
455 fds.fd = ws->efd[0];
456 fds.events = POLLIN;
458 ws->c = curve25519_tfm_alloc();
459 buff = xmalloc_aligned(blen, 64);
461 syslog(LOG_INFO, "curvetun thread on CPU%u up!\n", ws->cpu);
463 pthread_cleanup_push(curve25519_tfm_free_void, ws->c);
464 pthread_cleanup_push(xfree_func, buff);
466 while (likely(!sigint)) {
467 poll(&fds, 1, -1);
468 if ((fds.revents & POLLIN) != POLLIN)
469 continue;
471 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
473 while ((ret = read_exact(ws->efd[0], &fd, sizeof(fd), 1)) > 0) {
474 if (ret != sizeof(fd)) {
475 sched_yield();
476 continue;
479 ret = ws->handler(fd, ws, buff, blen);
480 if (ret)
481 write_exact(ws->parent.refd, &fd, sizeof(fd), 1);
484 pthread_setcancelstate(old_state, NULL);
487 syslog(LOG_INFO, "curvetun thread on CPU%u down!\n", ws->cpu);
489 pthread_cleanup_pop(1);
490 pthread_cleanup_pop(1);
492 pthread_exit((void *) ((long) ws->cpu));
495 static void thread_spawn_or_panic(unsigned int cpus, int efd, int refd,
496 int tunfd, int ipv4, int udp)
498 int i, ret;
499 cpu_set_t cpuset;
500 unsigned int threads;
502 threads = cpus * THREADS_PER_CPU;
504 for (i = 0; i < threads; ++i) {
505 CPU_ZERO(&cpuset);
506 threadpool[i].cpu = i % cpus;
507 CPU_SET(threadpool[i].cpu, &cpuset);
509 ret = pipe2(threadpool[i].efd, O_NONBLOCK);
510 if (ret < 0)
511 syslog_panic("Cannot create event socket!\n");
513 threadpool[i].c = xmalloc_aligned(sizeof(*threadpool[i].c), 64);
514 threadpool[i].parent.efd = efd;
515 threadpool[i].parent.refd = refd;
516 threadpool[i].parent.tunfd = tunfd;
517 threadpool[i].parent.ipv4 = ipv4;
518 threadpool[i].parent.udp = udp;
519 threadpool[i].handler = udp ? handler_udp : handler_tcp;
521 ret = pthread_create(&threadpool[i].trid, NULL,
522 worker, &threadpool[i]);
523 if (ret < 0)
524 syslog_panic("Thread creation failed!\n");
526 ret = pthread_setaffinity_np(threadpool[i].trid,
527 sizeof(cpuset), &cpuset);
528 if (ret < 0)
529 syslog_panic("Thread CPU migration failed!\n");
531 pthread_detach(threadpool[i].trid);
534 sleep(1);
537 static void thread_finish(unsigned int cpus)
539 int i;
540 unsigned int threads;
542 threads = cpus * THREADS_PER_CPU;
544 for (i = 0; i < threads; ++i) {
545 while (pthread_join(threadpool[i].trid, NULL) < 0)
548 close(threadpool[i].efd[0]);
549 close(threadpool[i].efd[1]);
553 int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log)
555 int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i;
556 unsigned int cpus = 0, threads, udp_cpu = 0;
557 ssize_t ret;
558 struct epoll_event *events;
559 struct addrinfo hints, *ahead, *ai;
561 auth_log = !!log;
562 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
564 syslog(LOG_INFO, "curvetun server booting!\n");
565 syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n");
567 parse_userfile_and_generate_user_store_or_die(home);
569 memset(&hints, 0, sizeof(hints));
570 hints.ai_family = PF_UNSPEC;
571 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
572 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
573 hints.ai_flags = AI_PASSIVE;
575 ret = getaddrinfo(NULL, port, &hints, &ahead);
576 if (ret < 0)
577 syslog_panic("Cannot get address info!\n");
579 for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) {
580 lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
581 if (lfd < 0)
582 continue;
583 if (ai->ai_family == AF_INET6) {
584 #ifdef IPV6_V6ONLY
585 ret = set_ipv6_only(lfd);
586 if (ret < 0) {
587 close(lfd);
588 lfd = -1;
589 continue;
591 #else
592 close(lfd);
593 lfd = -1;
594 continue;
595 #endif /* IPV6_V6ONLY */
598 set_reuseaddr(lfd);
599 set_mtu_disc_dont(lfd);
601 ret = bind(lfd, ai->ai_addr, ai->ai_addrlen);
602 if (ret < 0) {
603 close(lfd);
604 lfd = -1;
605 continue;
608 if (!udp) {
609 ret = listen(lfd, 5);
610 if (ret < 0) {
611 close(lfd);
612 lfd = -1;
613 continue;
617 if (ipv4 == -1) {
618 ipv4 = (ai->ai_family == AF_INET6 ? 0 :
619 (ai->ai_family == AF_INET ? 1 : -1));
622 syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s "
623 "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6,
624 udp ? "UDP" : "TCP", port);
625 syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is "
626 "IPv%d!\n", ipv4 ? 4 : 6);
629 freeaddrinfo(ahead);
631 if (lfd < 0 || ipv4 < 0)
632 syslog_panic("Cannot create socket!\n");
634 tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI);
636 pipe_or_die(efd, O_NONBLOCK);
637 pipe_or_die(refd, O_NONBLOCK);
639 set_nonblocking(lfd);
641 events = xcalloc(MAX_EPOLL_SIZE, sizeof(*events));
642 for (i = 0; i < MAX_EPOLL_SIZE; ++i)
643 events[i].data.fd = -1;
645 kdpfd = epoll_create(MAX_EPOLL_SIZE);
646 if (kdpfd < 0)
647 syslog_panic("Cannot create socket!\n");
649 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd,
650 udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN);
651 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN);
652 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN);
653 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd,
654 EPOLLIN | EPOLLET | EPOLLONESHOT);
655 curfds = 4;
657 trie_init();
659 cpus = get_number_cpus_online();
660 threads = cpus * THREADS_PER_CPU;
661 if (!ispow2(threads))
662 syslog_panic("Thread number not power of two!\n");
664 threadpool = xcalloc(threads, sizeof(*threadpool));
665 thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp);
667 init_cpusched(threads);
669 register_socket(tunfd);
670 register_socket(lfd);
672 syslog(LOG_INFO, "curvetun up and running!\n");
674 while (likely(!sigint)) {
675 nfds = epoll_wait(kdpfd, events, curfds, -1);
676 if (nfds < 0) {
677 syslog(LOG_ERR, "epoll_wait error: %s\n",
678 strerror(errno));
679 break;
682 for (i = 0; i < nfds; ++i) {
683 if (unlikely(events[i].data.fd < 0))
684 continue;
686 if (events[i].data.fd == lfd && !udp) {
687 int ncpu;
688 char hbuff[256], sbuff[256];
689 struct sockaddr_storage taddr;
690 socklen_t tlen;
692 tlen = sizeof(taddr);
693 nfd = accept(lfd, (struct sockaddr *) &taddr,
694 &tlen);
695 if (nfd < 0) {
696 syslog(LOG_ERR, "accept error: %s\n",
697 strerror(errno));
698 continue;
701 if (curfds + 1 > MAX_EPOLL_SIZE) {
702 close(nfd);
703 continue;
706 curfds++;
708 ncpu = register_socket(nfd);
710 memset(hbuff, 0, sizeof(hbuff));
711 memset(sbuff, 0, sizeof(sbuff));
712 getnameinfo((struct sockaddr *) &taddr, tlen,
713 hbuff, sizeof(hbuff),
714 sbuff, sizeof(sbuff),
715 NI_NUMERICHOST | NI_NUMERICSERV);
717 syslog_maybe(auth_log, LOG_INFO, "New connection "
718 "from %s:%s (%d active client connections) - id %d on CPU%d",
719 hbuff, sbuff, curfds-4, nfd, ncpu);
721 set_nonblocking(nfd);
722 set_socket_keepalive(nfd);
723 set_tcp_nodelay(nfd);
724 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD,
725 nfd, EPOLLIN | EPOLLET | EPOLLONESHOT);
726 if (ret < 0) {
727 close(nfd);
728 curfds--;
729 continue;
731 } else if (events[i].data.fd == refd[0]) {
732 int fd_one;
734 ret = read_exact(refd[0], &fd_one,
735 sizeof(fd_one), 1);
736 if (ret != sizeof(fd_one) || fd_one <= 0)
737 continue;
739 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD,
740 fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT);
741 if (ret < 0) {
742 close(fd_one);
743 continue;
745 } else if (events[i].data.fd == efd[0]) {
746 int fd_del, test;
748 ret = read_exact(efd[0], &fd_del,
749 sizeof(fd_del), 1);
750 if (ret != sizeof(fd_del) || fd_del <= 0)
751 continue;
753 ret = read(fd_del, &test, sizeof(test));
754 if (ret < 0 && errno == EBADF)
755 continue;
757 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL,
758 fd_del, 0);
759 if (ret < 0) {
760 close(fd_del);
761 continue;
764 close(fd_del);
765 curfds--;
766 unregister_socket(fd_del);
768 syslog_maybe(auth_log, LOG_INFO, "Closed connection "
769 "with id %d (%d active client connections remain)\n", fd_del,
770 curfds-4);
771 } else {
772 int cpu, fd_work = events[i].data.fd;
774 if (!udp)
775 cpu = socket_to_cpu(fd_work);
776 else
777 udp_cpu = (udp_cpu + 1) & (threads - 1);
779 write_exact(threadpool[udp ? udp_cpu : cpu].efd[1],
780 &fd_work, sizeof(fd_work), 1);
785 syslog(LOG_INFO, "curvetun prepare shut down!\n");
787 close(lfd);
788 close(efd[0]);
789 close(efd[1]);
790 close(refd[0]);
791 close(refd[1]);
792 close(tunfd);
794 thread_finish(cpus);
796 xfree(threadpool);
797 xfree(events);
799 unregister_socket(lfd);
800 unregister_socket(tunfd);
802 destroy_cpusched();
804 trie_cleanup();
806 destroy_user_store();
808 syslog(LOG_INFO, "curvetun shut down!\n");
809 closelog();
811 return 0;