2 * Copyright (c) 2009-2010 The FreeBSD Foundation
3 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h> /* MAXHOSTNAMELEN */
35 #include <sys/socket.h>
37 #include <arpa/inet.h>
39 #include <netinet/in.h>
40 #include <netinet/tcp.h>
52 #include "proto_impl.h"
55 #define TCP_CTX_MAGIC 0x7c41c
58 struct sockaddr_storage tc_sa
;
61 #define TCP_SIDE_CLIENT 0
62 #define TCP_SIDE_SERVER_LISTEN 1
63 #define TCP_SIDE_SERVER_WORK 2
66 static int tcp_connect_wait(void *ctx
, int timeout
);
67 static void tcp_close(void *ctx
);
70 * Function converts the given string to unsigned number.
73 numfromstr(const char *str
, intmax_t minnum
, intmax_t maxnum
, intmax_t *nump
)
78 goto invalid
; /* Empty string. */
80 for (; *str
!= '\0'; str
++) {
81 if (*str
< '0' || *str
> '9')
82 goto invalid
; /* Non-digit character. */
84 if (num
> num
* 10 + digit
)
85 goto invalid
; /* Overflow. */
86 num
= num
* 10 + digit
;
88 goto invalid
; /* Too big. */
91 goto invalid
; /* Too small. */
100 tcp_addr(const char *addr
, int defport
, struct sockaddr_storage
*sap
)
102 char iporhost
[MAXHOSTNAMELEN
], portstr
[6];
103 struct addrinfo hints
;
104 struct addrinfo
*res
;
113 bzero(&hints
, sizeof(hints
));
114 hints
.ai_flags
= AI_ADDRCONFIG
| AI_NUMERICSERV
;
115 hints
.ai_family
= PF_UNSPEC
;
116 hints
.ai_socktype
= SOCK_STREAM
;
117 hints
.ai_protocol
= IPPROTO_TCP
;
119 if (strncasecmp(addr
, "tcp4://", 7) == 0) {
121 hints
.ai_family
= PF_INET
;
122 } else if (strncasecmp(addr
, "tcp6://", 7) == 0) {
124 hints
.ai_family
= PF_INET6
;
125 } else if (strncasecmp(addr
, "tcp://", 6) == 0) {
129 * Because TCP is the default assume IP or host is given without
135 * Extract optional port.
136 * There are three cases to consider.
137 * 1. hostname with port, eg. freefall.freebsd.org:8457
138 * 2. IPv4 address with port, eg. 192.168.0.101:8457
139 * 3. IPv6 address with port, eg. [fe80::1]:8457
140 * We discover IPv6 address by checking for two colons and if port is
141 * given, the address has to start with [.
144 if (strchr(addr
, ':') != strrchr(addr
, ':')) {
146 pp
= strrchr(addr
, ':');
148 pp
= strrchr(addr
, ':');
151 /* Port not given, use the default. */
154 if (numfromstr(pp
+ 1, 1, 65535, &port
) == -1)
157 (void)snprintf(portstr
, sizeof(portstr
), "%jd", (intmax_t)port
);
158 /* Extract host name or IP address. */
160 size
= sizeof(iporhost
);
161 if (strlcpy(iporhost
, addr
, size
) >= size
)
162 return (ENAMETOOLONG
);
163 } else if (addr
[0] == '[' && pp
[-1] == ']') {
164 size
= (size_t)(pp
- addr
- 2 + 1);
165 if (size
> sizeof(iporhost
))
166 return (ENAMETOOLONG
);
167 (void)strlcpy(iporhost
, addr
+ 1, size
);
169 size
= (size_t)(pp
- addr
+ 1);
170 if (size
> sizeof(iporhost
))
171 return (ENAMETOOLONG
);
172 (void)strlcpy(iporhost
, addr
, size
);
175 error
= getaddrinfo(iporhost
, portstr
, &hints
, &res
);
177 pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost
,
178 portstr
, gai_strerror(error
));
184 memcpy(sap
, res
->ai_addr
, res
->ai_addrlen
);
192 tcp_setup_new(const char *addr
, int side
, void **ctxp
)
194 struct tcp_ctx
*tctx
;
197 PJDLOG_ASSERT(addr
!= NULL
);
198 PJDLOG_ASSERT(side
== TCP_SIDE_CLIENT
||
199 side
== TCP_SIDE_SERVER_LISTEN
);
200 PJDLOG_ASSERT(ctxp
!= NULL
);
202 tctx
= malloc(sizeof(*tctx
));
206 /* Parse given address. */
207 if ((ret
= tcp_addr(addr
, PROTO_TCP_DEFAULT_PORT
, &tctx
->tc_sa
)) != 0) {
212 PJDLOG_ASSERT(tctx
->tc_sa
.ss_family
!= AF_UNSPEC
);
214 tctx
->tc_fd
= socket(tctx
->tc_sa
.ss_family
, SOCK_STREAM
, 0);
215 if (tctx
->tc_fd
== -1) {
221 PJDLOG_ASSERT(tctx
->tc_sa
.ss_family
!= AF_UNSPEC
);
223 /* Socket settings. */
225 if (setsockopt(tctx
->tc_fd
, IPPROTO_TCP
, TCP_NODELAY
, &nodelay
,
226 sizeof(nodelay
)) == -1) {
227 pjdlog_errno(LOG_WARNING
, "Unable to set TCP_NOELAY");
230 tctx
->tc_side
= side
;
231 tctx
->tc_magic
= TCP_CTX_MAGIC
;
238 tcp_setup_wrap(int fd
, int side
, void **ctxp
)
240 struct tcp_ctx
*tctx
;
242 PJDLOG_ASSERT(fd
>= 0);
243 PJDLOG_ASSERT(side
== TCP_SIDE_CLIENT
||
244 side
== TCP_SIDE_SERVER_WORK
);
245 PJDLOG_ASSERT(ctxp
!= NULL
);
247 tctx
= malloc(sizeof(*tctx
));
252 tctx
->tc_sa
.ss_family
= AF_UNSPEC
;
253 tctx
->tc_side
= side
;
254 tctx
->tc_magic
= TCP_CTX_MAGIC
;
261 tcp_client(const char *srcaddr
, const char *dstaddr
, void **ctxp
)
263 struct tcp_ctx
*tctx
;
264 struct sockaddr_storage sa
;
267 ret
= tcp_setup_new(dstaddr
, TCP_SIDE_CLIENT
, ctxp
);
273 ret
= tcp_addr(srcaddr
, 0, &sa
);
278 if (bind(tctx
->tc_fd
, (struct sockaddr
*)&sa
, sa
.ss_len
) == -1) {
287 tcp_connect(void *ctx
, int timeout
)
289 struct tcp_ctx
*tctx
= ctx
;
292 PJDLOG_ASSERT(tctx
!= NULL
);
293 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
294 PJDLOG_ASSERT(tctx
->tc_side
== TCP_SIDE_CLIENT
);
295 PJDLOG_ASSERT(tctx
->tc_fd
>= 0);
296 PJDLOG_ASSERT(tctx
->tc_sa
.ss_family
!= AF_UNSPEC
);
297 PJDLOG_ASSERT(timeout
>= -1);
299 flags
= fcntl(tctx
->tc_fd
, F_GETFL
);
301 pjdlog_common(LOG_DEBUG
, 1, errno
, "fcntl(F_GETFL) failed");
305 * We make socket non-blocking so we can handle connection timeout
309 if (fcntl(tctx
->tc_fd
, F_SETFL
, flags
) == -1) {
310 pjdlog_common(LOG_DEBUG
, 1, errno
,
311 "fcntl(F_SETFL, O_NONBLOCK) failed");
315 if (connect(tctx
->tc_fd
, (struct sockaddr
*)&tctx
->tc_sa
,
316 tctx
->tc_sa
.ss_len
) == 0) {
322 if (errno
!= EINPROGRESS
) {
324 pjdlog_common(LOG_DEBUG
, 1, errno
, "connect() failed");
329 return (tcp_connect_wait(ctx
, timeout
));
331 flags
&= ~O_NONBLOCK
;
332 if (fcntl(tctx
->tc_fd
, F_SETFL
, flags
) == -1) {
335 pjdlog_common(LOG_DEBUG
, 1, errno
,
336 "fcntl(F_SETFL, ~O_NONBLOCK) failed");
342 tcp_connect_wait(void *ctx
, int timeout
)
344 struct tcp_ctx
*tctx
= ctx
;
348 int error
, flags
, ret
;
350 PJDLOG_ASSERT(tctx
!= NULL
);
351 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
352 PJDLOG_ASSERT(tctx
->tc_side
== TCP_SIDE_CLIENT
);
353 PJDLOG_ASSERT(tctx
->tc_fd
>= 0);
354 PJDLOG_ASSERT(timeout
>= 0);
360 FD_SET(tctx
->tc_fd
, &fdset
);
361 ret
= select(tctx
->tc_fd
+ 1, NULL
, &fdset
, NULL
, &tv
);
365 } else if (ret
== -1) {
369 pjdlog_common(LOG_DEBUG
, 1, errno
, "select() failed");
372 PJDLOG_ASSERT(ret
> 0);
373 PJDLOG_ASSERT(FD_ISSET(tctx
->tc_fd
, &fdset
));
374 esize
= sizeof(error
);
375 if (getsockopt(tctx
->tc_fd
, SOL_SOCKET
, SO_ERROR
, &error
,
378 pjdlog_common(LOG_DEBUG
, 1, errno
,
379 "getsockopt(SO_ERROR) failed");
383 pjdlog_common(LOG_DEBUG
, 1, error
,
384 "getsockopt(SO_ERROR) returned error");
389 flags
= fcntl(tctx
->tc_fd
, F_GETFL
);
393 pjdlog_common(LOG_DEBUG
, 1, errno
, "fcntl(F_GETFL) failed");
396 flags
&= ~O_NONBLOCK
;
397 if (fcntl(tctx
->tc_fd
, F_SETFL
, flags
) == -1) {
400 pjdlog_common(LOG_DEBUG
, 1, errno
,
401 "fcntl(F_SETFL, ~O_NONBLOCK) failed");
407 tcp_server(const char *addr
, void **ctxp
)
409 struct tcp_ctx
*tctx
;
412 ret
= tcp_setup_new(addr
, TCP_SIDE_SERVER_LISTEN
, ctxp
);
419 /* Ignore failure. */
420 (void)setsockopt(tctx
->tc_fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
,
423 PJDLOG_ASSERT(tctx
->tc_sa
.ss_family
!= AF_UNSPEC
);
425 if (bind(tctx
->tc_fd
, (struct sockaddr
*)&tctx
->tc_sa
,
426 tctx
->tc_sa
.ss_len
) == -1) {
431 if (listen(tctx
->tc_fd
, 8) == -1) {
441 tcp_accept(void *ctx
, void **newctxp
)
443 struct tcp_ctx
*tctx
= ctx
;
444 struct tcp_ctx
*newtctx
;
448 PJDLOG_ASSERT(tctx
!= NULL
);
449 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
450 PJDLOG_ASSERT(tctx
->tc_side
== TCP_SIDE_SERVER_LISTEN
);
451 PJDLOG_ASSERT(tctx
->tc_fd
>= 0);
452 PJDLOG_ASSERT(tctx
->tc_sa
.ss_family
!= AF_UNSPEC
);
454 newtctx
= malloc(sizeof(*newtctx
));
458 fromlen
= tctx
->tc_sa
.ss_len
;
459 newtctx
->tc_fd
= accept(tctx
->tc_fd
, (struct sockaddr
*)&tctx
->tc_sa
,
461 if (newtctx
->tc_fd
== -1) {
467 newtctx
->tc_side
= TCP_SIDE_SERVER_WORK
;
468 newtctx
->tc_magic
= TCP_CTX_MAGIC
;
475 tcp_wrap(int fd
, bool client
, void **ctxp
)
478 return (tcp_setup_wrap(fd
,
479 client
? TCP_SIDE_CLIENT
: TCP_SIDE_SERVER_WORK
, ctxp
));
483 tcp_send(void *ctx
, const unsigned char *data
, size_t size
, int fd
)
485 struct tcp_ctx
*tctx
= ctx
;
487 PJDLOG_ASSERT(tctx
!= NULL
);
488 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
489 PJDLOG_ASSERT(tctx
->tc_fd
>= 0);
490 PJDLOG_ASSERT(fd
== -1);
492 return (proto_common_send(tctx
->tc_fd
, data
, size
, -1));
496 tcp_recv(void *ctx
, unsigned char *data
, size_t size
, int *fdp
)
498 struct tcp_ctx
*tctx
= ctx
;
500 PJDLOG_ASSERT(tctx
!= NULL
);
501 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
502 PJDLOG_ASSERT(tctx
->tc_fd
>= 0);
503 PJDLOG_ASSERT(fdp
== NULL
);
505 return (proto_common_recv(tctx
->tc_fd
, data
, size
, NULL
));
509 tcp_descriptor(const void *ctx
)
511 const struct tcp_ctx
*tctx
= ctx
;
513 PJDLOG_ASSERT(tctx
!= NULL
);
514 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
516 return (tctx
->tc_fd
);
520 tcp_address_match(const void *ctx
, const char *addr
)
522 const struct tcp_ctx
*tctx
= ctx
;
523 struct sockaddr_storage sa1
, sa2
;
526 PJDLOG_ASSERT(tctx
!= NULL
);
527 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
529 if (tcp_addr(addr
, PROTO_TCP_DEFAULT_PORT
, &sa1
) != 0)
533 if (getpeername(tctx
->tc_fd
, (struct sockaddr
*)&sa2
, &salen
) == -1)
536 if (sa1
.ss_family
!= sa2
.ss_family
|| sa1
.ss_len
!= sa2
.ss_len
)
539 switch (sa1
.ss_family
) {
542 struct sockaddr_in
*sin1
, *sin2
;
544 sin1
= (struct sockaddr_in
*)&sa1
;
545 sin2
= (struct sockaddr_in
*)&sa2
;
547 return (memcmp(&sin1
->sin_addr
, &sin2
->sin_addr
,
548 sizeof(sin1
->sin_addr
)) == 0);
552 struct sockaddr_in6
*sin1
, *sin2
;
554 sin1
= (struct sockaddr_in6
*)&sa1
;
555 sin2
= (struct sockaddr_in6
*)&sa2
;
557 return (memcmp(&sin1
->sin6_addr
, &sin2
->sin6_addr
,
558 sizeof(sin1
->sin6_addr
)) == 0);
566 tcp_local_address(const void *ctx
, char *addr
, size_t size
)
568 const struct tcp_ctx
*tctx
= ctx
;
569 struct sockaddr_storage sa
;
572 PJDLOG_ASSERT(tctx
!= NULL
);
573 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
576 if (getsockname(tctx
->tc_fd
, (struct sockaddr
*)&sa
, &salen
) == -1) {
577 PJDLOG_VERIFY(strlcpy(addr
, "N/A", size
) < size
);
580 PJDLOG_VERIFY(snprintf(addr
, size
, "tcp://%S", &sa
) < (ssize_t
)size
);
584 tcp_remote_address(const void *ctx
, char *addr
, size_t size
)
586 const struct tcp_ctx
*tctx
= ctx
;
587 struct sockaddr_storage sa
;
590 PJDLOG_ASSERT(tctx
!= NULL
);
591 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
594 if (getpeername(tctx
->tc_fd
, (struct sockaddr
*)&sa
, &salen
) == -1) {
595 PJDLOG_VERIFY(strlcpy(addr
, "N/A", size
) < size
);
598 PJDLOG_VERIFY(snprintf(addr
, size
, "tcp://%S", &sa
) < (ssize_t
)size
);
604 struct tcp_ctx
*tctx
= ctx
;
606 PJDLOG_ASSERT(tctx
!= NULL
);
607 PJDLOG_ASSERT(tctx
->tc_magic
== TCP_CTX_MAGIC
);
609 if (tctx
->tc_fd
>= 0)
615 static struct proto tcp_proto
= {
617 .prt_client
= tcp_client
,
618 .prt_connect
= tcp_connect
,
619 .prt_connect_wait
= tcp_connect_wait
,
620 .prt_server
= tcp_server
,
621 .prt_accept
= tcp_accept
,
622 .prt_wrap
= tcp_wrap
,
623 .prt_send
= tcp_send
,
624 .prt_recv
= tcp_recv
,
625 .prt_descriptor
= tcp_descriptor
,
626 .prt_address_match
= tcp_address_match
,
627 .prt_local_address
= tcp_local_address
,
628 .prt_remote_address
= tcp_remote_address
,
629 .prt_close
= tcp_close
632 static __constructor
void
636 proto_register(&tcp_proto
, true);