1/*
2 This file is part of Mtproto-proxy Library.
3
4 Mtproto-proxy Library is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Mtproto-proxy Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2009-2013 Vkontakte Ltd
18 2008-2013 Nikolai Durov
19 2008-2013 Andrey Lopatin
20
21 Copyright 2014-2016 Telegram Messenger Inc
22 2016 Vitaly Valtman
23*/
24
25#include <arpa/inet.h>
26#include <assert.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <ifaddrs.h>
30#include <limits.h>
31#include <netinet/in.h>
32#include <netinet/tcp.h>
33#include <pwd.h>
34#include <signal.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/epoll.h>
39#include <sys/io.h>
40#include <sys/socket.h>
41#include <time.h>
42#include <unistd.h>
43
44#include "engine/engine.h"
45#include "net/net-events.h"
46#include "kprintf.h"
47#include "precise-time.h"
48#include "vv/vv-io.h"
49
50
51/*
52 * generic events (epoll-based) machinery
53 */
54double tot_idle_time, a_idle_time, a_idle_quotient;
55
56volatile int main_thread_interrupt_status;
57
58event_t Events[MAX_EVENTS];
59int epoll_fd;
60static long long ev_timestamp;
61
62static event_t *ev_heap[MAX_EVENTS+1];
63int ev_heap_size;
64
65long long epoll_calls;
66long long epoll_intr;
67long long event_timer_insert_ops;
68long long event_timer_remove_ops;
69
70int epoll_remove (int fd);
71
72int init_epoll (void) {
73 int fd;
74 if (epoll_fd) {
75 return 0;
76 }
77 Events[0].fd = -1;
78 fd = epoll_create (MAX_EVENTS);
79 if (fd < 0) {
80 perror ("epoll_create()");
81 return -1;
82 }
83 epoll_fd = fd;
84 assert (fd > 0);
85 return fd;
86}
87
88/* returns positive value if ev1 is greater than ev2 */
89/* since we use only "greater_ev(x,y) > 0" and "greater_ev(x,y) <= 0" compares, */
90/* it is unimportant to distinguish "x<y" and "x==y" cases */
91static int greater_ev (event_t *ev1, event_t *ev2) {
92 int x = ev1->priority - ev2->priority;
93 if (x) return x;
94 return (ev1->timestamp > ev2->timestamp) ? 1 : 0;
95}
96
97static event_t *pop_heap_head (void) {
98 int i, j, N = ev_heap_size;
99 event_t *ev, *x, *y;
100 if (!N) return 0;
101 ev = ev_heap[1];
102 assert (ev && ev->in_queue == 1);
103 ev->in_queue = 0;
104 if (!--ev_heap_size) return ev;
105 x = ev_heap[N--];
106 i = 1;
107 while (1) {
108 j = (i << 1);
109 if (j > N) break;
110 if (j < N && greater_ev (ev_heap[j], ev_heap[j+1]) > 0) j++;
111 y = ev_heap[j];
112 if (greater_ev (x, y) <= 0) break;
113 ev_heap[i] = y;
114 y->in_queue = i;
115 i = j;
116 }
117 ev_heap[i] = x;
118 x->in_queue = i;
119 return ev;
120}
121
122int remove_event_from_heap (event_t *ev, int allow_hole) {
123 int v = ev->fd, i, j, N = ev_heap_size;
124 event_t *x;
125 assert (v >= 0 && v < MAX_EVENTS && Events + v == ev);
126 i = ev->in_queue;
127 if (!i) return 0;
128 assert (i > 0 && i <= N);
129 ev->in_queue = 0;
130 do {
131 j = (i << 1);
132 if (j > N) break;
133 if (j < N && greater_ev (ev_heap[j], ev_heap[j+1]) > 0) j++;
134 ev_heap[i] = x = ev_heap[j];
135 x->in_queue = i;
136 i = j;
137 } while(1);
138 if (allow_hole) {
139 ev_heap[i] = 0;
140 return i;
141 }
142 if (i < N) {
143 ev = ev_heap[N];
144 ev_heap[N] = 0;
145 while (i > 1) {
146 j = (i >> 1);
147 x = ev_heap[j];
148 if (greater_ev (x, ev) <= 0) break;
149 ev_heap[i] = x;
150 x->in_queue = i;
151 i = j;
152 }
153 ev_heap[i] = ev;
154 ev->in_queue = i;
155 }
156 ev_heap_size--;
157 return N;
158}
159
160int put_event_into_heap (event_t *ev) {
161 int v = ev->fd, i, j;
162 event_t *x;
163 assert (v >= 0 && v < MAX_EVENTS && Events + v == ev);
164 i = ev->in_queue ? remove_event_from_heap (ev, 1) : ++ev_heap_size;
165 assert (i <= MAX_EVENTS);
166 while (i > 1) {
167 j = (i >> 1);
168 x = ev_heap[j];
169 if (greater_ev (x, ev) <= 0) break;
170 ev_heap[i] = x;
171 x->in_queue = i;
172 i = j;
173 }
174 ev_heap[i] = ev;
175 ev->in_queue = i;
176 return i;
177}
178
179int put_event_into_heap_tail (event_t *ev, int ts_delta) {
180 ev->timestamp = ev_timestamp + ts_delta;
181 return put_event_into_heap (ev);
182}
183
184int epoll_sethandler (int fd, int prio, event_handler_t handler, void *data) {
185 event_t *ev;
186 assert (fd >= 0 && fd < MAX_EVENTS);
187 ev = Events + fd;
188 if (ev->fd != fd) {
189 memset (ev, 0, sizeof (*ev));
190 ev->fd = fd;
191 }
192 assert (!ev->refcnt);
193 __sync_fetch_and_add (&ev->refcnt, 1);
194 ev->priority = prio;
195 ev->data = data;
196 ev->work = handler;
197 return 0;
198}
199
200int epoll_conv_flags (int flags) {
201 if (!flags) {
202 return 0;
203 }
204 int r = EPOLLERR;
205
206 // no need
207 // it is always set
208 //if (!(flags & EVT_NOHUP)) {
209 // r |= EPOLLHUP;
210 //}
211 if (flags & EVT_READ) {
212 r |= EPOLLIN;
213 }
214 if (flags & EVT_WRITE) {
215 r |= EPOLLOUT;
216 }
217 if (flags & EVT_SPEC) {
218 r |= EPOLLRDHUP | EPOLLPRI;
219 }
220 if (!(flags & EVT_LEVEL)) {
221 r |= EPOLLET;
222 }
223 return r;
224}
225
226int epoll_unconv_flags (int f) {
227 int r = EVT_FROM_EPOLL;
228 if (f & (EPOLLIN | EPOLLERR)) {
229 r |= EVT_READ;
230 }
231 if (f & EPOLLOUT) {
232 r |= EVT_WRITE;
233 }
234 if (f & (EPOLLRDHUP | EPOLLPRI)) {
235 r |= EVT_SPEC;
236 }
237 return r;
238}
239
240int epoll_insert (int fd, int flags) {
241 event_t *ev;
242 int ef;
243 struct epoll_event ee;
244 if (!flags) {
245 return epoll_remove (fd);
246 }
247 assert (fd >= 0 && fd < MAX_EVENTS);
248 ev = Events + fd;
249 if (ev->fd != fd) {
250 memset (ev, 0, sizeof(event_t));
251 ev->fd = fd;
252 }
253 flags &= EVT_NEW | EVT_NOHUP | EVT_LEVEL | EVT_RWX;
254 ev->ready = 0; // !!! this bugfix led to some AIO-related bugs, now fixed with the aid of C_REPARSE flag
255 if ((ev->state & (EVT_LEVEL | EVT_RWX | EVT_IN_EPOLL)) == flags + EVT_IN_EPOLL) {
256 return 0;
257 }
258 ev->state = (ev->state & ~(EVT_LEVEL | EVT_RWX)) | (flags & (EVT_LEVEL | EVT_RWX));
259 ef = epoll_conv_flags (flags);
260 if (ef != ev->epoll_state || (flags & EVT_NEW) || !(ev->state & EVT_IN_EPOLL)) {
261 ev->epoll_state = ef;
262 memset (&ee, 0, sizeof (ee));
263 ee.events = ef;
264 ee.data.fd = fd;
265
266 vkprintf (2, "epoll_mod(%d,0x%08x,%d,%d,%08x)\n", epoll_fd, ev->state, fd, ee.data.fd, ee.events);
267
268 if (epoll_ctl (epoll_fd, (ev->state & EVT_IN_EPOLL) ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &ee) < 0) {
269 vkprintf (0, "epoll_ctl(%d,0x%x,%d,%d,%08x): %m\n", epoll_fd, ev->state, fd, ee.data.fd, ee.events);
270 }
271 ev->state |= EVT_IN_EPOLL;
272 }
273 return 0;
274}
275
276int epoll_remove (int fd) {
277 event_t *ev;
278 assert (fd >= 0 && fd < MAX_EVENTS);
279 ev = Events + fd;
280 if (ev->fd != fd) { return -1; }
281 if (ev->state & EVT_IN_EPOLL) {
282 ev->state &= ~EVT_IN_EPOLL;
283 vkprintf (2, "epoll_del(%d,0x%08x,%d,%d,%08x)\n", epoll_fd, EPOLL_CTL_DEL, fd, 0, 0);
284 if (epoll_ctl (epoll_fd, EPOLL_CTL_DEL, fd, 0) < 0) {
285 perror ("epoll_ctl(DEL)");
286 }
287 }
288 return 0;
289}
290
291int epoll_close (int fd) {
292 event_t *ev;
293 assert (fd >= 0 && fd < MAX_EVENTS);
294 ev = Events + fd;
295 if (ev->fd != fd) {
296 return -1;
297 }
298 epoll_remove (fd);
299 if (ev->in_queue) {
300 remove_event_from_heap (ev, 0);
301 }
302 memset (ev, 0, sizeof (event_t));
303 ev->fd = -1;
304 return 0;
305}
306
307int thread_run_timers (void);
308int epoll_run_timers (void) {
309 return thread_run_timers ();
310}
311
312int term_signal_received (void) {
313 return signal_check_pending (SIGINT) || signal_check_pending (SIGTERM);
314}
315
316int epoll_runqueue (void) {
317 event_t *ev;
318 int res, fd, cnt = 0;
319 if (!ev_heap_size) {
320 return 0;
321 }
322
323 vkprintf (3, "epoll_runqueue: %d events\n", ev_heap_size);
324
325 ev_timestamp += 2;
326 while (ev_heap_size && (ev = ev_heap[1])->timestamp < ev_timestamp && !term_signal_received ()) {
327 pop_heap_head();
328 fd = ev->fd;
329 assert (ev == Events + fd && fd >= 0 && fd < MAX_EVENTS);
330 if (ev->work) {
331 res = ev->work(fd, ev->data, ev);
332 } else {
333 res = EVA_REMOVE;
334 }
335 if (res == EVA_REMOVE || res == EVA_DESTROY || res <= EVA_ERROR) {
336 remove_event_from_heap (ev, 0);
337 epoll_remove (ev->fd);
338 if (res == EVA_DESTROY) {
339 if (!(ev->state & EVT_CLOSED)) {
340 close (ev->fd);
341 }
342 memset (ev, 0, sizeof(event_t));
343 }
344 if (res <= EVA_FATAL) {
345 perror ("fatal");
346 exit(1);
347 }
348 } else if (res == EVA_RERUN) {
349 ev->timestamp = ev_timestamp;
350 put_event_into_heap (ev);
351 } else if (res > 0) {
352 epoll_insert (fd, res & 0xf);
353 } else if (res == EVA_CONTINUE) {
354 ev->ready = 0;
355 }
356 cnt++;
357 }
358 return cnt;
359}
360
361double last_epoll_wait_at;
362struct epoll_event new_ev_list[MAX_EVENTS];
363int epoll_sleep_ns = 0;
364
365int epoll_fetch_events (int timeout) {
366 epoll_calls ++;
367 int fd, i;
368 main_thread_interrupt_status = 1;
369 struct timespec ts;
370 ts.tv_sec = 0;
371 ts.tv_nsec = epoll_sleep_ns;
372 nanosleep (&ts, NULL);
373 int res = epoll_wait (epoll_fd, new_ev_list, MAX_EVENTS, timeout);
374 main_thread_interrupt_status = 0;
375 if (res < 0 && errno == EINTR) {
376 epoll_intr ++;
377 res = 0;
378 }
379 if (res < 0) {
380 perror ("epoll_wait()");
381 }
382 if (verbosity > 2 && res) {
383 kprintf ("epoll_wait(%d, ...) = %d\n", epoll_fd, res);
384 }
385 for (i = 0; i < res; i++) {
386 fd = new_ev_list[i].data.fd;
387 assert (fd >= 0 && fd < MAX_EVENTS);
388 event_t *ev = Events + fd;
389 assert (ev->fd == fd);
390 ev->ready |= epoll_unconv_flags (ev->epoll_ready = new_ev_list[i].events);
391 ev->timestamp = ev_timestamp;
392 put_event_into_heap (ev);
393 }
394 return res;
395}
396
397void jobs_check_all_timers (void);
398int epoll_work (int timeout) {
399 int timeout2 = 10000;
400 if (1) {
401 now = time (0);
402 get_utime_monotonic ();
403 do {
404 epoll_runqueue ();
405 timeout2 = epoll_run_timers ();
406 } while ((timeout2 <= 0 || ev_heap_size) && !term_signal_received ());
407 }
408 if (term_signal_received ()) {
409 return 0;
410 }
411
412 double epoll_wait_start = get_utime_monotonic ();
413
414 epoll_fetch_events (1);
415
416 last_epoll_wait_at = get_utime_monotonic ();
417 double epoll_wait_time = last_epoll_wait_at - epoll_wait_start;
418 tot_idle_time += epoll_wait_time;
419 a_idle_time += epoll_wait_time;
420
421 now = time (0);
422 static int prev_now = 0;
423 if (now > prev_now && now < prev_now + 60) {
424 while (prev_now < now) {
425 a_idle_time *= 100.0 / 101;
426 a_idle_quotient = a_idle_quotient * (100.0/101) + 1;
427 prev_now++;
428 }
429 } else {
430 prev_now = now;
431 }
432
433 epoll_run_timers ();
434
435 jobs_check_all_timers ();
436 return epoll_runqueue();
437}
438
439// ------- end of definitions ----------
440
441/*
442 * end (events)
443 */
444
445
446// From memcached.c: socket functions
447
448int new_socket (int mode, int nonblock) {
449 int socket_fd;
450 int flags;
451
452 if ((socket_fd = socket (mode & SM_IPV6 ? AF_INET6 : AF_INET, mode & SM_UDP ? SOCK_DGRAM : SOCK_STREAM, 0)) == -1) {
453 perror ("socket()");
454 return -1;
455 }
456
457 if (mode & SM_IPV6) {
458 flags = (mode & SM_IPV6_ONLY) != 0;
459 if (setsockopt (socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, &flags, 4) < 0) {
460 perror ("setting IPV6_V6ONLY");
461 close (socket_fd);
462 return -1;
463 }
464 }
465
466 if (!nonblock) {
467 return socket_fd;
468 }
469
470 if ((flags = fcntl (socket_fd, F_GETFL, 0)) < 0 || fcntl (socket_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
471 perror ("setting O_NONBLOCK");
472 close (socket_fd);
473 return -1;
474 }
475 return socket_fd;
476}
477
478
479/*
480 * Sets a socket's send buffer size to the maximum allowed by the system.
481 */
482void maximize_sndbuf (int socket_fd, int max) {
483 socklen_t intsize = sizeof(int);
484 int last_good = 0;
485 int min, avg;
486 int old_size;
487
488 if (max <= 0) {
489 max = MAX_UDP_SENDBUF_SIZE;
490 }
491
492 /* Start with the default size. */
493 if (getsockopt (socket_fd, SOL_SOCKET, SO_SNDBUF, &old_size, &intsize)) {
494 if (verbosity > 0) {
495 perror ("getsockopt (SO_SNDBUF)");
496 }
497 return;
498 }
499
500 /* Binary-search for the real maximum. */
501 min = last_good = old_size;
502 max = MAX_UDP_SENDBUF_SIZE;
503
504 while (min <= max) {
505 avg = ((unsigned int) min + max) / 2;
506 if (setsockopt (socket_fd, SOL_SOCKET, SO_SNDBUF, &avg, intsize) == 0) {
507 last_good = avg;
508 min = avg + 1;
509 } else {
510 max = avg - 1;
511 }
512 }
513
514 vkprintf (2, "<%d send buffer was %d, now %d\n", socket_fd, old_size, last_good);
515}
516
517/*
518 * Sets a socket's receive buffer size to the maximum allowed by the system.
519 */
520void maximize_rcvbuf (int socket_fd, int max) {
521 socklen_t intsize = sizeof(int);
522 int last_good = 0;
523 int min, avg;
524 int old_size;
525
526 if (max <= 0) {
527 max = MAX_UDP_RCVBUF_SIZE;
528 }
529
530 /* Start with the default size. */
531 if (getsockopt (socket_fd, SOL_SOCKET, SO_RCVBUF, &old_size, &intsize)) {
532 if (verbosity > 0) {
533 perror ("getsockopt (SO_RCVBUF)");
534 }
535 return;
536 }
537
538 /* Binary-search for the real maximum. */
539 min = last_good = old_size;
540 max = MAX_UDP_RCVBUF_SIZE;
541
542 while (min <= max) {
543 avg = ((unsigned int) min + max) / 2;
544 if (setsockopt (socket_fd, SOL_SOCKET, SO_RCVBUF, &avg, intsize) == 0) {
545 last_good = avg;
546 min = avg + 1;
547 } else {
548 max = avg - 1;
549 }
550 }
551
552 vkprintf (2, ">%d receive buffer was %d, now %d\n", socket_fd, old_size, last_good);
553}
554
555int tcp_maximize_buffers;
556struct in_addr settings_addr;
557
558int server_socket (int port, struct in_addr in_addr, int backlog, int mode) {
559 int socket_fd;
560 struct linger ling = {0, 0};
561 int flags = 1;
562
563 if ((socket_fd = new_socket (mode, 1)) == -1) {
564 return -1;
565 }
566
567 if (mode & SM_UDP) {
568 maximize_sndbuf (socket_fd, 0);
569 maximize_rcvbuf (socket_fd, 0);
570 setsockopt (socket_fd, SOL_IP, IP_RECVERR, &flags, sizeof (flags));
571
572 } else {
573 setsockopt (socket_fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags));
574 if (tcp_maximize_buffers) {
575 maximize_sndbuf (socket_fd, 0);
576 maximize_rcvbuf (socket_fd, 0);
577 }
578 assert (setsockopt (socket_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)) >= 0);
579 assert (flags == 1);
580 setsockopt (socket_fd, SOL_SOCKET, SO_LINGER, &ling, sizeof (ling));
581 setsockopt (socket_fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags));
582
583 int x = 40;
584 assert (setsockopt (socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &x, sizeof (x)) >= 0);
585 assert (setsockopt (socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &x, sizeof (x)) >= 0);
586 x = 5;
587 assert (setsockopt (socket_fd, IPPROTO_TCP, TCP_KEEPCNT, &x, sizeof (x)) >= 0);
588 }
589
590 if (mode & SM_REUSE) {
591 setsockopt (socket_fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags));
592 }
593
594 if (!(mode & SM_IPV6)) {
595 struct sockaddr_in addr;
596 memset (&addr, 0, sizeof (addr));
597
598 addr.sin_family = AF_INET;
599 addr.sin_port = htons (port);
600 addr.sin_addr = in_addr;
601 if (bind (socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
602 perror ("bind()");
603 close (socket_fd);
604 return -1;
605 }
606 } else {
607 struct sockaddr_in6 addr;
608 memset (&addr, 0, sizeof (addr));
609
610 addr.sin6_family = AF_INET6;
611 addr.sin6_port = htons (port);
612 addr.sin6_addr = in6addr_any;
613
614 if (bind (socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
615 perror ("bind()");
616 close (socket_fd);
617 return -1;
618 }
619 }
620 if (!(mode & SM_UDP) && listen (socket_fd, backlog) == -1) {
621// perror("listen()");
622 close (socket_fd);
623 return -1;
624 }
625 return socket_fd;
626}
627
628int client_socket (in_addr_t in_addr, int port, int mode) {
629 int socket_fd;
630 struct sockaddr_in addr;
631 int flags = 1;
632
633 if (mode & SM_IPV6) {
634 return -1;
635 }
636
637 if ((socket_fd = new_socket (mode, 1)) == -1) {
638 return -1;
639 }
640
641 if (mode & SM_UDP) {
642 maximize_sndbuf (socket_fd, 0);
643 maximize_rcvbuf (socket_fd, 0);
644 setsockopt (socket_fd, SOL_IP, IP_RECVERR, &flags, sizeof (flags));
645 } else {
646 setsockopt (socket_fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags));
647 if (tcp_maximize_buffers) {
648 maximize_sndbuf (socket_fd, 0);
649 maximize_rcvbuf (socket_fd, 0);
650 }
651 assert (setsockopt (socket_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)) >= 0);
652 assert (flags == 1);
653 setsockopt (socket_fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags));
654
655 int x = 40;
656 assert (setsockopt (socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &x, sizeof (x)) >= 0);
657 assert (setsockopt (socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &x, sizeof (x)) >= 0);
658 x = 5;
659 assert (setsockopt (socket_fd, IPPROTO_TCP, TCP_KEEPCNT, &x, sizeof (x)) >= 0);
660 }
661
662 if (!(mode & SM_IPV6)) {
663 engine_t *E = engine_state;
664 if (E && E->settings_addr.s_addr) {
665 struct sockaddr_in localaddr;
666 memset (&localaddr, 0, sizeof (localaddr));
667
668 localaddr.sin_family = AF_INET;
669 localaddr.sin_port = 0;
670 localaddr.sin_addr = E->settings_addr;
671 if (bind (socket_fd, (struct sockaddr *) &localaddr, sizeof (localaddr)) == -1) {
672 perror ("bind()");
673 close (socket_fd);
674 return -1;
675 }
676 }
677 }
678
679 memset (&addr, 0, sizeof (addr));
680
681 addr.sin_family = AF_INET;
682 addr.sin_port = htons (port);
683 addr.sin_addr.s_addr = in_addr;
684
685 if (connect (socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1 && errno != EINPROGRESS) {
686 perror ("connect()");
687 close (socket_fd);
688 return -1;
689 }
690
691 return socket_fd;
692
693}
694
695int client_socket_ipv6 (const unsigned char in6_addr_ptr[16], int port, int mode) {
696 int socket_fd;
697 struct sockaddr_in6 addr;
698 int flags = 1;
699
700 if (!(mode & SM_IPV6)) {
701 return -1;
702 }
703
704 if ((socket_fd = new_socket (mode, 1)) == -1) {
705 return -1;
706 }
707
708 if (mode & SM_UDP) {
709 maximize_sndbuf (socket_fd, 0);
710 maximize_rcvbuf (socket_fd, 0);
711 } else {
712 setsockopt (socket_fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags));
713 if (tcp_maximize_buffers) {
714 maximize_sndbuf (socket_fd, 0);
715 maximize_rcvbuf (socket_fd, 0);
716 }
717 setsockopt (socket_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags));
718 setsockopt (socket_fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags));
719 }
720
721 memset (&addr, 0, sizeof (addr));
722
723 addr.sin6_family = AF_INET6;
724 addr.sin6_port = htons (port);
725 memcpy (&addr.sin6_addr, in6_addr_ptr, 16);
726
727 if (connect (socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1 && errno != EINPROGRESS) {
728 perror ("connect()");
729 close (socket_fd);
730 return -1;
731 }
732
733 return socket_fd;
734
735}
736
737unsigned get_my_ipv4 (void) {
738 struct ifaddrs *ifa_first, *ifa;
739 unsigned my_ip = 0, my_netmask = -1;
740 char *my_iface = 0;
741 if (getifaddrs (&ifa_first) < 0) {
742 perror ("getifaddrs()");
743 return 0;
744 }
745 for (ifa = ifa_first; ifa; ifa = ifa->ifa_next) {
746 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) {
747 continue;
748 }
749 if (!strncmp (ifa->ifa_name, "lo", 2)) {
750 continue;
751 }
752 unsigned ip = ntohl (((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr);
753 unsigned mask = ntohl (((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr);
754 // fprintf (stderr, "%08x %08x\t%s\n", ip, mask, ifa->ifa_name);
755 if ((ip & (-1 << 24)) == (10 << 24) && (mask < my_netmask || (my_ip >> 24) != 10)) {
756 my_ip = ip;
757 my_netmask = mask;
758 my_iface = ifa->ifa_name;
759 } else if ((ip & (-1 << 24)) != (127 << 24) && mask < my_netmask && (my_ip >> 24) != 10) {
760 my_ip = ip;
761 my_netmask = mask;
762 my_iface = ifa->ifa_name;
763 }
764 }
765 vkprintf (1, "using main IP %d.%d.%d.%d/%d at interface %s\n", (my_ip >> 24), (my_ip >> 16) & 255, (my_ip >> 8) & 255, my_ip & 255,
766 __builtin_clz (~my_netmask), my_iface ?: "(none)");
767 freeifaddrs (ifa_first);
768 return my_ip;
769}
770
771int get_my_ipv6 (unsigned char ipv6[16]) {
772 struct ifaddrs *ifa_first, *ifa;
773 char *my_iface = 0;
774 unsigned char ip[16];
775 unsigned char mask[16];
776 memset (mask, 0, sizeof (mask));
777 if (getifaddrs (&ifa_first) < 0) {
778 perror ("getifaddrs()");
779 return 0;
780 }
781 int found_auto = 0;
782 for (ifa = ifa_first; ifa; ifa = ifa->ifa_next) {
783 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6) {
784 continue;
785 }
786 memcpy (ip, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, 16);
787 vkprintf (2, "test IP " IPV6_PRINT_STR " at interface %s\n", IPV6_TO_PRINT (ip), ifa->ifa_name);
788
789 if ((ip[0] & 0xf0) != 0x30 && (ip[0] & 0xf0) != 0x20) {
790 vkprintf (2, "not a global ipv6 address\n");
791 continue;
792 }
793
794 if (ip[11] == 0xff && ip[12] == 0xfe && (ip[8] & 2)) {
795 if (found_auto) { continue; }
796 my_iface = ifa->ifa_name;
797 memcpy (ipv6, ip, 16);
798 memcpy (mask, &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr, 16);
799 found_auto = 1;
800 } else {
801 my_iface = ifa->ifa_name;
802 memcpy (ipv6, ip, 16);
803 memcpy (mask, &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr, 16);
804 break;
805 }
806 }
807 int m = 0;
808 while (m < 128 && mask[m / 8] == 0xff) { m += 8; }
809 if (m < 128) {
810 unsigned char c = mask[m / 8];
811 while (c & 1) {
812 c /= 2;
813 m ++;
814 }
815 }
816 vkprintf (1, "using main IP " IPV6_PRINT_STR "/%d at interface %s\n", IPV6_TO_PRINT (ipv6), m, my_iface);
817 freeifaddrs (ifa_first);
818 return 1;
819}
820
821/* IPv4/IPv6 address formatting functions */
822
823const char *conv_addr (in_addr_t a, char *buf) {
824 static char abuf[64];
825 if (!buf) {
826 buf = abuf;
827 }
828 sprintf (buf, "%d.%d.%d.%d", a&255, (a>>8)&255, (a>>16)&255, a>>24);
829 return buf;
830}
831
832int conv_ipv6_internal (const unsigned short a[8], char *buf) {
833 int i, j = 0, k = 0, l = 0;
834 for (i = 0; i < 8; i++) {
835 if (a[i]) {
836 if (j > l) {
837 l = j;
838 k = i;
839 }
840 j = 0;
841 } else {
842 j++;
843 }
844 }
845 if (j == 8) {
846 memcpy (buf, "::", 3);
847 return 2;
848 }
849 if (l == 5 && a[5] == 0xffff) {
850 return sprintf (buf, "::ffff:%d.%d.%d.%d", a[6]&255, a[6]>>8, a[7]&255, a[7]>>8);
851 }
852 char *ptr = buf;
853 if (l) {
854 for (i = 0; i < k - l; i++) {
855 ptr += sprintf (ptr, "%x:", ntohs (a[i]));
856 }
857 if (!i || k == 8) {
858 *ptr++ = ':';
859 }
860 for (i = k; i < 8; i++) {
861 ptr += sprintf (ptr, ":%x", ntohs (a[i]));
862 }
863 } else {
864 for (i = 0; i < 7; i++) {
865 ptr += sprintf (ptr, "%x:", ntohs (a[i]));
866 }
867 ptr += sprintf (ptr, "%x", ntohs (a[i]));
868 }
869 return ptr - buf;
870}
871
872const char *conv_addr6 (const unsigned char a[16], char *buf) {
873 static char abuf[64];
874 if (!buf) {
875 buf = abuf;
876 }
877 conv_ipv6_internal ((const unsigned short *) a, buf);
878 return buf;
879}
880
881const char *show_ip (unsigned ip) {
882 static char abuf[256], *ptr = abuf;
883 char *res;
884 if (ptr > abuf + 200) {
885 ptr = abuf;
886 }
887 res = ptr;
888 ptr += sprintf (ptr, "%d.%d.%d.%d", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff) + 1;
889 return res;
890}
891
892const char *show_ipv6 (const unsigned char ipv6[16]) {
893 static char abuf[256], *ptr = abuf;
894 char *res;
895 if (ptr > abuf + 200) {
896 ptr = abuf;
897 }
898 res = ptr;
899 ptr += conv_ipv6_internal ((const unsigned short *) ipv6, ptr) + 1;
900 return res;
901}
902
903