Merge pull request #59 from electronjoe/graceful-SIGTERM-handling
[netsniff-ng-old.git] / ct_server.c
blob045472ec1d0ac2bd7d35ff7dfe28c85346b47fc7
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 "xio.h"
34 #include "xmalloc.h"
35 #include "curvetun.h"
36 #include "curve.h"
37 #include "built_in.h"
38 #include "ct_usermgmt.h"
39 #include "cpusched.h"
40 #include "trie.h"
42 struct parent_info {
43 int efd;
44 int refd;
45 int tunfd;
46 int ipv4;
47 int udp;
50 struct worker_struct {
51 pthread_t trid;
52 int efd[2];
53 unsigned int cpu;
54 struct parent_info parent;
55 int (*handler)(int fd, const struct worker_struct *ws,
56 char *buff, size_t len);
57 struct curve25519_struct *c;
60 static struct worker_struct *threadpool = NULL;
62 static int auth_log = 1;
64 extern volatile sig_atomic_t sigint;
66 static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
67 char *buff, size_t len) __pure;
68 static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
69 char *buff, size_t len) __pure;
70 static int handler_udp(int fd, const struct worker_struct *ws,
71 char *buff, size_t len) __pure;
72 static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws,
73 char *buff, size_t len) __pure;
74 static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws,
75 char *buff, size_t len) __pure;
76 static int handler_tcp(int fd, const struct worker_struct *ws,
77 char *buff, size_t len) __pure;
78 ssize_t handler_tcp_read(int fd, char *buff, size_t len);
79 static void *worker(void *self) __pure;
81 static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws,
82 char *buff, size_t len)
84 int dfd, keep = 1;
85 char *cbuff;
86 ssize_t rlen, err, clen;
87 struct ct_proto *hdr;
88 struct curve25519_proto *p;
89 struct sockaddr_storage naddr;
90 socklen_t nlen;
91 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
93 if (!buff || len <= off)
94 return 0;
96 memset(buff, 0, len);
97 while ((rlen = read(fd, buff + off, len - off)) > 0) {
98 dfd = -1; nlen = 0; p = NULL;
100 memset(&naddr, 0, sizeof(naddr));
102 hdr = (struct ct_proto *) buff;
103 memset(hdr, 0, sizeof(*hdr));
104 hdr->flags = 0;
106 trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr,
107 (size_t *) &nlen);
108 if (unlikely(dfd < 0 || nlen == 0)) {
109 memset(buff, 0, len);
110 continue;
113 err = get_user_by_sockaddr(&naddr, nlen, &p);
114 if (unlikely(err || !p)) {
115 memset(buff, 0, len);
116 continue;
119 clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
120 crypto_box_zerobytes), (rlen +
121 crypto_box_zerobytes), (unsigned char **)
122 &cbuff);
123 if (unlikely(clen <= 0)) {
124 memset(buff, 0, len);
125 continue;
128 hdr->payload = htons((uint16_t) clen);
130 set_udp_cork(dfd);
132 sendto(dfd, hdr, sizeof(struct ct_proto), 0, (struct sockaddr *)
133 &naddr, nlen);
134 sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr, nlen);
136 set_udp_uncork(dfd);
138 memset(buff, 0, len);
141 return keep;
144 static void handler_udp_notify_close(int fd, struct sockaddr_storage *addr)
146 struct ct_proto hdr;
148 memset(&hdr, 0, sizeof(hdr));
149 hdr.flags |= PROTO_FLAG_EXIT;
150 hdr.payload = 0;
152 sendto(fd, &hdr, sizeof(hdr), 0, (struct sockaddr *) addr,
153 sizeof(*addr));
156 static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws,
157 char *buff, size_t len)
159 int keep = 1;
160 char *cbuff;
161 ssize_t rlen, err, clen;
162 struct ct_proto *hdr;
163 struct curve25519_proto *p;
164 struct sockaddr_storage naddr;
165 socklen_t nlen = sizeof(naddr);
167 if (!buff || !len)
168 return 0;
170 memset(&naddr, 0, sizeof(naddr));
171 while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr,
172 &nlen)) > 0) {
173 p = NULL;
175 hdr = (struct ct_proto *) buff;
177 if (unlikely(rlen < sizeof(struct ct_proto)))
178 goto close;
179 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
180 goto close;
181 if (unlikely(ntohs(hdr->payload) == 0))
182 goto close;
183 if (hdr->flags & PROTO_FLAG_EXIT) {
184 close:
185 remove_user_by_sockaddr(&naddr, nlen);
186 trie_addr_remove_addr(&naddr, nlen);
187 handler_udp_notify_close(fd, &naddr);
189 return keep;
191 if (hdr->flags & PROTO_FLAG_INIT) {
192 syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
193 "from remote end!\n");
195 if (unlikely(rlen - sizeof(*hdr) <
196 sizeof(struct username_struct)))
197 goto close;
199 err = try_register_user_by_sockaddr(ws->c,
200 buff + sizeof(struct ct_proto),
201 rlen - sizeof(struct ct_proto),
202 &naddr, nlen, auth_log);
203 if (unlikely(err))
204 goto close;
206 goto next;
209 err = get_user_by_sockaddr(&naddr, nlen, &p);
210 if (unlikely(err || !p))
211 goto close;
213 clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
214 sizeof(struct ct_proto),
215 rlen - sizeof(struct ct_proto),
216 (unsigned char **) &cbuff, NULL);
217 if (unlikely(clen <= 0))
218 goto close;
220 cbuff += crypto_box_zerobytes;
221 clen -= crypto_box_zerobytes;
223 err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
224 fd, &naddr, nlen);
225 if (unlikely(err))
226 goto next;
228 err = write(ws->parent.tunfd, cbuff, clen);
229 next:
230 nlen = sizeof(naddr);
231 memset(&naddr, 0, sizeof(naddr));
234 return keep;
237 static int handler_udp(int fd, const struct worker_struct *ws,
238 char *buff, size_t len)
240 int ret = 0;
242 if (fd == ws->parent.tunfd)
243 ret = handler_udp_tun_to_net(fd, ws, buff, len);
244 else
245 ret = handler_udp_net_to_tun(fd, ws, buff, len);
247 return ret;
250 static int handler_tcp_tun_to_net(int fd, const struct worker_struct *ws,
251 char *buff, size_t len)
253 int dfd, keep = 1;
254 char *cbuff;
255 ssize_t rlen, err, clen;
256 struct ct_proto *hdr;
257 struct curve25519_proto *p;
258 socklen_t nlen;
259 size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes;
261 if (!buff || len <= off)
262 return 0;
264 memset(buff, 0, len);
265 while ((rlen = read(fd, buff + off, len - off)) > 0) {
266 dfd = -1; p = NULL;
268 hdr = (struct ct_proto *) buff;
269 memset(hdr, 0, sizeof(*hdr));
270 hdr->flags = 0;
272 trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, NULL,
273 (size_t *) &nlen);
274 if (unlikely(dfd < 0)) {
275 memset(buff, 0, len);
276 continue;
279 err = get_user_by_socket(dfd, &p);
280 if (unlikely(err || !p)) {
281 memset(buff, 0, len);
282 continue;
285 clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off -
286 crypto_box_zerobytes), (rlen +
287 crypto_box_zerobytes), (unsigned char **)
288 &cbuff);
289 if (unlikely(clen <= 0)) {
290 memset(buff, 0, len);
291 continue;
294 hdr->payload = htons((uint16_t) clen);
296 set_tcp_cork(dfd);
298 write_exact(dfd, hdr, sizeof(struct ct_proto), 0);
299 write_exact(dfd, cbuff, clen, 0);
301 set_tcp_uncork(dfd);
303 memset(buff, 0, len);
306 return keep;
309 ssize_t handler_tcp_read(int fd, char *buff, size_t len)
311 ssize_t rlen;
312 struct ct_proto *hdr = (struct ct_proto *) buff;
314 if (!buff || !len)
315 return 0;
317 /* May exit on EAGAIN if 0 Byte read */
318 rlen = read_exact(fd, buff, sizeof(struct ct_proto), 1);
319 if (rlen < 0)
320 return rlen;
321 if (unlikely(ntohs(hdr->payload) > len - sizeof(struct ct_proto))) {
322 errno = ENOMEM;
323 return 1; /* Force server to close connection */
326 /* May not exit on EAGAIN if 0 Byte read */
327 rlen = read_exact(fd, buff + sizeof(struct ct_proto),
328 ntohs(hdr->payload), 0);
329 if (rlen < 0)
330 return rlen;
332 return sizeof(struct ct_proto) + rlen;
335 static void handler_tcp_notify_close(int fd)
337 struct ct_proto hdr;
339 memset(&hdr, 0, sizeof(hdr));
340 hdr.flags |= PROTO_FLAG_EXIT;
341 hdr.payload = 0;
343 if (write(fd, &hdr, sizeof(hdr))) { ; }
346 static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws,
347 char *buff, size_t len)
349 int keep = 1, count = 0;
350 char *cbuff;
351 ssize_t rlen, err, clen;
352 struct ct_proto *hdr;
353 struct curve25519_proto *p;
355 if (!buff || !len)
356 return 0;
358 while ((rlen = handler_tcp_read(fd, buff, len)) > 0) {
359 p = NULL;
361 hdr = (struct ct_proto *) buff;
363 if (unlikely(rlen < sizeof(struct ct_proto)))
364 goto close;
365 if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload)))
366 goto close;
367 if (unlikely(ntohs(hdr->payload) == 0))
368 goto close;
369 if (hdr->flags & PROTO_FLAG_EXIT) {
370 close:
371 remove_user_by_socket(fd);
372 trie_addr_remove(fd);
373 handler_tcp_notify_close(fd);
374 rlen = write(ws->parent.efd, &fd, sizeof(fd));
376 keep = 0;
377 return keep;
379 if (hdr->flags & PROTO_FLAG_INIT) {
380 syslog_maybe(auth_log, LOG_INFO, "Got initial userhash "
381 "from remote end!\n");
383 if (unlikely(rlen - sizeof(*hdr) <
384 sizeof(struct username_struct)))
385 goto close;
387 err = try_register_user_by_socket(ws->c,
388 buff + sizeof(struct ct_proto),
389 rlen - sizeof(struct ct_proto),
390 fd, auth_log);
391 if (unlikely(err))
392 goto close;
394 continue;
397 err = get_user_by_socket(fd, &p);
398 if (unlikely(err || !p))
399 continue;
401 clen = curve25519_decode(ws->c, p, (unsigned char *) buff +
402 sizeof(struct ct_proto),
403 rlen - sizeof(struct ct_proto),
404 (unsigned char **) &cbuff, NULL);
405 if (unlikely(clen <= 0))
406 continue;
408 cbuff += crypto_box_zerobytes;
409 clen -= crypto_box_zerobytes;
411 err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4,
412 fd, NULL, 0);
413 if (unlikely(err))
414 continue;
416 err = write(ws->parent.tunfd, cbuff, clen);
418 count++;
419 if (count == 10) {
420 write_exact(ws->efd[1], &fd, sizeof(fd), 1);
421 /* Read later next data and let others process */
422 return keep;
426 return keep;
429 static int handler_tcp(int fd, const struct worker_struct *ws,
430 char *buff, size_t len)
432 int ret = 0;
434 if (fd == ws->parent.tunfd)
435 ret = handler_tcp_tun_to_net(fd, ws, buff, len);
436 else
437 ret = handler_tcp_net_to_tun(fd, ws, buff, len);
439 return ret;
442 static void *worker(void *self)
444 int fd, old_state;
445 ssize_t ret;
446 size_t blen = TUNBUFF_SIZ; //FIXME
447 const struct worker_struct *ws = self;
448 struct pollfd fds;
449 char *buff;
451 fds.fd = ws->efd[0];
452 fds.events = POLLIN;
454 curve25519_alloc_or_maybe_die(ws->c);
456 buff = xmalloc_aligned(blen, 64);
458 syslog(LOG_INFO, "curvetun thread on CPU%u up!\n", ws->cpu);
460 pthread_cleanup_push(xfree_func, ws->c);
461 pthread_cleanup_push(curve25519_free, ws->c);
462 pthread_cleanup_push(xfree_func, buff);
464 while (likely(!sigint)) {
465 poll(&fds, 1, -1);
466 if ((fds.revents & POLLIN) != POLLIN)
467 continue;
469 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
471 while ((ret = read_exact(ws->efd[0], &fd, sizeof(fd), 1)) > 0) {
472 if (ret != sizeof(fd)) {
473 sched_yield();
474 continue;
477 ret = ws->handler(fd, ws, buff, blen);
478 if (ret)
479 write_exact(ws->parent.refd, &fd, sizeof(fd), 1);
482 pthread_setcancelstate(old_state, NULL);
485 syslog(LOG_INFO, "curvetun thread on CPU%u down!\n", ws->cpu);
487 pthread_cleanup_pop(1);
488 pthread_cleanup_pop(1);
489 pthread_cleanup_pop(1);
491 pthread_exit((void *) ((long) ws->cpu));
494 static void thread_spawn_or_panic(unsigned int cpus, int efd, int refd,
495 int tunfd, int ipv4, int udp)
497 int i, ret;
498 cpu_set_t cpuset;
499 unsigned int threads;
501 threads = cpus * THREADS_PER_CPU;
503 for (i = 0; i < threads; ++i) {
504 CPU_ZERO(&cpuset);
505 threadpool[i].cpu = i % cpus;
506 CPU_SET(threadpool[i].cpu, &cpuset);
508 ret = pipe2(threadpool[i].efd, O_NONBLOCK);
509 if (ret < 0)
510 syslog_panic("Cannot create event socket!\n");
512 threadpool[i].c = xmalloc_aligned(sizeof(*threadpool[i].c), 64);
513 threadpool[i].parent.efd = efd;
514 threadpool[i].parent.refd = refd;
515 threadpool[i].parent.tunfd = tunfd;
516 threadpool[i].parent.ipv4 = ipv4;
517 threadpool[i].parent.udp = udp;
518 threadpool[i].handler = udp ? handler_udp : handler_tcp;
520 ret = pthread_create(&threadpool[i].trid, NULL,
521 worker, &threadpool[i]);
522 if (ret < 0)
523 syslog_panic("Thread creation failed!\n");
525 ret = pthread_setaffinity_np(threadpool[i].trid,
526 sizeof(cpuset), &cpuset);
527 if (ret < 0)
528 syslog_panic("Thread CPU migration failed!\n");
530 pthread_detach(threadpool[i].trid);
533 sleep(1);
536 static void thread_finish(unsigned int cpus)
538 int i;
539 unsigned int threads;
541 threads = cpus * THREADS_PER_CPU;
543 for (i = 0; i < threads; ++i) {
544 while (pthread_join(threadpool[i].trid, NULL) < 0)
547 close(threadpool[i].efd[0]);
548 close(threadpool[i].efd[1]);
552 int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log)
554 int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i;
555 unsigned int cpus = 0, threads, udp_cpu = 0;
556 ssize_t ret;
557 struct epoll_event *events;
558 struct addrinfo hints, *ahead, *ai;
560 auth_log = !!log;
561 openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
563 syslog(LOG_INFO, "curvetun server booting!\n");
564 syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n");
566 parse_userfile_and_generate_user_store_or_die(home);
568 memset(&hints, 0, sizeof(hints));
569 hints.ai_family = PF_UNSPEC;
570 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
571 hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
572 hints.ai_flags = AI_PASSIVE;
574 ret = getaddrinfo(NULL, port, &hints, &ahead);
575 if (ret < 0)
576 syslog_panic("Cannot get address info!\n");
578 for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) {
579 lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
580 if (lfd < 0)
581 continue;
582 if (ai->ai_family == AF_INET6) {
583 #ifdef IPV6_V6ONLY
584 ret = set_ipv6_only(lfd);
585 if (ret < 0) {
586 close(lfd);
587 lfd = -1;
588 continue;
590 #else
591 close(lfd);
592 lfd = -1;
593 continue;
594 #endif /* IPV6_V6ONLY */
597 set_reuseaddr(lfd);
598 set_mtu_disc_dont(lfd);
600 ret = bind(lfd, ai->ai_addr, ai->ai_addrlen);
601 if (ret < 0) {
602 close(lfd);
603 lfd = -1;
604 continue;
607 if (!udp) {
608 ret = listen(lfd, 5);
609 if (ret < 0) {
610 close(lfd);
611 lfd = -1;
612 continue;
616 if (ipv4 == -1) {
617 ipv4 = (ai->ai_family == AF_INET6 ? 0 :
618 (ai->ai_family == AF_INET ? 1 : -1));
621 syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s "
622 "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6,
623 udp ? "UDP" : "TCP", port);
624 syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is "
625 "IPv%d!\n", ipv4 ? 4 : 6);
628 freeaddrinfo(ahead);
630 if (lfd < 0 || ipv4 < 0)
631 syslog_panic("Cannot create socket!\n");
633 tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI);
635 pipe_or_die(efd, O_NONBLOCK);
636 pipe_or_die(refd, O_NONBLOCK);
638 set_nonblocking(lfd);
640 events = xzmalloc(MAX_EPOLL_SIZE * sizeof(*events));
641 for (i = 0; i < MAX_EPOLL_SIZE; ++i)
642 events[i].data.fd = -1;
644 kdpfd = epoll_create(MAX_EPOLL_SIZE);
645 if (kdpfd < 0)
646 syslog_panic("Cannot create socket!\n");
648 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd,
649 udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN);
650 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN);
651 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN);
652 set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd,
653 EPOLLIN | EPOLLET | EPOLLONESHOT);
654 curfds = 4;
656 trie_init();
658 cpus = get_number_cpus_online();
659 threads = cpus * THREADS_PER_CPU;
660 if (!ispow2(threads))
661 syslog_panic("Thread number not power of two!\n");
663 threadpool = xzmalloc(sizeof(*threadpool) * threads);
664 thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp);
666 init_cpusched(threads);
668 register_socket(tunfd);
669 register_socket(lfd);
671 syslog(LOG_INFO, "curvetun up and running!\n");
673 while (likely(!sigint)) {
674 nfds = epoll_wait(kdpfd, events, curfds, -1);
675 if (nfds < 0) {
676 syslog(LOG_ERR, "epoll_wait error: %s\n",
677 strerror(errno));
678 break;
681 for (i = 0; i < nfds; ++i) {
682 if (unlikely(events[i].data.fd < 0))
683 continue;
685 if (events[i].data.fd == lfd && !udp) {
686 int ncpu;
687 char hbuff[256], sbuff[256];
688 struct sockaddr_storage taddr;
689 socklen_t tlen;
691 tlen = sizeof(taddr);
692 nfd = accept(lfd, (struct sockaddr *) &taddr,
693 &tlen);
694 if (nfd < 0) {
695 syslog(LOG_ERR, "accept error: %s\n",
696 strerror(errno));
697 continue;
700 if (curfds + 1 > MAX_EPOLL_SIZE) {
701 close(nfd);
702 continue;
705 curfds++;
707 ncpu = register_socket(nfd);
709 memset(hbuff, 0, sizeof(hbuff));
710 memset(sbuff, 0, sizeof(sbuff));
711 getnameinfo((struct sockaddr *) &taddr, tlen,
712 hbuff, sizeof(hbuff),
713 sbuff, sizeof(sbuff),
714 NI_NUMERICHOST | NI_NUMERICSERV);
716 syslog_maybe(auth_log, LOG_INFO, "New connection "
717 "from %s:%s (%d active client connections) - id %d on CPU%d",
718 hbuff, sbuff, curfds-4, nfd, ncpu);
720 set_nonblocking(nfd);
721 set_socket_keepalive(nfd);
722 set_tcp_nodelay(nfd);
723 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD,
724 nfd, EPOLLIN | EPOLLET | EPOLLONESHOT);
725 if (ret < 0) {
726 close(nfd);
727 curfds--;
728 continue;
730 } else if (events[i].data.fd == refd[0]) {
731 int fd_one;
733 ret = read_exact(refd[0], &fd_one,
734 sizeof(fd_one), 1);
735 if (ret != sizeof(fd_one) || fd_one <= 0)
736 continue;
738 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD,
739 fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT);
740 if (ret < 0) {
741 close(fd_one);
742 continue;
744 } else if (events[i].data.fd == efd[0]) {
745 int fd_del, test;
747 ret = read_exact(efd[0], &fd_del,
748 sizeof(fd_del), 1);
749 if (ret != sizeof(fd_del) || fd_del <= 0)
750 continue;
752 ret = read(fd_del, &test, sizeof(test));
753 if (ret < 0 && errno == EBADF)
754 continue;
756 ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL,
757 fd_del, 0);
758 if (ret < 0) {
759 close(fd_del);
760 continue;
763 close(fd_del);
764 curfds--;
765 unregister_socket(fd_del);
767 syslog_maybe(auth_log, LOG_INFO, "Closed connection "
768 "with id %d (%d active client connections remain)\n", fd_del,
769 curfds-4);
770 } else {
771 int cpu, fd_work = events[i].data.fd;
773 if (!udp)
774 cpu = socket_to_cpu(fd_work);
775 else
776 udp_cpu = (udp_cpu + 1) & (threads - 1);
778 write_exact(threadpool[udp ? udp_cpu : cpu].efd[1],
779 &fd_work, sizeof(fd_work), 1);
784 syslog(LOG_INFO, "curvetun prepare shut down!\n");
786 close(lfd);
787 close(efd[0]);
788 close(efd[1]);
789 close(refd[0]);
790 close(refd[1]);
791 close(tunfd);
793 thread_finish(cpus);
795 xfree(threadpool);
796 xfree(events);
798 unregister_socket(lfd);
799 unregister_socket(tunfd);
801 destroy_cpusched();
803 trie_cleanup();
805 destroy_user_store();
807 syslog(LOG_INFO, "curvetun shut down!\n");
808 closelog();
810 return 0;