libcoap 4.3.1
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
17#include "coap3/coap_internal.h"
18
19#include <errno.h>
20#include <sys/types.h>
21#ifdef HAVE_SYS_SOCKET_H
22# include <sys/socket.h>
23# define OPTVAL_T(t) (t)
24# define OPTVAL_GT(t) (t)
25#endif
26#ifdef HAVE_SYS_IOCTL_H
27 #include <sys/ioctl.h>
28#endif
29#ifdef HAVE_WS2TCPIP_H
30#include <ws2tcpip.h>
31# define OPTVAL_T(t) (const char*)(t)
32# define OPTVAL_GT(t) (char*)(t)
33# undef CMSG_DATA
34# define CMSG_DATA WSA_CMSG_DATA
35#endif
36
37int
39 return !COAP_DISABLE_TCP;
40}
41
42#if !COAP_DISABLE_TCP
43int
45 const coap_address_t *local_if,
46 const coap_address_t *server,
47 int default_port,
48 coap_address_t *local_addr,
49 coap_address_t *remote_addr) {
50 int on = 1;
51#ifndef RIOT_VERSION
52 int off = 0;
53#endif /* RIOT_VERSION */
54#ifdef _WIN32
55 u_long u_on = 1;
56#endif
57 coap_address_t connect_addr;
58 coap_address_copy( &connect_addr, server );
59
60 sock->flags &= ~COAP_SOCKET_CONNECTED;
61 sock->fd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0);
62
63 if (sock->fd == COAP_INVALID_SOCKET) {
65 "coap_socket_connect_tcp1: socket: %s\n",
67 goto error;
68 }
69
70#ifndef RIOT_VERSION
71#ifdef _WIN32
72 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
73#else
74 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
75#endif
77 "coap_socket_connect_tcp1: ioctl FIONBIO: %s\n",
79 }
80#endif /* RIOT_VERSION */
81
82 switch (server->addr.sa.sa_family) {
83 case AF_INET:
84 if (connect_addr.addr.sin.sin_port == 0)
85 connect_addr.addr.sin.sin_port = htons(default_port);
86 break;
87 case AF_INET6:
88 if (connect_addr.addr.sin6.sin6_port == 0)
89 connect_addr.addr.sin6.sin6_port = htons(default_port);
90#ifndef RIOT_VERSION
91 /* Configure the socket as dual-stacked */
92 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
94 "coap_socket_connect_tcp1: setsockopt IPV6_V6ONLY: %s\n",
96#endif /* RIOT_VERSION */
97 break;
98 default:
99 coap_log(LOG_ALERT, "coap_socket_connect_tcp1: unsupported sa_family\n");
100 break;
101 }
102
103 if (local_if && local_if->addr.sa.sa_family) {
104 coap_address_copy(local_addr, local_if);
105 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
107 "coap_socket_connect_tcp1: setsockopt SO_REUSEADDR: %s\n",
109 if (bind(sock->fd, &local_if->addr.sa,
110 local_if->addr.sa.sa_family == AF_INET ?
111 (socklen_t)sizeof(struct sockaddr_in) :
112 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
113 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: bind: %s\n",
115 goto error;
116 }
117 } else {
118 local_addr->addr.sa.sa_family = server->addr.sa.sa_family;
119 }
120
121 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
122#ifdef _WIN32
123 if (WSAGetLastError() == WSAEWOULDBLOCK) {
124#else
125 if (errno == EINPROGRESS) {
126#endif
127 /*
128 * COAP_SOCKET_CONNECTED needs to be set here as there will be reads/writes
129 * by underlying TLS libraries during connect() and we do not want to
130 * assert() in coap_read_session() or coap_write_session() when called by coap_read()
131 */
133 return 1;
134 }
135 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: connect: %s\n",
137 goto error;
138 }
139
140 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
141 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getsockname: %s\n",
143 }
144
145 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
146 coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getpeername: %s\n",
148 }
149
151 return 1;
152
153error:
154 coap_socket_close(sock);
155 return 0;
156}
157
158int
160 coap_address_t *local_addr,
161 coap_address_t *remote_addr) {
162 int error = 0;
163#ifdef _WIN32
164 int optlen = (int)sizeof( error );
165#else
166 socklen_t optlen = (socklen_t)sizeof( error );
167#endif
168
170
171 if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, OPTVAL_GT(&error),
172 &optlen) == COAP_SOCKET_ERROR) {
173 coap_log(LOG_WARNING, "coap_socket_finish_connect_tcp: getsockopt: %s\n",
175 }
176
177 if (error) {
179 "coap_socket_finish_connect_tcp: connect failed: %s\n",
181 coap_socket_close(sock);
182 return 0;
183 }
184
185 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
186 coap_log(LOG_WARNING, "coap_socket_connect_tcp: getsockname: %s\n",
188 }
189
190 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
191 coap_log(LOG_WARNING, "coap_socket_connect_tcp: getpeername: %s\n",
193 }
194
195 return 1;
196}
197
198int
200 const coap_address_t *listen_addr,
201 coap_address_t *bound_addr) {
202 int on = 1;
203#ifndef RIOT_VERSION
204 int off = 0;
205#endif /* RIOT_VERSION */
206#ifdef _WIN32
207 u_long u_on = 1;
208#endif
209
210 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_STREAM, 0);
211
212 if (sock->fd == COAP_INVALID_SOCKET) {
213 coap_log(LOG_WARNING, "coap_socket_bind_tcp: socket: %s\n",
215 goto error;
216 }
217
218#ifndef RIOT_VERSION
219#ifdef _WIN32
220 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
221#else
222 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
223#endif
224 coap_log(LOG_WARNING, "coap_socket_bind_tcp: ioctl FIONBIO: %s\n",
226 }
227#endif /* RIOT_VERSION */
228 if (setsockopt (sock->fd, SOL_SOCKET, SO_KEEPALIVE, OPTVAL_T(&on),
229 sizeof (on)) == COAP_SOCKET_ERROR)
231 "coap_socket_bind_tcp: setsockopt SO_KEEPALIVE: %s\n",
233
234 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on),
235 sizeof(on)) == COAP_SOCKET_ERROR)
237 "coap_socket_bind_tcp: setsockopt SO_REUSEADDR: %s\n",
239
240 switch (listen_addr->addr.sa.sa_family) {
241 case AF_INET:
242 break;
243 case AF_INET6:
244#ifndef RIOT_VERSION
245 /* Configure the socket as dual-stacked */
246 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
248 "coap_socket_bind_tcp: setsockopt IPV6_V6ONLY: %s\n",
250#endif /* RIOT_VERSION */
251 break;
252 default:
253 coap_log(LOG_ALERT, "coap_socket_bind_tcp: unsupported sa_family\n");
254 }
255
256 if (bind(sock->fd, &listen_addr->addr.sa,
257 listen_addr->addr.sa.sa_family == AF_INET ?
258 (socklen_t)sizeof(struct sockaddr_in) :
259 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
260 coap_log(LOG_ALERT, "coap_socket_bind_tcp: bind: %s\n",
262 goto error;
263 }
264
265 bound_addr->size = (socklen_t)sizeof(*bound_addr);
266 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
267 coap_log(LOG_WARNING, "coap_socket_bind_tcp: getsockname: %s\n",
269 goto error;
270 }
271
272 if (listen(sock->fd, 5) == COAP_SOCKET_ERROR) {
273 coap_log(LOG_ALERT, "coap_socket_bind_tcp: listen: %s\n",
275 goto error;
276 }
277
278 return 1;
279
280error:
281 coap_socket_close(sock);
282 return 0;
283}
284
285int
287 coap_socket_t *new_client,
288 coap_address_t *local_addr,
289 coap_address_t *remote_addr) {
290#ifndef RIOT_VERSION
291#ifdef _WIN32
292 u_long u_on = 1;
293#else
294 int on = 1;
295#endif
296#endif /* RIOT_VERSION */
297
298 server->flags &= ~COAP_SOCKET_CAN_ACCEPT;
299
300 new_client->fd = accept(server->fd, &remote_addr->addr.sa,
301 &remote_addr->size);
302 if (new_client->fd == COAP_INVALID_SOCKET) {
303 coap_log(LOG_WARNING, "coap_socket_accept_tcp: accept: %s\n",
305 return 0;
306 }
307
308 if (getsockname( new_client->fd, &local_addr->addr.sa, &local_addr->size) < 0)
309 coap_log(LOG_WARNING, "coap_socket_accept_tcp: getsockname: %s\n",
311
312#ifndef RIOT_VERSION
313 #ifdef _WIN32
314 if (ioctlsocket(new_client->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
315#else
316 if (ioctl(new_client->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
317#endif
318 coap_log(LOG_WARNING, "coap_socket_accept_tcp: ioctl FIONBIO: %s\n",
320 }
321#endif /* RIOT_VERSION */
322 return 1;
323}
324#endif /* !COAP_DISABLE_TCP */
COAP_STATIC_INLINE void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: coap_address.h:152
Pulls together all the internal only header files.
void coap_socket_close(coap_socket_t *sock)
Definition: coap_io.c:377
const char * coap_socket_strerror(void)
Definition: coap_io.c:1604
const char * coap_socket_format_errno(int error)
Definition: coap_io.c:1601
#define COAP_SOCKET_ERROR
Definition: coap_io.h:49
#define COAP_INVALID_SOCKET
Definition: coap_io.h:50
#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:38
#define LOG_ALERT
Definition: coap_debug.h:63
#define LOG_WARNING
Definition: coap_debug.h:72
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:165
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:199
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:44
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:286
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:159
multi-purpose address abstraction
Definition: coap_address.h:96
socklen_t size
size of addr
Definition: coap_address.h:97
struct sockaddr_in sin
Definition: coap_address.h:100
struct sockaddr_in6 sin6
Definition: coap_address.h:101
struct sockaddr sa
Definition: coap_address.h:99
union coap_address_t::@0 addr
coap_socket_flags_t flags