1 /**
2 * @file tcp.c Transport Control Protocol
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <stdlib.h>
7 #ifdef HAVE_UNISTD_H
8 #include <unistd.h>
9 #endif
10 #ifdef HAVE_IO_H
11 #include <io.h>
12 #endif
13 #if !defined(WIN32)
14 #define __USE_POSIX 1 /**< Use POSIX flag */
15 #define __USE_XOPEN2K 1/**< Use POSIX.1:2001 code */
16 #define __USE_MISC 1
17 #include <netdb.h>
18 #endif
19 #ifdef __APPLE__
20 #include "TargetConditionals.h"
21 #endif
22 #include <string.h>
23 #include <re_types.h>
24 #include <re_fmt.h>
25 #include <re_mem.h>
26 #include <re_mbuf.h>
27 #include <re_list.h>
28 #include <re_main.h>
29 #include <re_sa.h>
30 #include <re_net.h>
31 #include <re_tcp.h>
32
33
34 #define DEBUG_MODULE "tcp"
sys_rel_get(uint32_t * rel,uint32_t * maj,uint32_t * min,uint32_t * patch)35 #define DEBUG_LEVEL 5
36 #include <re_dbg.h>
37
38
39 /** Platform independent buffer type cast */
40 #ifdef WIN32
41 #define BUF_CAST (char *)
42 #define SOK_CAST (int)
43 #define SIZ_CAST (int)
44 #define close closesocket
45 #else
46 #define BUF_CAST
47 #define SOK_CAST
48 #define SIZ_CAST
49 #endif
50
51
52 enum {
53 TCP_TXQSZ_DEFAULT = 524288,
54 TCP_RXSZ_DEFAULT = 8192
55 };
56
57
58 /** Defines a listening TCP socket */
59 struct tcp_sock {
60 int fd; /**< Listening file descriptor */
61 int fdc; /**< Cached connection file descriptor */
62 tcp_conn_h *connh; /**< TCP Connect handler */
63 void *arg; /**< Handler argument */
64 };
65
66
67 /** Defines a TCP connection */
68 struct tcp_conn {
69 struct list helpers; /**< List of TCP-helpers */
70 struct list sendq; /**< Sending queue */
71 int fdc; /**< Connection file descriptor */
72 tcp_estab_h *estabh; /**< Connection established handler */
73 tcp_send_h *sendh; /**< Data send handler */
74 tcp_recv_h *recvh; /**< Data receive handler */
75 tcp_close_h *closeh; /**< Connection close handler */
76 void *arg; /**< Handler argument */
77 size_t rxsz; /**< Maximum receive chunk size */
78 size_t txqsz;
79 size_t txqsz_max;
80 bool active; /**< We are connecting flag */
81 bool connected; /**< Connection is connected flag */
82 };
83
sys_kernel_get(struct re_printf * pf,void * unused)84
85 /** Defines a TCP-Connection Helper */
86 struct tcp_helper {
87 struct le le;
88 int layer;
89 tcp_helper_estab_h *estabh;
90 tcp_helper_send_h *sendh;
91 tcp_helper_recv_h *recvh;
92 void *arg;
93 };
94
95
96 struct tcp_qent {
97 struct le le;
98 struct mbuf mb;
99 };
100
101
102 static void tcp_recv_handler(int flags, void *arg);
103
104
105 static bool helper_estab_handler(int *err, bool active, void *arg)
106 {
107 (void)err;
108 (void)active;
109 (void)arg;
110 return false;
111 }
112
113
114 static bool helper_send_handler(int *err, struct mbuf *mb, void *arg)
115 {
116 (void)err;
117 (void)mb;
118 (void)arg;
119 return false;
sys_build_get(struct re_printf * pf,void * unused)120 }
121
122
123 static bool helper_recv_handler(int *err, struct mbuf *mb, bool *estab,
124 void *arg)
125 {
126 (void)err;
127 (void)mb;
128 (void)estab;
129 (void)arg;
130 return false;
131 }
132
133
134 static void sock_destructor(void *data)
135 {
136 struct tcp_sock *ts = data;
137
138 if (ts->fd >= 0) {
139 fd_close(ts->fd);
140 (void)close(ts->fd);
141 }
142 if (ts->fdc >= 0)
143 (void)close(ts->fdc);
144 }
145
146
sys_arch_get(void)147 static void conn_destructor(void *data)
148 {
149 struct tcp_conn *tc = data;
150
151 list_flush(&tc->helpers);
152 list_flush(&tc->sendq);
153
154 if (tc->fdc >= 0) {
155 fd_close(tc->fdc);
156 (void)close(tc->fdc);
157 }
158 }
159
160
161 static void helper_destructor(void *data)
sys_os_get(void)162 {
163 struct tcp_helper *th = data;
164
165 list_unlink(&th->le);
166 }
167
168
169 static void qent_destructor(void *arg)
170 {
171 struct tcp_qent *qe = arg;
172
173 list_unlink(&qe->le);
174 mem_deref(qe->mb.buf);
175 }
176
sys_libre_version_get(void)177
178 static int enqueue(struct tcp_conn *tc, struct mbuf *mb)
179 {
180 const size_t n = mbuf_get_left(mb);
181 struct tcp_qent *qe;
182 int err;
183
184 if (tc->txqsz + n > tc->txqsz_max)
185 return ENOSPC;
186
187 if (!tc->sendq.head && !tc->sendh) {
188
189 err = fd_listen(tc->fdc, FD_READ | FD_WRITE,
190 tcp_recv_handler, tc);
191 if (err)
192 return err;
193 }
194
195 qe = mem_zalloc(sizeof(*qe), qent_destructor);
196 if (!qe)
197 return ENOMEM;
198
199 list_append(&tc->sendq, &qe->le, qe);
200
201 mbuf_init(&qe->mb);
202
203 err = mbuf_write_mem(&qe->mb, mbuf_buf(mb), n);
204 qe->mb.pos = 0;
205
206 if (err)
207 mem_deref(qe);
208 else
209 tc->txqsz += qe->mb.end;
210
211 return err;
212 }
213
214
215 static int dequeue(struct tcp_conn *tc)
216 {
217 struct tcp_qent *qe = list_ledata(tc->sendq.head);
218 ssize_t n;
219 #ifdef MSG_NOSIGNAL
sys_coredump_set(bool enable)220 const int flags = MSG_NOSIGNAL; /* disable SIGPIPE signal */
221 #else
222 const int flags = 0;
223 #endif
224 if (!qe) {
225 if (tc->sendh)
226 tc->sendh(tc->arg);
227
228 return 0;
229 }
230
231 n = send(tc->fdc, BUF_CAST mbuf_buf(&qe->mb),
232 qe->mb.end - qe->mb.pos, flags);
233 if (n < 0) {
234 if (EAGAIN == errno)
235 return 0;
236 #ifdef WIN32
237 if (WSAEWOULDBLOCK == WSAGetLastError())
238 return 0;
239 #endif
240 return errno;
241 }
242
243 tc->txqsz -= n;
244 qe->mb.pos += n;
245
246 if (qe->mb.pos >= qe->mb.end)
247 mem_deref(qe);
248
249 return 0;
250 }
251
252
253 static void conn_close(struct tcp_conn *tc, int err)
254 {
255 list_flush(&tc->sendq);
256 tc->txqsz = 0;
257
258 /* Stop polling */
259 if (tc->fdc >= 0) {
260 fd_close(tc->fdc);
261 (void)close(tc->fdc);
262 tc->fdc = -1;
263 }
264
265 if (tc->closeh)
266 tc->closeh(err, tc->arg);
267 }
268
269
270 static void tcp_recv_handler(int flags, void *arg)
271 {
272 struct tcp_conn *tc = arg;
273 struct mbuf *mb = NULL;
274 bool hlp_estab = false;
275 struct le *le;
276 ssize_t n;
277 int err;
278 socklen_t err_len = sizeof(err);
279
280 if (flags & FD_EXCEPT) {
281 DEBUG_INFO("recv handler: got FD_EXCEPT on fd=%d\n", tc->fdc);
282 }
283
284 /* check for any errors */
285 if (-1 == getsockopt(tc->fdc, SOL_SOCKET, SO_ERROR,
286 BUF_CAST &err, &err_len)) {
287 DEBUG_WARNING("recv handler: getsockopt: (%m)\n", errno);
288 return;
289 }
290
291 if (err) {
292 conn_close(tc, err);
293 return;
294 }
295 #if 0
296 if (EINPROGRESS != err && EALREADY != err) {
297 DEBUG_WARNING("recv handler: Socket error (%m)\n", err);
298 return;
299 }
300 #endif
301
302 if (flags & FD_WRITE) {
303
304 if (tc->connected) {
305
306 uint32_t nrefs;
307
308 mem_ref(tc);
309
310 err = dequeue(tc);
311
312 nrefs = mem_nrefs(tc);
313 mem_deref(tc);
314
315 /* check if connection was deref'd from send handler */
316 if (nrefs == 1)
317 return;
318
319 if (err) {
320 conn_close(tc, err);
321 return;
322 }
323
324 if (!tc->sendq.head && !tc->sendh) {
325
326 err = fd_listen(tc->fdc, FD_READ,
327 tcp_recv_handler, tc);
328 if (err) {
329 conn_close(tc, err);
330 return;
331 }
332 }
333
334 if (flags & FD_READ)
335 goto read;
336
337 return;
338 }
339
340 tc->connected = true;
341
342 err = fd_listen(tc->fdc, FD_READ, tcp_recv_handler, tc);
343 if (err) {
344 DEBUG_WARNING("recv handler: fd_listen(): %m\n", err);
345 conn_close(tc, err);
346 return;
347 }
348
349 le = tc->helpers.head;
350 while (le) {
351 struct tcp_helper *th = le->data;
352
353 le = le->next;
354
355 if (th->estabh(&err, tc->active, th->arg) || err) {
356 if (err)
357 conn_close(tc, err);
358 return;
359 }
360 }
361
362 if (tc->estabh)
363 tc->estabh(tc->arg);
364
365 return;
366 }
367
368 read:
369 mb = mbuf_alloc(tc->rxsz);
370 if (!mb)
371 return;
372
373 n = recv(tc->fdc, BUF_CAST mb->buf, mb->size, 0);
374 if (0 == n) {
375 mem_deref(mb);
376 conn_close(tc, 0);
377 return;
378 }
379 else if (n < 0) {
380 DEBUG_WARNING("recv handler: recv(): %m\n", errno);
381 goto out;
382 }
383
384 mb->end = n;
385
386 le = tc->helpers.head;
387 while (le) {
388 struct tcp_helper *th = le->data;
389 bool hdld = false;
390
391 le = le->next;
392
393 if (hlp_estab) {
394
395 hdld |= th->estabh(&err, tc->active, th->arg);
396 if (err) {
397 conn_close(tc, err);
398 goto out;
399 }
400 }
401
402 if (mb->pos < mb->end) {
403
404 hdld |= th->recvh(&err, mb, &hlp_estab, th->arg);
405 if (err) {
406 conn_close(tc, err);
407 goto out;
408 }
409 }
410
411 if (hdld)
412 goto out;
413 }
414
415 mbuf_trim(mb);
416
417 if (hlp_estab && tc->estabh) {
418
419 uint32_t nrefs;
420
421 mem_ref(tc);
422
423 tc->estabh(tc->arg);
424
425 nrefs = mem_nrefs(tc);
426 mem_deref(tc);
427
428 /* check if connection was deref'ed from establish handler */
429 if (nrefs == 1)
430 goto out;
431 }
432
433 if (mb->pos < mb->end && tc->recvh) {
434 tc->recvh(mb, tc->arg);
435 }
436
437 out:
438 mem_deref(mb);
439 }
440
441
442 static struct tcp_conn *conn_alloc(tcp_estab_h *eh, tcp_recv_h *rh,
443 tcp_close_h *ch, void *arg)
444 {
445 struct tcp_conn *tc;
446
447 tc = mem_zalloc(sizeof(*tc), conn_destructor);
448 if (!tc)
449 return NULL;
450
451 list_init(&tc->helpers);
452
453 tc->fdc = -1;
454 tc->rxsz = TCP_RXSZ_DEFAULT;
455 tc->txqsz_max = TCP_TXQSZ_DEFAULT;
456 tc->estabh = eh;
457 tc->recvh = rh;
458 tc->closeh = ch;
459 tc->arg = arg;
460
461 return tc;
462 }
463
464
465 static void tcp_sockopt_set(int fd)
466 {
467 #ifdef SO_LINGER
468 const struct linger dl = {0, 0};
469 int err;
470
471 err = setsockopt(fd, SOL_SOCKET, SO_LINGER, BUF_CAST &dl, sizeof(dl));
472 if (err) {
473 DEBUG_WARNING("sockopt: SO_LINGER (%m)\n", err);
474 }
475 #else
476 (void)fd;
477 #endif
478 }
479
480
481 /**
482 * Handler for incoming TCP connections.
483 *
484 * @param flags Event flags.
485 * @param arg Handler argument.
486 */
487 static void tcp_conn_handler(int flags, void *arg)
488 {
489 struct sa peer;
490 struct tcp_sock *ts = arg;
491 int err;
492
493 (void)flags;
494
495 sa_init(&peer, AF_UNSPEC);
496
497 if (ts->fdc >= 0)
498 (void)close(ts->fdc);
499
500 ts->fdc = SOK_CAST accept(ts->fd, &peer.u.sa, &peer.len);
501 if (-1 == ts->fdc) {
502
503 #if TARGET_OS_IPHONE
504 if (EAGAIN == errno) {
505
506 struct tcp_sock *ts_new;
507 struct sa laddr;
508
509 err = tcp_sock_local_get(ts, &laddr);
510 if (err)
511 return;
512
513 if (ts->fd >= 0) {
514 fd_close(ts->fd);
515 (void)close(ts->fd);
516 ts->fd = -1;
517 }
518
519 err = tcp_listen(&ts_new, &laddr, NULL, NULL);
520 if (err)
521 return;
522
523 ts->fd = ts_new->fd;
524 ts_new->fd = -1;
525
526 mem_deref(ts_new);
527
528 fd_listen(ts->fd, FD_READ, tcp_conn_handler, ts);
529 }
530 #endif
531
532 return;
533 }
534
535 err = net_sockopt_blocking_set(ts->fdc, false);
536 if (err) {
537 DEBUG_WARNING("conn handler: nonblock set: %m\n", err);
538 (void)close(ts->fdc);
539 ts->fdc = -1;
540 return;
541 }
542
543 tcp_sockopt_set(ts->fdc);
544
545 if (ts->connh)
546 ts->connh(&peer, ts->arg);
547 }
548
549
550 /**
551 * Create a TCP Socket
552 *
553 * @param tsp Pointer to returned TCP Socket
554 * @param local Local listen address (NULL for any)
555 * @param ch Incoming connection handler
556 * @param arg Handler argument
557 *
558 * @return 0 if success, otherwise errorcode
559 */
560 int tcp_sock_alloc(struct tcp_sock **tsp, const struct sa *local,
561 tcp_conn_h *ch, void *arg)
562 {
563 struct addrinfo hints, *res = NULL, *r;
564 char addr[64] = "";
565 char serv[6] = "0";
566 struct tcp_sock *ts = NULL;
567 int error, err;
568
569 if (!tsp)
570 return EINVAL;
571
572 ts = mem_zalloc(sizeof(*ts), sock_destructor);
573 if (!ts)
574 return ENOMEM;
575
576 ts->fd = -1;
577 ts->fdc = -1;
578
579 if (local) {
580 (void)re_snprintf(addr, sizeof(addr), "%H",
581 sa_print_addr, local);
582 (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local));
583 }
584
585 memset(&hints, 0, sizeof(hints));
586 /* set-up hints structure */
587 hints.ai_family = PF_UNSPEC;
588 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
589 hints.ai_socktype = SOCK_STREAM;
590 hints.ai_protocol = IPPROTO_TCP;
591
592 error = getaddrinfo(addr[0] ? addr : NULL, serv, &hints, &res);
593 if (error) {
594 #ifdef WIN32
595 DEBUG_WARNING("listen: getaddrinfo: wsaerr=%d\n",
596 WSAGetLastError());
597 #endif
598 DEBUG_WARNING("listen: getaddrinfo: %s:%s error=%d (%s)\n",
599 addr, serv, error, gai_strerror(error));
600 err = EADDRNOTAVAIL;
601 goto out;
602 }
603
604 err = EINVAL;
605 for (r = res; r; r = r->ai_next) {
606 int fd = -1;
607
608 if (ts->fd >= 0)
609 continue;
610
611 fd = SOK_CAST socket(r->ai_family, SOCK_STREAM, IPPROTO_TCP);
612 if (fd < 0) {
613 err = errno;
614 continue;
615 }
616
617 (void)net_sockopt_reuse_set(fd, true);
618
619 err = net_sockopt_blocking_set(fd, false);
620 if (err) {
621 DEBUG_WARNING("listen: nonblock set: %m\n", err);
622 (void)close(fd);
623 continue;
624 }
625
626 tcp_sockopt_set(fd);
627
628 /* OK */
629 ts->fd = fd;
630 err = 0;
631 break;
632 }
633
634 freeaddrinfo(res);
635
636 if (-1 == ts->fd)
637 goto out;
638
639 ts->connh = ch;
640 ts->arg = arg;
641
642 out:
643 if (err)
644 mem_deref(ts);
645 else
646 *tsp = ts;
647
648 return err;
649 }
650
651
652 /**
653 * Bind to a TCP Socket
654 *
655 * @param ts TCP Socket
656 * @param local Local bind address
657 *
658 * @return 0 if success, otherwise errorcode
659 */
660 int tcp_sock_bind(struct tcp_sock *ts, const struct sa *local)
661 {
662 struct addrinfo hints, *res = NULL, *r;
663 char addr[64] = "";
664 char serv[NI_MAXSERV] = "0";
665 int error, err;
666
667 if (!ts || ts->fd<0)
668 return EINVAL;
669
670 if (local) {
671 (void)re_snprintf(addr, sizeof(addr), "%H",
672 sa_print_addr, local);
673 (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local));
674 }
675
676 memset(&hints, 0, sizeof(hints));
677 /* set-up hints structure */
678 hints.ai_family = PF_UNSPEC;
679 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
680 hints.ai_socktype = SOCK_STREAM;
681 hints.ai_protocol = IPPROTO_TCP;
682
683 error = getaddrinfo(addr[0] ? addr : NULL, serv, &hints, &res);
684 if (error) {
685 #ifdef WIN32
686 DEBUG_WARNING("sock_bind: getaddrinfo: wsaerr=%d\n",
687 WSAGetLastError());
688 #endif
689 DEBUG_WARNING("sock_bind: getaddrinfo: %s:%s error=%d (%s)\n",
690 addr, serv, error, gai_strerror(error));
691 return EADDRNOTAVAIL;
692 }
693
694 err = EINVAL;
695 for (r = res; r; r = r->ai_next) {
696
697 if (bind(ts->fd, r->ai_addr, SIZ_CAST r->ai_addrlen) < 0) {
698 err = errno;
699 DEBUG_WARNING("sock_bind: bind: %m (af=%d, %J)\n",
700 err, r->ai_family, local);
701 continue;
702 }
703
704 /* OK */
705 err = 0;
706 break;
707 }
708
709 freeaddrinfo(res);
710
711 return err;
712 }
713
714
715 /**
716 * Listen on a TCP Socket
717 *
718 * @param ts TCP Socket
719 * @param backlog Maximum length the queue of pending connections
720 *
721 * @return 0 if success, otherwise errorcode
722 */
723 int tcp_sock_listen(struct tcp_sock *ts, int backlog)
724 {
725 int err;
726
727 if (!ts)
728 return EINVAL;
729
730 if (ts->fd < 0) {
731 DEBUG_WARNING("sock_listen: invalid fd\n");
732 return EBADF;
733 }
734
735 if (listen(ts->fd, backlog) < 0) {
736 err = errno;
737 DEBUG_WARNING("sock_listen: listen(): %m\n", err);
738 return err;
739 }
740
741 return fd_listen(ts->fd, FD_READ, tcp_conn_handler, ts);
742 }
743
744
745 /**
746 * Accept an incoming TCP Connection
747 *
748 * @param tcp Returned TCP Connection object
749 * @param ts Corresponding TCP Socket
750 * @param eh TCP Connection Established handler
751 * @param rh TCP Connection Receive data handler
752 * @param ch TCP Connection close handler
753 * @param arg Handler argument
754 *
755 * @return 0 if success, otherwise errorcode
756 */
757 int tcp_accept(struct tcp_conn **tcp, struct tcp_sock *ts, tcp_estab_h *eh,
758 tcp_recv_h *rh, tcp_close_h *ch, void *arg)
759 {
760 struct tcp_conn *tc;
761 int err;
762
763 if (!tcp || !ts || ts->fdc < 0)
764 return EINVAL;
765
766 tc = conn_alloc(eh, rh, ch, arg);
767 if (!tc)
768 return ENOMEM;
769
770 /* Transfer ownership to TCP connection */
771 tc->fdc = ts->fdc;
772 ts->fdc = -1;
773
774 err = fd_listen(tc->fdc, FD_READ | FD_WRITE | FD_EXCEPT,
775 tcp_recv_handler, tc);
776 if (err) {
777 DEBUG_WARNING("accept: fd_listen(): %m\n", err);
778 }
779
780 if (err)
781 mem_deref(tc);
782 else
783 *tcp = tc;
784
785 return err;
786 }
787
788
789 /**
790 * Reject an incoming TCP Connection
791 *
792 * @param ts Corresponding TCP Socket
793 */
794 void tcp_reject(struct tcp_sock *ts)
795 {
796 if (!ts)
797 return;
798
799 if (ts->fdc >= 0) {
800 (void)close(ts->fdc);
801 ts->fdc = -1;
802 }
803 }
804
805
806 /**
807 * Allocate a TCP Connection
808 *
809 * @param tcp Returned TCP Connection object
810 * @param peer Network address of peer
811 * @param eh TCP Connection Established handler
812 * @param rh TCP Connection Receive data handler
813 * @param ch TCP Connection close handler
814 * @param arg Handler argument
815 *
816 * @return 0 if success, otherwise errorcode
817 */
818 int tcp_conn_alloc(struct tcp_conn **tcp,
819 const struct sa *peer, tcp_estab_h *eh,
820 tcp_recv_h *rh, tcp_close_h *ch, void *arg)
821 {
822 struct tcp_conn *tc;
823 struct addrinfo hints, *res = NULL, *r;
824 char addr[64];
825 char serv[NI_MAXSERV] = "0";
826 int error, err;
827
828 if (!tcp || !sa_isset(peer, SA_ALL))
829 return EINVAL;
830
831 tc = conn_alloc(eh, rh, ch, arg);
832 if (!tc)
833 return ENOMEM;
834
835 memset(&hints, 0, sizeof(hints));
836 /* set-up hints structure */
837 hints.ai_family = PF_UNSPEC;
838 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
839 hints.ai_socktype = SOCK_STREAM;
840 hints.ai_protocol = IPPROTO_TCP;
841
842 (void)re_snprintf(addr, sizeof(addr), "%H",
843 sa_print_addr, peer);
844 (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(peer));
845
846 error = getaddrinfo(addr, serv, &hints, &res);
847 if (error) {
848 DEBUG_WARNING("connect: getaddrinfo(): (%s)\n",
849 gai_strerror(error));
850 err = EADDRNOTAVAIL;
851 goto out;
852 }
853
854 err = EINVAL;
855 for (r = res; r; r = r->ai_next) {
856
857 tc->fdc = SOK_CAST socket(r->ai_family, SOCK_STREAM,
858 IPPROTO_TCP);
859 if (tc->fdc < 0) {
860 err = errno;
861 continue;
862 }
863
864 err = net_sockopt_blocking_set(tc->fdc, false);
865 if (err) {
866 DEBUG_WARNING("connect: nonblock set: %m\n", err);
867 (void)close(tc->fdc);
868 tc->fdc = -1;
869 continue;
870 }
871
872 tcp_sockopt_set(tc->fdc);
873
874 err = 0;
875 break;
876 }
877
878 freeaddrinfo(res);
879
880 out:
881 if (err)
882 mem_deref(tc);
883 else
884 *tcp = tc;
885
886 return err;
887 }
888
889
890 /**
891 * Bind a TCP Connection to a local address
892 *
893 * @param tc TCP Connection object
894 * @param local Local bind address
895 *
896 * @return 0 if success, otherwise errorcode
897 */
898 int tcp_conn_bind(struct tcp_conn *tc, const struct sa *local)
899 {
900 struct addrinfo hints, *res = NULL, *r;
901 char addr[64] = "";
902 char serv[NI_MAXSERV] = "0";
903 int error, err;
904
905 if (!tc)
906 return EINVAL;
907
908 if (local) {
909 (void)re_snprintf(addr, sizeof(addr), "%H",
910 sa_print_addr, local);
911 (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local));
912 }
913
914 memset(&hints, 0, sizeof(hints));
915 /* set-up hints structure */
916 hints.ai_family = PF_UNSPEC;
917 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
918 hints.ai_socktype = SOCK_STREAM;
919 hints.ai_protocol = IPPROTO_TCP;
920
921 error = getaddrinfo(addr[0] ? addr : NULL, serv, &hints, &res);
922 if (error) {
923 DEBUG_WARNING("conn_bind: getaddrinfo(): (%s)\n",
924 gai_strerror(error));
925 return EADDRNOTAVAIL;
926 }
927
928 err = EINVAL;
929 for (r = res; r; r = r->ai_next) {
930
931 (void)net_sockopt_reuse_set(tc->fdc, true);
932
933 /* bind to local address */
934 if (bind(tc->fdc, r->ai_addr, SIZ_CAST r->ai_addrlen) < 0) {
935
936 /* Special case for mingw32/wine */
937 if (0 == errno) {
938 goto ok;
939 }
940
941 err = errno;
942 DEBUG_WARNING("conn_bind: bind(): %J: %m\n",
943 local, err);
944 continue;
945 }
946
947 ok:
948 /* OK */
949 err = 0;
950 break;
951 }
952
953 freeaddrinfo(res);
954
955 if (err) {
956 DEBUG_WARNING("conn_bind failed: %J (%m)\n", local, err);
957 }
958
959 return err;
960 }
961
962
963 /**
964 * Connect to a remote peer
965 *
966 * @param tc TCP Connection object
967 * @param peer Network address of peer
968 *
969 * @return 0 if success, otherwise errorcode
970 */
971 int tcp_conn_connect(struct tcp_conn *tc, const struct sa *peer)
972 {
973 struct addrinfo hints, *res = NULL, *r;
974 char addr[64];
975 char serv[NI_MAXSERV];
976 int error, err = 0;
977
978 if (!tc || !sa_isset(peer, SA_ALL))
979 return EINVAL;
980
981 tc->active = true;
982
983 if (tc->fdc < 0) {
984 DEBUG_WARNING("invalid fd\n");
985 return EBADF;
986 }
987
988 memset(&hints, 0, sizeof(hints));
989 /* set-up hints structure */
990 hints.ai_family = PF_UNSPEC;
991 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
992 hints.ai_socktype = SOCK_STREAM;
993 hints.ai_protocol = IPPROTO_TCP;
994
995 (void)re_snprintf(addr, sizeof(addr), "%H",
996 sa_print_addr, peer);
997 (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(peer));
998
999 error = getaddrinfo(addr, serv, &hints, &res);
1000 if (error) {
1001 DEBUG_WARNING("connect: getaddrinfo(): (%s)\n",
1002 gai_strerror(error));
1003 return EADDRNOTAVAIL;
1004 }
1005
1006 for (r = res; r; r = r->ai_next) {
1007 struct sockaddr *sa = r->ai_addr;
1008
1009 again:
1010 if (0 == connect(tc->fdc, sa, SIZ_CAST r->ai_addrlen)) {
1011 err = 0;
1012 goto out;
1013 }
1014 else {
1015 #ifdef WIN32
1016 /* Special error handling for Windows */
1017 if (WSAEWOULDBLOCK == WSAGetLastError()) {
1018 err = 0;
1019 goto out;
1020 }
1021 #endif
1022
1023 /* Special case for mingw32/wine */
1024 if (0 == errno) {
1025 err = 0;
1026 goto out;
1027 }
1028
1029 if (EINTR == errno)
1030 goto again;
1031
1032 if (EINPROGRESS != errno && EALREADY != errno) {
1033 err = errno;
1034 DEBUG_INFO("connect: connect() %J: %m\n",
1035 peer, err);
1036 }
1037 }
1038 }
1039
1040 out:
1041 freeaddrinfo(res);
1042
1043 if (err)
1044 return err;
1045
1046 return fd_listen(tc->fdc, FD_READ | FD_WRITE | FD_EXCEPT,
1047 tcp_recv_handler, tc);
1048 }
1049
1050
1051 static int tcp_send_internal(struct tcp_conn *tc, struct mbuf *mb,
1052 struct le *le)
1053 {
1054 int err = 0;
1055 ssize_t n;
1056 #ifdef MSG_NOSIGNAL
1057 const int flags = MSG_NOSIGNAL; /* disable SIGPIPE signal */
1058 #else
1059 const int flags = 0;
1060 #endif
1061
1062 if (tc->fdc < 0)
1063 return ENOTCONN;
1064
1065 if (!mbuf_get_left(mb)) {
1066 DEBUG_WARNING("send: empty mbuf (pos=%u end=%u)\n",
1067 mb->pos, mb->end);
1068 return EINVAL;
1069 }
1070
1071 /* call helpers in reverse order */
1072 while (le) {
1073 struct tcp_helper *th = le->data;
1074
1075 le = le->prev;
1076
1077 if (th->sendh(&err, mb, th->arg) || err)
1078 return err;
1079 }
1080
1081 if (tc->sendq.head)
1082 return enqueue(tc, mb);
1083
1084 n = send(tc->fdc, BUF_CAST mbuf_buf(mb), mb->end - mb->pos, flags);
1085 if (n < 0) {
1086
1087 if (EAGAIN == errno)
1088 return enqueue(tc, mb);
1089
1090 #ifdef WIN32
1091 if (WSAEWOULDBLOCK == WSAGetLastError())
1092 return enqueue(tc, mb);
1093 #endif
1094 err = errno;
1095
1096 DEBUG_WARNING("send: write(): %m (fdc=%d)\n", err, tc->fdc);
1097
1098 #ifdef WIN32
1099 DEBUG_WARNING("WIN32 error: %d\n", WSAGetLastError());
1100 #endif
1101
1102 return err;
1103 }
1104
1105 if ((size_t)n < mb->end - mb->pos) {
1106
1107 mb->pos += n;
1108 err = enqueue(tc, mb);
1109 mb->pos -= n;
1110
1111 return err;
1112 }
1113
1114 return 0;
1115 }
1116
1117
1118 /**
1119 * Send data on a TCP Connection to a remote peer
1120 *
1121 * @param tc TCP Connection
1122 * @param mb Buffer to send
1123 *
1124 * @return 0 if success, otherwise errorcode
1125 */
1126 int tcp_send(struct tcp_conn *tc, struct mbuf *mb)
1127 {
1128 if (!tc || !mb)
1129 return EINVAL;
1130
1131 return tcp_send_internal(tc, mb, tc->helpers.tail);
1132 }
1133
1134
1135 /**
1136 * Send data on a TCP Connection to a remote peer bypassing this
1137 * helper and the helpers above it.
1138 *
1139 * @param tc TCP Connection
1140 * @param mb Buffer to send
1141 * @param th TCP Helper
1142 *
1143 * @return 0 if success, otherwise errorcode
1144 */
1145 int tcp_send_helper(struct tcp_conn *tc, struct mbuf *mb,
1146 struct tcp_helper *th)
1147 {
1148 if (!tc || !mb || !th)
1149 return EINVAL;
1150
1151 return tcp_send_internal(tc, mb, th->le.prev);
1152 }
1153
1154
1155 /**
1156 * Set the send handler on a TCP Connection, which will be called
1157 * every time it is ready to send data
1158 *
1159 * @param tc TCP Connection
1160 * @param sendh TCP Send handler
1161 *
1162 * @return 0 if success, otherwise errorcode
1163 */
1164 int tcp_set_send(struct tcp_conn *tc, tcp_send_h *sendh)
1165 {
1166 if (!tc)
1167 return EINVAL;
1168
1169 tc->sendh = sendh;
1170
1171 if (tc->sendq.head || !sendh)
1172 return 0;
1173
1174 return fd_listen(tc->fdc, FD_READ | FD_WRITE, tcp_recv_handler, tc);
1175 }
1176
1177
1178 /**
1179 * Set handlers on a TCP Connection
1180 *
1181 * @param tc TCP Connection
1182 * @param eh TCP Connection Established handler
1183 * @param rh TCP Connection Receive data handler
1184 * @param ch TCP Connection Close handler
1185 * @param arg Handler argument
1186 */
1187 void tcp_set_handlers(struct tcp_conn *tc, tcp_estab_h *eh, tcp_recv_h *rh,
1188 tcp_close_h *ch, void *arg)
1189 {
1190 if (!tc)
1191 return;
1192
1193 tc->estabh = eh;
1194 tc->recvh = rh;
1195 tc->closeh = ch;
1196 tc->arg = arg;
1197 }
1198
1199
1200 /**
1201 * Get local network address of TCP Socket
1202 *
1203 * @param ts TCP Socket
1204 * @param local Returned local network address
1205 *
1206 * @return 0 if success, otherwise errorcode
1207 */
1208 int tcp_sock_local_get(const struct tcp_sock *ts, struct sa *local)
1209 {
1210 if (!ts || !local)
1211 return EINVAL;
1212
1213 sa_init(local, AF_UNSPEC);
1214
1215 if (getsockname(ts->fd, &local->u.sa, &local->len) < 0) {
1216 DEBUG_WARNING("local get: getsockname(): %m\n", errno);
1217 return errno;
1218 }
1219
1220 return 0;
1221 }
1222
1223
1224 /**
1225 * Get local network address of TCP Connection
1226 *
1227 * @param tc TCP Connection
1228 * @param local Returned local network address
1229 *
1230 * @return 0 if success, otherwise errorcode
1231 */
1232 int tcp_conn_local_get(const struct tcp_conn *tc, struct sa *local)
1233 {
1234 if (!tc || !local)
1235 return EINVAL;
1236
1237 sa_init(local, AF_UNSPEC);
1238
1239 if (getsockname(tc->fdc, &local->u.sa, &local->len) < 0) {
1240 DEBUG_WARNING("conn local get: getsockname(): %m\n", errno);
1241 return errno;
1242 }
1243
1244 return 0;
1245 }
1246
1247
1248 /**
1249 * Get remote peer network address of TCP Connection
1250 *
1251 * @param tc TCP Connection
1252 * @param peer Returned remote peer network address
1253 *
1254 * @return 0 if success, otherwise errorcode
1255 */
1256 int tcp_conn_peer_get(const struct tcp_conn *tc, struct sa *peer)
1257 {
1258 if (!tc || !peer)
1259 return EINVAL;
1260
1261 sa_init(peer, AF_UNSPEC);
1262
1263 if (getpeername(tc->fdc, &peer->u.sa, &peer->len) < 0) {
1264 DEBUG_WARNING("conn peer get: getpeername(): %m\n", errno);
1265 return errno;
1266 }
1267
1268 return 0;
1269 }
1270
1271
1272 /**
1273 * Set the maximum receive chunk size on a TCP Connection
1274 *
1275 * @param tc TCP Connection
1276 * @param rxsz Maximum receive chunk size
1277 */
1278 void tcp_conn_rxsz_set(struct tcp_conn *tc, size_t rxsz)
1279 {
1280 if (!tc)
1281 return;
1282
1283 tc->rxsz = rxsz;
1284 }
1285
1286
1287 /**
1288 * Set the maximum send queue size on a TCP Connection
1289 *
1290 * @param tc TCP Connection
1291 * @param txqsz Maximum send queue size
1292 */
1293 void tcp_conn_txqsz_set(struct tcp_conn *tc, size_t txqsz)
1294 {
1295 if (!tc)
1296 return;
1297
1298 tc->txqsz_max = txqsz;
1299 }
1300
1301
1302 /**
1303 * Get the file descriptor of a TCP Connection
1304 *
1305 * @param tc TCP-Connection
1306 *
1307 * @return File destriptor, or -1 if errors
1308 */
1309 int tcp_conn_fd(const struct tcp_conn *tc)
1310 {
1311 return tc ? tc->fdc : -1;
1312 }
1313
1314
1315 /**
1316 * Get the current length of the transmit queue on a TCP Connection
1317 *
1318 * @param tc TCP-Connection
1319 *
1320 * @return Current transmit queue length, or 0 if errors
1321 */
1322 size_t tcp_conn_txqsz(const struct tcp_conn *tc)
1323 {
1324 return tc ? tc->txqsz : 0;
1325 }
1326
1327
1328 static bool sort_handler(struct le *le1, struct le *le2, void *arg)
1329 {
1330 struct tcp_helper *th1 = le1->data, *th2 = le2->data;
1331 (void)arg;
1332
1333 return th1->layer <= th2->layer;
1334 }
1335
1336
1337 /**
1338 * Register a new TCP-helper on a TCP-Connection
1339 *
1340 * @param thp Pointer to allocated TCP helper
1341 * @param tc TCP Connection
1342 * @param layer Protocol layer; higher number means higher up in stack
1343 * @param eh Established handler
1344 * @param sh Send handler
1345 * @param rh Receive handler
1346 * @param arg Handler argument
1347 *
1348 * @return 0 if success, otherwise errorcode
1349 */
1350 int tcp_register_helper(struct tcp_helper **thp, struct tcp_conn *tc,
1351 int layer,
1352 tcp_helper_estab_h *eh, tcp_helper_send_h *sh,
1353 tcp_helper_recv_h *rh, void *arg)
1354 {
1355 struct tcp_helper *th;
1356
1357 if (!tc)
1358 return EINVAL;
1359
1360 th = mem_zalloc(sizeof(*th), helper_destructor);
1361 if (!th)
1362 return ENOMEM;
1363
1364 list_append(&tc->helpers, &th->le, th);
1365
1366 th->layer = layer;
1367 th->estabh = eh ? eh : helper_estab_handler;
1368 th->sendh = sh ? sh : helper_send_handler;
1369 th->recvh = rh ? rh : helper_recv_handler;
1370 th->arg = arg;
1371
1372 list_sort(&tc->helpers, sort_handler, NULL);
1373
1374 if (thp)
1375 *thp = th;
1376
1377 return 0;
1378 }
1379