libcoap 4.3.0
coap_tcp.c
Go to the documentation of this file.
1/*
2 * coap_tcp.c -- TCP functions for libcoap
3 *
4 * Copyright (C) 2019 Olaf Bergmann <bergmann@tzi.org> and others
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * This file is part of the CoAP library libcoap. Please see README for terms
9 * of use.
10 */
11
12#include "coap3/coap_internal.h"
13
14#include <errno.h>
15#include <sys/types.h>
16#ifdef HAVE_SYS_SOCKET_H
17# include <sys/socket.h>
18# define OPTVAL_T(t) (t)
19# define OPTVAL_GT(t) (t)
20#endif
21#ifdef HAVE_SYS_IOCTL_H
22 #include <sys/ioctl.h>
23#endif
24#ifdef HAVE_WS2TCPIP_H
25#include <ws2tcpip.h>
26# define OPTVAL_T(t) (const char*)(t)
27# define OPTVAL_GT(t) (char*)(t)
28# undef CMSG_DATA
29# define CMSG_DATA WSA_CMSG_DATA
30#endif
31
32int
34 return !COAP_DISABLE_TCP;
35}
36
37#if !COAP_DISABLE_TCP
38int
40 const coap_address_t *local_if,
41 const coap_address_t *server,
42 int default_port,
43 coap_address_t *local_addr,
44 coap_address_t *remote_addr) {
45 int on = 1;
46#ifndef RIOT_VERSION
47 int off = 0;
48#endif /* RIOT_VERSION */
49#ifdef _WIN32
50 u_long u_on = 1;
51#endif
52 coap_address_t connect_addr;
53 coap_address_copy( &connect_addr, server );
54
55 sock->flags &= ~COAP_SOCKET_CONNECTED;
56 sock->fd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0);
57
58 if (sock->fd == COAP_INVALID_SOCKET) {
60 "coap_socket_connect_tcp1: socket: %s\n",
62 goto error;
63 }
64
65#ifndef RIOT_VERSION
66#ifdef _WIN32
67 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
68#else
69 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
70#endif
72 "coap_socket_connect_tcp1: ioctl FIONBIO: %s\n",
74 }
75#endif /* RIOT_VERSION */
76
77 switch (server->addr.sa.sa_family) {
78 case AF_INET:
79 if (connect_addr.addr.sin.sin_port == 0)
80 connect_addr.addr.sin.sin_port = htons(default_port);
81 break;
82 case AF_INET6:
83 if (connect_addr.addr.sin6.sin6_port == 0)
84 connect_addr.addr.sin6.sin6_port = htons(default_port);
85#ifndef RIOT_VERSION
86 /* Configure the socket as dual-stacked */
87 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
89 "coap_socket_connect_tcp1: setsockopt IPV6_V6ONLY: %s\n",
91#endif /* RIOT_VERSION */
92 break;
93 default:
94 coap_log(LOG_ALERT, "coap_socket_connect_tcp1: unsupported sa_family\n");
95 break;
96 }
97
98 if (local_if && local_if->addr.sa.sa_family) {
99 coap_address_copy(local_addr, local_if);
100 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
102 "coap_socket_connect_tcp1: setsockopt SO_REUSEADDR: %s\n",
104 if (bind(sock->fd, &local_if->addr.sa,
105 local_if->addr.sa.sa_family == AF_INET ?
106 (socklen_t)sizeof(struct sockaddr_in) :
107 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
108 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: bind: %s\n",
110 goto error;
111 }
112 } else {
113 local_addr->addr.sa.sa_family = server->addr.sa.sa_family;
114 }
115
116 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
117#ifdef _WIN32
118 if (WSAGetLastError() == WSAEWOULDBLOCK) {
119#else
120 if (errno == EINPROGRESS) {
121#endif
122 /*
123 * COAP_SOCKET_CONNECTED needs to be set here as there will be reads/writes
124 * by underlying TLS libraries during connect() and we do not want to
125 * assert() in coap_read_session() or coap_write_session() when called by coap_read()
126 */
128 return 1;
129 }
130 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: connect: %s\n",
132 goto error;
133 }
134
135 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
136 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getsockname: %s\n",
138 }
139
140 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
141 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getpeername: %s\n",
143 }
144
146 return 1;
147
148error:
149 coap_socket_close(sock);
150 return 0;
151}
152
153int
155 coap_address_t *local_addr,
156 coap_address_t *remote_addr) {
157 int error = 0;
158#ifdef _WIN32
159 int optlen = (int)sizeof( error );
160#else
161 socklen_t optlen = (socklen_t)sizeof( error );
162#endif
163
165
166 if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, OPTVAL_GT(&error),
167 &optlen) == COAP_SOCKET_ERROR) {
168 coap_log(LOG_WARNING, "coap_socket_finish_connect_tcp: getsockopt: %s\n",
170 }
171
172 if (error) {
174 "coap_socket_finish_connect_tcp: connect failed: %s\n",
176 coap_socket_close(sock);
177 return 0;
178 }
179
180 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
181 coap_log(LOG_WARNING, "coap_socket_connect_tcp: getsockname: %s\n",
183 }
184
185 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
186 coap_log(LOG_WARNING, "coap_socket_connect_tcp: getpeername: %s\n",
188 }
189
190 return 1;
191}
192
193int
195 const coap_address_t *listen_addr,
196 coap_address_t *bound_addr) {
197 int on = 1;
198#ifndef RIOT_VERSION
199 int off = 0;
200#endif /* RIOT_VERSION */
201#ifdef _WIN32
202 u_long u_on = 1;
203#endif
204
205 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_STREAM, 0);
206
207 if (sock->fd == COAP_INVALID_SOCKET) {
208 coap_log(LOG_WARNING, "coap_socket_bind_tcp: socket: %s\n",
210 goto error;
211 }
212
213#ifndef RIOT_VERSION
214#ifdef _WIN32
215 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
216#else
217 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
218#endif
219 coap_log(LOG_WARNING, "coap_socket_bind_tcp: ioctl FIONBIO: %s\n",
221 }
222#endif /* RIOT_VERSION */
223 if (setsockopt (sock->fd, SOL_SOCKET, SO_KEEPALIVE, OPTVAL_T(&on),
224 sizeof (on)) == COAP_SOCKET_ERROR)
226 "coap_socket_bind_tcp: setsockopt SO_KEEPALIVE: %s\n",
228
229 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on),
230 sizeof(on)) == COAP_SOCKET_ERROR)
232 "coap_socket_bind_tcp: setsockopt SO_REUSEADDR: %s\n",
234
235 switch (listen_addr->addr.sa.sa_family) {
236 case AF_INET:
237 break;
238 case AF_INET6:
239#ifndef RIOT_VERSION
240 /* Configure the socket as dual-stacked */
241 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
243 "coap_socket_bind_tcp: setsockopt IPV6_V6ONLY: %s\n",
245#endif /* RIOT_VERSION */
246 break;
247 default:
248 coap_log(LOG_ALERT, "coap_socket_bind_tcp: unsupported sa_family\n");
249 }
250
251 if (bind(sock->fd, &listen_addr->addr.sa,
252 listen_addr->addr.sa.sa_family == AF_INET ?
253 (socklen_t)sizeof(struct sockaddr_in) :
254 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
255 coap_log(LOG_ALERT, "coap_socket_bind_tcp: bind: %s\n",
257 goto error;
258 }
259
260 bound_addr->size = (socklen_t)sizeof(*bound_addr);
261 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
262 coap_log(LOG_WARNING, "coap_socket_bind_tcp: getsockname: %s\n",
264 goto error;
265 }
266
267 if (listen(sock->fd, 5) == COAP_SOCKET_ERROR) {
268 coap_log(LOG_ALERT, "coap_socket_bind_tcp: listen: %s\n",
270 goto error;
271 }
272
273 return 1;
274
275error:
276 coap_socket_close(sock);
277 return 0;
278}
279
280int
282 coap_socket_t *new_client,
283 coap_address_t *local_addr,
284 coap_address_t *remote_addr) {
285#ifndef RIOT_VERSION
286#ifdef _WIN32
287 u_long u_on = 1;
288#else
289 int on = 1;
290#endif
291#endif /* RIOT_VERSION */
292
293 server->flags &= ~COAP_SOCKET_CAN_ACCEPT;
294
295 new_client->fd = accept(server->fd, &remote_addr->addr.sa,
296 &remote_addr->size);
297 if (new_client->fd == COAP_INVALID_SOCKET) {
298 coap_log(LOG_WARNING, "coap_socket_accept_tcp: accept: %s\n",
300 return 0;
301 }
302
303 if (getsockname( new_client->fd, &local_addr->addr.sa, &local_addr->size) < 0)
304 coap_log(LOG_WARNING, "coap_socket_accept_tcp: getsockname: %s\n",
306
307#ifndef RIOT_VERSION
308 #ifdef _WIN32
309 if (ioctlsocket(new_client->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
310#else
311 if (ioctl(new_client->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
312#endif
313 coap_log(LOG_WARNING, "coap_socket_accept_tcp: ioctl FIONBIO: %s\n",
315 }
316#endif /* RIOT_VERSION */
317 return 1;
318}
319#endif /* !COAP_DISABLE_TCP */
COAP_STATIC_INLINE void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: address.h:152
Pulls together all the internal only header files.
const char * coap_socket_format_errno(int error)
Definition: coap_io.c:1499
void coap_socket_close(coap_socket_t *sock)
Definition: coap_io.c:368
const char * coap_socket_strerror(void)
Definition: coap_io.c:1502
#define COAP_SOCKET_ERROR
Definition: coap_io.h:44
#define COAP_INVALID_SOCKET
Definition: coap_io.h:45
#define COAP_SOCKET_CAN_CONNECT
non blocking client socket can now connect without blocking
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
#define COAP_SOCKET_CONNECTED
the socket is connected
int coap_tcp_is_supported(void)
Check whether TCP is available.
Definition: coap_tcp.c:33
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:152
@ LOG_ALERT
Alert.
Definition: coap_debug.h:53
@ LOG_WARNING
Warning.
Definition: coap_debug.h:56
int coap_socket_bind_tcp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Create a new TCP socket and then listen for new incoming TCP sessions.
Definition: coap_tcp.c:194
int coap_socket_connect_tcp1(coap_socket_t *sock, const coap_address_t *local_if, const coap_address_t *server, int default_port, coap_address_t *local_addr, coap_address_t *remote_addr)
Create a new TCP socket and initiate the connection.
Definition: coap_tcp.c:39
int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, coap_address_t *remote_addr)
Accept a new incoming TCP session.
Definition: coap_tcp.c:281
int coap_socket_connect_tcp2(coap_socket_t *sock, coap_address_t *local_addr, coap_address_t *remote_addr)
Complete the TCP Connection.
Definition: coap_tcp.c:154
multi-purpose address abstraction
Definition: address.h:96
socklen_t size
size of addr
Definition: address.h:97
struct sockaddr_in sin
Definition: address.h:100
struct sockaddr_in6 sin6
Definition: address.h:101
struct sockaddr sa
Definition: address.h:99
union coap_address_t::@0 addr
coap_socket_flags_t flags