/src/libcoap/src/coap_io.c
Line | Count | Source |
1 | | /* coap_io.c -- Default network I/O functions for libcoap |
2 | | * |
3 | | * Copyright (C) 2012,2014,2016-2026 Olaf Bergmann <bergmann@tzi.org> and others |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | * |
7 | | * This file is part of the CoAP library libcoap. Please see |
8 | | * README for terms of use. |
9 | | */ |
10 | | |
11 | | /** |
12 | | * @file coap_io.c |
13 | | * @brief Network I/O functions |
14 | | */ |
15 | | |
16 | | #include "coap3/coap_libcoap_build.h" |
17 | | |
18 | | #ifdef HAVE_STDIO_H |
19 | | # include <stdio.h> |
20 | | #endif |
21 | | #ifdef HAVE_UNISTD_H |
22 | | # include <unistd.h> |
23 | | #endif |
24 | | |
25 | | #ifndef __ZEPHYR__ |
26 | | #ifdef HAVE_SYS_SELECT_H |
27 | | # include <sys/select.h> |
28 | | #endif |
29 | | #ifdef HAVE_SYS_SOCKET_H |
30 | | # include <sys/socket.h> |
31 | | #endif |
32 | | #ifdef HAVE_SYS_IOCTL_H |
33 | | #include <sys/ioctl.h> |
34 | | #endif |
35 | | #ifdef HAVE_NETINET_IN_H |
36 | | # include <netinet/in.h> |
37 | | #endif |
38 | | #ifdef HAVE_SYS_UIO_H |
39 | | # include <sys/uio.h> |
40 | | #endif |
41 | | #ifdef _WIN32 |
42 | | #include <stdio.h> |
43 | | #endif /* _WIN32 */ |
44 | | #ifdef COAP_EPOLL_SUPPORT |
45 | | #include <sys/epoll.h> |
46 | | #include <sys/timerfd.h> |
47 | | #ifdef HAVE_LIMITS_H |
48 | | #include <limits.h> |
49 | | #endif |
50 | | #endif /* COAP_EPOLL_SUPPORT */ |
51 | | #else /* __ZEPHYR__ */ |
52 | | #include <sys/ioctl.h> |
53 | | #include <sys/select.h> |
54 | | #endif /* __ZEPHYR__ */ |
55 | | |
56 | | #if COAP_SERVER_SUPPORT |
57 | | coap_endpoint_t * |
58 | 0 | coap_malloc_endpoint(void) { |
59 | 0 | return (coap_endpoint_t *)coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t)); |
60 | 0 | } |
61 | | |
62 | | void |
63 | 0 | coap_mfree_endpoint(coap_endpoint_t *ep) { |
64 | 0 | coap_free_type(COAP_ENDPOINT, ep); |
65 | 0 | } |
66 | | #endif /* COAP_SERVER_SUPPORT */ |
67 | | |
68 | | #ifndef WITH_CONTIKI |
69 | | void |
70 | 0 | coap_update_io_timer(coap_context_t *context, coap_tick_t delay) { |
71 | 0 | #if COAP_EPOLL_SUPPORT |
72 | 0 | if (context->eptimerfd != -1) { |
73 | 0 | coap_tick_t now; |
74 | |
|
75 | 0 | coap_ticks(&now); |
76 | 0 | if (context->next_timeout == 0 || context->next_timeout > now + delay) { |
77 | 0 | struct itimerspec new_value; |
78 | 0 | int ret; |
79 | |
|
80 | 0 | context->next_timeout = now + delay; |
81 | 0 | memset(&new_value, 0, sizeof(new_value)); |
82 | 0 | if (delay == 0) { |
83 | 0 | new_value.it_value.tv_nsec = 1; /* small but not zero */ |
84 | 0 | } else { |
85 | 0 | new_value.it_value.tv_sec = delay / COAP_TICKS_PER_SECOND; |
86 | 0 | new_value.it_value.tv_nsec = (delay % COAP_TICKS_PER_SECOND) * |
87 | 0 | 1000000; |
88 | 0 | } |
89 | 0 | ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL); |
90 | 0 | if (ret == -1) { |
91 | 0 | coap_log_err("%s: timerfd_settime failed: %s (%d)\n", |
92 | 0 | "coap_update_io_timer", |
93 | 0 | coap_socket_strerror(), errno); |
94 | 0 | } |
95 | | #ifdef COAP_DEBUG_WAKEUP_TIMES |
96 | | else { |
97 | | coap_log_debug("****** Next wakeup time %3ld.%09ld\n", |
98 | | new_value.it_value.tv_sec, new_value.it_value.tv_nsec); |
99 | | } |
100 | | #endif /* COAP_DEBUG_WAKEUP_TIMES */ |
101 | 0 | } |
102 | 0 | } |
103 | | #else /* ! COAP_EPOLL_SUPPORT */ |
104 | | coap_tick_t now; |
105 | | |
106 | | coap_ticks(&now); |
107 | | if (context->next_timeout == 0 || context->next_timeout > now + delay) { |
108 | | context->next_timeout = now + delay; |
109 | | } |
110 | | #endif /* ! COAP_EPOLL_SUPPORT */ |
111 | 0 | } |
112 | | #endif /* ! WITH_CONTIKI */ |
113 | | |
114 | | #ifdef _WIN32 |
115 | | void |
116 | | coap_win_error_to_errno(void) { |
117 | | int w_error = WSAGetLastError(); |
118 | | switch (w_error) { |
119 | | case WSA_NOT_ENOUGH_MEMORY: |
120 | | errno = ENOMEM; |
121 | | break; |
122 | | case WSA_INVALID_PARAMETER: |
123 | | errno = EINVAL; |
124 | | break; |
125 | | case WSAEINTR: |
126 | | errno = EINTR; |
127 | | break; |
128 | | case WSAEBADF: |
129 | | errno = EBADF; |
130 | | break; |
131 | | case WSAEACCES: |
132 | | errno = EACCES; |
133 | | break; |
134 | | case WSAEFAULT: |
135 | | errno = EFAULT; |
136 | | break; |
137 | | case WSAEINVAL: |
138 | | errno = EINVAL; |
139 | | break; |
140 | | case WSAEMFILE: |
141 | | errno = EMFILE; |
142 | | break; |
143 | | case WSAEWOULDBLOCK: |
144 | | errno = EWOULDBLOCK; |
145 | | break; |
146 | | case WSAENETDOWN: |
147 | | errno = ENETDOWN; |
148 | | break; |
149 | | case WSAENETUNREACH: |
150 | | errno = ENETUNREACH; |
151 | | break; |
152 | | case WSAENETRESET: |
153 | | errno = ENETRESET; |
154 | | break; |
155 | | case WSAECONNABORTED: |
156 | | errno = ECONNABORTED; |
157 | | break; |
158 | | case WSAECONNRESET: |
159 | | errno = ECONNRESET; |
160 | | break; |
161 | | case WSAENOBUFS: |
162 | | errno = ENOBUFS; |
163 | | break; |
164 | | case WSAETIMEDOUT: |
165 | | errno = ETIMEDOUT; |
166 | | break; |
167 | | case WSAECONNREFUSED: |
168 | | errno = ECONNREFUSED; |
169 | | break; |
170 | | case WSAEADDRNOTAVAIL: |
171 | | errno = EADDRNOTAVAIL; |
172 | | break; |
173 | | default: |
174 | | coap_log_err("WSAGetLastError: %d mapping to errno failed - please fix\n", |
175 | | w_error); |
176 | | errno = EPERM; |
177 | | break; |
178 | | } |
179 | | } |
180 | | #endif /* _WIN32 */ |
181 | | |
182 | | #if !defined(WITH_LWIP) && !defined(__ZEPHYR__) |
183 | | #if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) ) |
184 | | /* define struct in6_pktinfo and struct in_pktinfo if not available |
185 | | FIXME: check with configure |
186 | | */ |
187 | | #if !defined(__MINGW32__) && !defined(RIOT_VERSION) |
188 | | struct in6_pktinfo { |
189 | | struct in6_addr ipi6_addr; /* src/dst IPv6 address */ |
190 | | unsigned int ipi6_ifindex; /* send/recv interface index */ |
191 | | }; |
192 | | |
193 | | struct in_pktinfo { |
194 | | int ipi_ifindex; |
195 | | struct in_addr ipi_spec_dst; |
196 | | struct in_addr ipi_addr; |
197 | | }; |
198 | | #endif /* ! __MINGW32__ && ! RIOT_VERSION */ |
199 | | #endif |
200 | | #endif /* ! WITH_LWIP && ! __ZEPHYR__ */ |
201 | | |
202 | | void |
203 | 0 | coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) { |
204 | 0 | *address = packet->payload; |
205 | 0 | *length = packet->length; |
206 | 0 | } |
207 | | |
208 | | COAP_API unsigned int |
209 | 0 | coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) { |
210 | 0 | unsigned int ret; |
211 | |
|
212 | 0 | coap_lock_lock(return 0); |
213 | 0 | ret = coap_io_prepare_epoll_lkd(ctx, now); |
214 | 0 | coap_lock_unlock(); |
215 | 0 | return ret; |
216 | 0 | } |
217 | | |
218 | | unsigned int |
219 | 0 | coap_io_prepare_epoll_lkd(coap_context_t *ctx, coap_tick_t now) { |
220 | | #ifndef COAP_EPOLL_SUPPORT |
221 | | (void)ctx; |
222 | | (void)now; |
223 | | coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n"); |
224 | | return 0; |
225 | | #else /* COAP_EPOLL_SUPPORT */ |
226 | 0 | coap_socket_t *sockets[1]; |
227 | 0 | unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]); |
228 | 0 | unsigned int num_sockets; |
229 | 0 | unsigned int timeout; |
230 | |
|
231 | 0 | coap_lock_check_locked(); |
232 | | /* Use the common logic */ |
233 | 0 | timeout = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, &num_sockets, now); |
234 | | /* Save when the next expected I/O is to take place */ |
235 | 0 | ctx->next_timeout = timeout ? now + timeout : 0; |
236 | 0 | if (ctx->eptimerfd != -1) { |
237 | 0 | struct itimerspec new_value; |
238 | 0 | int ret; |
239 | |
|
240 | 0 | memset(&new_value, 0, sizeof(new_value)); |
241 | 0 | coap_ticks(&now); |
242 | 0 | if (ctx->next_timeout != 0 && ctx->next_timeout > now) { |
243 | 0 | coap_tick_t rem_timeout = ctx->next_timeout - now; |
244 | | /* Need to trigger an event on ctx->eptimerfd in the future */ |
245 | 0 | new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND; |
246 | 0 | new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) * |
247 | 0 | 1000000; |
248 | 0 | } |
249 | | #ifdef COAP_DEBUG_WAKEUP_TIMES |
250 | | coap_log_debug("****** Next wakeup time %3ld.%09ld\n", |
251 | | new_value.it_value.tv_sec, new_value.it_value.tv_nsec); |
252 | | #endif /* COAP_DEBUG_WAKEUP_TIMES */ |
253 | | /* reset, or specify a future time for eptimerfd to trigger */ |
254 | 0 | ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL); |
255 | 0 | if (ret == -1) { |
256 | 0 | coap_log_err("%s: timerfd_settime failed: %s (%d)\n", |
257 | 0 | "coap_io_prepare_epoll", |
258 | 0 | coap_socket_strerror(), errno); |
259 | 0 | } |
260 | 0 | } |
261 | 0 | return timeout; |
262 | 0 | #endif /* COAP_EPOLL_SUPPORT */ |
263 | 0 | } |
264 | | |
265 | | /* |
266 | | * return 0 No i/o pending |
267 | | * +ve millisecs to next i/o activity |
268 | | */ |
269 | | COAP_API unsigned int |
270 | | coap_io_prepare_io(coap_context_t *ctx, |
271 | | coap_socket_t *sockets[], |
272 | | unsigned int max_sockets, |
273 | | unsigned int *num_sockets, |
274 | 0 | coap_tick_t now) { |
275 | 0 | unsigned int ret; |
276 | |
|
277 | 0 | coap_lock_lock(return 0); |
278 | 0 | ret = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, num_sockets, now); |
279 | 0 | coap_lock_unlock(); |
280 | 0 | return ret; |
281 | 0 | } |
282 | | |
283 | | #if COAP_CLIENT_SUPPORT |
284 | | static coap_tick_t |
285 | | coap_check_need_reconnect(coap_context_t *ctx, coap_session_t *s, coap_tick_t now, |
286 | 0 | coap_tick_t timeout) { |
287 | 0 | coap_tick_t s_timeout; |
288 | |
|
289 | 0 | if (s->client_initiated && s->session_failed && ctx->reconnect_time) { |
290 | 0 | if (s->last_rx_tx + ctx->reconnect_time * COAP_TICKS_PER_SECOND <= now) { |
291 | 0 | if (!coap_session_reconnect(s)) { |
292 | | /* server is not back up yet - delay retry a while */ |
293 | 0 | s->last_rx_tx = now; |
294 | 0 | s_timeout = ctx->reconnect_time * COAP_TICKS_PER_SECOND; |
295 | 0 | if (timeout == 0 || s_timeout < timeout) |
296 | 0 | timeout = s_timeout; |
297 | 0 | } |
298 | 0 | } else { |
299 | | /* Always positive due to if() above */ |
300 | 0 | s_timeout = (s->last_rx_tx + ctx->reconnect_time * COAP_TICKS_PER_SECOND) - now; |
301 | 0 | if (s_timeout < timeout) |
302 | 0 | timeout = s_timeout; |
303 | 0 | } |
304 | 0 | } |
305 | 0 | return timeout; |
306 | 0 | } |
307 | | |
308 | | void |
309 | 0 | coap_reset_doing_first(coap_session_t *session) { |
310 | 0 | if (session->doing_first) { |
311 | 0 | session->doing_first = 0; |
312 | 0 | while (!session->doing_first && session->doing_first_pdu) { |
313 | 0 | coap_pdu_t *k_pdu = session->doing_first_pdu; |
314 | |
|
315 | 0 | LL_DELETE(session->doing_first_pdu, session->doing_first_pdu); |
316 | 0 | coap_log_debug("** %s: mid=0x%04x: released\n", |
317 | 0 | coap_session_str(session), k_pdu->mid); |
318 | 0 | if (coap_send_lkd(session, k_pdu) == COAP_INVALID_MID) { |
319 | 0 | coap_handle_event_lkd(session->context, COAP_EVENT_FIRST_PDU_FAIL, session); |
320 | 0 | } |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } |
324 | | #endif /* COAP_CLIENT_SUPPORT */ |
325 | | |
326 | | /* |
327 | | * return 0 No i/o pending |
328 | | * +ve millisecs to next i/o activity |
329 | | */ |
330 | | unsigned int |
331 | | coap_io_prepare_io_lkd(coap_context_t *ctx, |
332 | | coap_socket_t *sockets[], |
333 | | unsigned int max_sockets, |
334 | | unsigned int *num_sockets, |
335 | 0 | coap_tick_t now) { |
336 | 0 | coap_queue_t *nextpdu; |
337 | 0 | coap_session_t *s, *stmp; |
338 | 0 | coap_tick_t timeout = COAP_MAX_DELAY_TICKS; |
339 | 0 | coap_tick_t s_timeout; |
340 | 0 | #if COAP_SERVER_SUPPORT |
341 | 0 | int check_dtls_timeouts = 0; |
342 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
343 | 0 | #if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP) || defined(RIOT_VERSION) |
344 | 0 | (void)sockets; |
345 | 0 | (void)max_sockets; |
346 | 0 | #endif /* COAP_EPOLL_SUPPORT || WITH_LWIP || RIOT_VERSION*/ |
347 | |
|
348 | 0 | coap_lock_check_locked(); |
349 | 0 | *num_sockets = 0; |
350 | |
|
351 | 0 | #if COAP_SERVER_SUPPORT |
352 | | /* Check to see if we need to send off any Observe requests */ |
353 | 0 | coap_check_notify_lkd(ctx); |
354 | |
|
355 | 0 | #if COAP_ASYNC_SUPPORT |
356 | | /* Check to see if we need to send off any Async requests */ |
357 | 0 | if (coap_check_async(ctx, now, &s_timeout)) { |
358 | 0 | if (s_timeout < timeout) |
359 | 0 | timeout = s_timeout; |
360 | 0 | } |
361 | 0 | #endif /* COAP_ASYNC_SUPPORT */ |
362 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
363 | | |
364 | | /* Check to see if we need to send off any retransmit request */ |
365 | 0 | nextpdu = coap_peek_next(ctx); |
366 | 0 | while (nextpdu && now >= ctx->sendqueue_basetime && |
367 | 0 | nextpdu->t <= now - ctx->sendqueue_basetime) { |
368 | 0 | coap_retransmit(ctx, coap_pop_next(ctx)); |
369 | 0 | nextpdu = coap_peek_next(ctx); |
370 | 0 | } |
371 | 0 | if (nextpdu && now >= ctx->sendqueue_basetime && |
372 | 0 | (nextpdu->t - (now - ctx->sendqueue_basetime) < timeout)) |
373 | 0 | timeout = nextpdu->t - (now - ctx->sendqueue_basetime); |
374 | | |
375 | | /* Check for DTLS timeouts */ |
376 | 0 | if (ctx->dtls_context) { |
377 | 0 | if (coap_dtls_is_context_timeout()) { |
378 | 0 | coap_tick_t tls_timeout = coap_dtls_get_context_timeout(ctx->dtls_context); |
379 | 0 | if (tls_timeout > 0) { |
380 | 0 | if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10) |
381 | 0 | tls_timeout = now + COAP_TICKS_PER_SECOND / 10; |
382 | 0 | coap_log_debug("** DTLS global timeout set to %dms\n", |
383 | 0 | (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND)); |
384 | 0 | if (tls_timeout - now < timeout) |
385 | 0 | timeout = tls_timeout - now; |
386 | 0 | } |
387 | 0 | #if COAP_SERVER_SUPPORT |
388 | 0 | } else { |
389 | 0 | check_dtls_timeouts = 1; |
390 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
391 | 0 | } |
392 | 0 | } |
393 | 0 | #if COAP_PROXY_SUPPORT |
394 | 0 | if (coap_proxy_check_timeouts(ctx, now, &s_timeout)) { |
395 | 0 | if (s_timeout < timeout) |
396 | 0 | timeout = s_timeout; |
397 | 0 | } |
398 | 0 | #endif /* COAP_PROXY_SUPPORT */ |
399 | 0 | #if COAP_SERVER_SUPPORT |
400 | 0 | coap_endpoint_t *ep; |
401 | 0 | coap_tick_t session_timeout; |
402 | |
|
403 | 0 | if (ctx->session_timeout > 0) |
404 | 0 | session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND; |
405 | 0 | else |
406 | 0 | session_timeout = COAP_DEFAULT_SESSION_TIMEOUT * COAP_TICKS_PER_SECOND; |
407 | |
|
408 | 0 | LL_FOREACH(ctx->endpoint, ep) { |
409 | | #if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION) |
410 | | if (ep->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_ACCEPT)) { |
411 | | if (*num_sockets < max_sockets) |
412 | | sockets[(*num_sockets)++] = &ep->sock; |
413 | | } |
414 | | #endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */ |
415 | 0 | SESSIONS_ITER_SAFE(ep->sessions, s, stmp) { |
416 | | /* Check whether any idle server sessions should be released */ |
417 | 0 | if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 && |
418 | 0 | s->delayqueue == NULL && |
419 | 0 | #if COAP_CLIENT_SUPPORT |
420 | 0 | !(s->client_initiated && ctx->reconnect_time) && |
421 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
422 | 0 | (s->last_rx_tx + session_timeout <= now || |
423 | 0 | s->state == COAP_SESSION_STATE_NONE)) { |
424 | 0 | coap_handle_event_lkd(ctx, COAP_EVENT_SERVER_SESSION_DEL, s); |
425 | 0 | coap_session_free(s); |
426 | 0 | continue; |
427 | 0 | } else if (s->is_rate_limiting) { |
428 | 0 | continue; |
429 | 0 | } else { |
430 | 0 | if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 && |
431 | 0 | s->delayqueue == NULL && s->last_rx_tx + session_timeout <= now) { |
432 | | /* Has to be positive based on if() above */ |
433 | 0 | s_timeout = (s->last_rx_tx + session_timeout) - now; |
434 | 0 | if (s_timeout < timeout) |
435 | 0 | timeout = s_timeout; |
436 | 0 | } |
437 | | /* Make sure the session object is not deleted in any callbacks */ |
438 | 0 | coap_session_reference_lkd(s); |
439 | | /* Check any DTLS timeouts and expire if appropriate */ |
440 | 0 | if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE && |
441 | 0 | s->proto == COAP_PROTO_DTLS && s->tls) { |
442 | 0 | coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now); |
443 | 0 | while (tls_timeout > 0 && tls_timeout <= now) { |
444 | 0 | coap_log_debug("** %s: DTLS retransmit timeout\n", |
445 | 0 | coap_session_str(s)); |
446 | 0 | if (coap_dtls_handle_timeout(s)) |
447 | 0 | goto release_1; |
448 | | |
449 | 0 | if (s->tls) |
450 | 0 | tls_timeout = coap_dtls_get_timeout(s, now); |
451 | 0 | else { |
452 | 0 | tls_timeout = 0; |
453 | 0 | timeout = 1; |
454 | 0 | } |
455 | 0 | } |
456 | 0 | if (tls_timeout > 0 && tls_timeout - now < timeout) |
457 | 0 | timeout = tls_timeout - now; |
458 | 0 | } |
459 | | /* Check if any server large receives are missing blocks */ |
460 | 0 | if (s->lg_srcv) { |
461 | 0 | if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) { |
462 | 0 | if (s_timeout < timeout) |
463 | 0 | timeout = s_timeout; |
464 | 0 | } |
465 | 0 | } |
466 | | /* Check if any server large sending have timed out */ |
467 | 0 | if (s->lg_xmit) { |
468 | 0 | if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) { |
469 | 0 | if (s_timeout < timeout) |
470 | 0 | timeout = s_timeout; |
471 | 0 | } |
472 | 0 | } |
473 | | #if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION) |
474 | | if (s->sock.flags & (COAP_SOCKET_WANT_READ|COAP_SOCKET_WANT_WRITE)) { |
475 | | if (*num_sockets < max_sockets && !(s->sock.flags & COAP_SOCKET_SLAVE)) |
476 | | sockets[(*num_sockets)++] = &s->sock; |
477 | | } |
478 | | #endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */ |
479 | 0 | #if COAP_Q_BLOCK_SUPPORT |
480 | | /* |
481 | | * Check if any server large transmits have hit MAX_PAYLOAD and need |
482 | | * restarting |
483 | | */ |
484 | 0 | if (s->lg_xmit && !s->is_rate_limiting) { |
485 | 0 | if (coap_block_check_q_block2_xmit(s, now, &s_timeout)) { |
486 | 0 | if (s_timeout < timeout) |
487 | 0 | timeout = s_timeout; |
488 | 0 | } |
489 | 0 | } |
490 | 0 | #endif /* COAP_Q_BLOCK_SUPPORT */ |
491 | 0 | release_1: |
492 | 0 | coap_session_release_lkd(s); |
493 | 0 | } |
494 | 0 | if (s->type == COAP_SESSION_TYPE_SERVER && |
495 | 0 | s->state == COAP_SESSION_STATE_ESTABLISHED && |
496 | 0 | (s->ref_subscriptions || s->ref_proxy_subs |
497 | 0 | #if COAP_CLIENT_SUPPORT |
498 | 0 | || (s->client_initiated && ctx->reconnect_time) |
499 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
500 | 0 | ) && |
501 | 0 | !s->con_active && ctx->ping_timeout > 0) { |
502 | | /* Only do this if this session is observing or reconnecting */ |
503 | 0 | if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) { |
504 | | /* Time to send a ping */ |
505 | 0 | coap_mid_t mid; |
506 | |
|
507 | 0 | if ((mid = coap_session_send_ping_lkd(s)) == COAP_INVALID_MID) { |
508 | | /* Some issue - not safe to continue processing */ |
509 | 0 | s->ping_failed++; |
510 | 0 | s->last_rx_tx = now; |
511 | 0 | #if COAP_CLIENT_SUPPORT |
512 | 0 | if (s->client_initiated && ctx->reconnect_time) { |
513 | 0 | coap_session_failed(s); |
514 | 0 | } |
515 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
516 | 0 | if (s->ping_failed <= COAP_MAX_PING_FAILURES) |
517 | 0 | continue; |
518 | 0 | } |
519 | 0 | s->last_ping_mid = mid; |
520 | 0 | if ((s->last_ping > 0 && s->last_pong < s->last_ping) || s->ping_failed > COAP_MAX_PING_FAILURES) { |
521 | 0 | #if COAP_CLIENT_SUPPORT |
522 | 0 | if (s->client_initiated && ctx->reconnect_time) { |
523 | 0 | coap_session_failed(s); |
524 | 0 | } else { |
525 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
526 | 0 | coap_session_server_keepalive_failed(s); |
527 | 0 | #if COAP_CLIENT_SUPPORT |
528 | 0 | } |
529 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
530 | | /* check the next session */ |
531 | 0 | continue; |
532 | 0 | } |
533 | 0 | s->last_rx_tx = now; |
534 | 0 | s->last_ping = now; |
535 | 0 | } else { |
536 | | /* Always positive due to if() above */ |
537 | 0 | s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now; |
538 | 0 | if (s_timeout < timeout) |
539 | 0 | timeout = s_timeout; |
540 | 0 | } |
541 | 0 | } |
542 | 0 | #if COAP_CLIENT_SUPPORT |
543 | 0 | timeout = coap_check_need_reconnect(ctx, s, now, timeout); |
544 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
545 | 0 | } |
546 | 0 | } |
547 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
548 | 0 | #if COAP_CLIENT_SUPPORT |
549 | 0 | SESSIONS_ITER_SAFE(ctx->sessions, s, stmp) { |
550 | 0 | if (s->is_rate_limiting) { |
551 | 0 | continue; |
552 | 0 | } |
553 | 0 | if (s->type == COAP_SESSION_TYPE_CLIENT && |
554 | 0 | s->state == COAP_SESSION_STATE_ESTABLISHED && !s->con_active && |
555 | 0 | ctx->ping_timeout > 0) { |
556 | 0 | if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) { |
557 | | /* Time to send a ping */ |
558 | 0 | coap_mid_t mid; |
559 | |
|
560 | 0 | if ((mid = coap_session_send_ping_lkd(s)) == COAP_INVALID_MID) { |
561 | | /* Some issue - not safe to continue processing */ |
562 | 0 | s->ping_failed++; |
563 | 0 | s->last_rx_tx = now; |
564 | 0 | coap_session_failed(s); |
565 | 0 | if (s->ping_failed <= COAP_MAX_PING_FAILURES) |
566 | 0 | continue; |
567 | 0 | } |
568 | 0 | s->last_ping_mid = mid; |
569 | 0 | if (s->last_ping > 0 && s->last_pong < s->last_ping) { |
570 | 0 | coap_handle_event_lkd(s->context, COAP_EVENT_KEEPALIVE_FAILURE, s); |
571 | 0 | } |
572 | 0 | if (s->ping_failed > COAP_MAX_PING_FAILURES) { |
573 | 0 | #if COAP_CLIENT_SUPPORT |
574 | 0 | if (s->client_initiated) { |
575 | 0 | if (ctx->reconnect_time) { |
576 | 0 | coap_session_failed(s); |
577 | 0 | } else { |
578 | 0 | coap_session_disconnected_lkd(s, COAP_NACK_NOT_DELIVERABLE); |
579 | 0 | } |
580 | 0 | } else { |
581 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
582 | 0 | #if COAP_SERVER_SUPPORT |
583 | 0 | coap_session_server_keepalive_failed(s); |
584 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
585 | 0 | #if COAP_CLIENT_SUPPORT |
586 | 0 | } |
587 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
588 | 0 | continue; |
589 | 0 | } else { |
590 | 0 | s->last_rx_tx = now; |
591 | 0 | s->last_ping = now; |
592 | 0 | } |
593 | 0 | } else { |
594 | | /* Always positive due to if() above */ |
595 | 0 | s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now; |
596 | 0 | if (s_timeout < timeout) |
597 | 0 | timeout = s_timeout; |
598 | 0 | } |
599 | 0 | } |
600 | 0 | timeout = coap_check_need_reconnect(ctx, s, now, timeout); |
601 | |
|
602 | 0 | #if !COAP_DISABLE_TCP |
603 | 0 | if (s->type == COAP_SESSION_TYPE_CLIENT && COAP_PROTO_RELIABLE(s->proto) && |
604 | 0 | s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout_ms > 0) { |
605 | 0 | if (s->csm_tx == 0) { |
606 | 0 | s->csm_tx = now; |
607 | 0 | s_timeout = (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000; |
608 | 0 | } else if (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000 <= now) { |
609 | | /* timed out - cannot handle 0, so has to be just +ve */ |
610 | 0 | s_timeout = 1; |
611 | 0 | } else { |
612 | 0 | s_timeout = (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000) - now; |
613 | 0 | } |
614 | 0 | if (s_timeout < timeout) |
615 | 0 | timeout = s_timeout; |
616 | 0 | } |
617 | 0 | #endif /* !COAP_DISABLE_TCP */ |
618 | | |
619 | | /* Make sure the session object is not deleted in any callbacks */ |
620 | 0 | coap_session_reference_lkd(s); |
621 | | /* Check any DTLS timeouts and expire if appropriate */ |
622 | 0 | if (s->state == COAP_SESSION_STATE_HANDSHAKE && |
623 | 0 | s->proto == COAP_PROTO_DTLS && s->tls) { |
624 | 0 | coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now); |
625 | 0 | while (tls_timeout > 0 && tls_timeout <= now) { |
626 | 0 | coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s)); |
627 | 0 | if (coap_dtls_handle_timeout(s)) |
628 | 0 | goto release_2; |
629 | | |
630 | 0 | if (s->tls) |
631 | 0 | tls_timeout = coap_dtls_get_timeout(s, now); |
632 | 0 | else { |
633 | 0 | tls_timeout = 0; |
634 | 0 | timeout = 1; |
635 | 0 | } |
636 | 0 | } |
637 | 0 | if (tls_timeout > 0 && tls_timeout - now < timeout) |
638 | 0 | timeout = tls_timeout - now; |
639 | 0 | } |
640 | | |
641 | | /* Check if any client large receives are missing blocks */ |
642 | 0 | if (s->lg_crcv) { |
643 | 0 | if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) { |
644 | 0 | if (s_timeout < timeout) |
645 | 0 | timeout = s_timeout; |
646 | 0 | } |
647 | 0 | } |
648 | | /* Check if any client large sending have timed out */ |
649 | 0 | if (s->lg_xmit) { |
650 | 0 | if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) { |
651 | 0 | if (s_timeout < timeout) |
652 | 0 | timeout = s_timeout; |
653 | 0 | } |
654 | 0 | } |
655 | 0 | if (s->doing_first && s->doing_first_timeout) { |
656 | 0 | if ((s->doing_first_timeout + 5 * COAP_TICKS_PER_SECOND) > now) { |
657 | 0 | s_timeout = s->doing_first_timeout + 5 * COAP_TICKS_PER_SECOND - now; |
658 | 0 | if (s_timeout < timeout) |
659 | 0 | timeout = s_timeout; |
660 | 0 | } else { |
661 | | /* Session set up has failed */ |
662 | 0 | coap_queue_t *sent; |
663 | 0 | coap_queue_t *p = NULL; |
664 | 0 | coap_queue_t *q; |
665 | 0 | coap_queue_t *tmp; |
666 | |
|
667 | 0 | if (s->state == COAP_SESSION_STATE_CSM) { |
668 | 0 | coap_log_debug("** %s: timeout waiting for CSM response\n", |
669 | 0 | coap_session_str(s)); |
670 | 0 | s->csm_not_seen = 1; |
671 | 0 | } else { |
672 | 0 | coap_log_debug("** %s: timeout waiting for first response\n", |
673 | 0 | coap_session_str(s)); |
674 | 0 | } |
675 | 0 | #if COAP_Q_BLOCK_SUPPORT |
676 | | /* Check if testing for Q-Block */ |
677 | 0 | if (s->block_mode & COAP_BLOCK_PROBE_Q_BLOCK) { |
678 | 0 | coap_log_debug("Q-Block support assumed not available\n"); |
679 | 0 | set_block_mode_drop_q(s->block_mode); |
680 | 0 | } |
681 | 0 | #endif /* COAP_Q_BLOCK_SUPPORT */ |
682 | | /* Check if testing for Extended Token */ |
683 | 0 | if (s->max_token_checked == COAP_EXT_T_CHECKING) { |
684 | 0 | s->max_token_size = COAP_TOKEN_DEFAULT_MAX; |
685 | 0 | s->max_token_checked = COAP_EXT_T_CHECKED; |
686 | 0 | coap_log_debug("Extended Token support assumed not available\n"); |
687 | 0 | } |
688 | | /* |
689 | | * Remove the test packet to stop re-transmission. |
690 | | * The test packet may be in the delayqueue ((D)TLS has not been set up), |
691 | | * or in the sendqueue if sent and is pending re-transmission. |
692 | | */ |
693 | 0 | LL_FOREACH_SAFE(s->delayqueue, q, tmp) { |
694 | 0 | if (q->pdu->mid == s->remote_test_mid) { |
695 | 0 | if (q->pdu->type==COAP_MESSAGE_CON) { |
696 | 0 | coap_handle_nack(s, q->pdu, |
697 | 0 | s->proto == COAP_PROTO_DTLS ? |
698 | 0 | COAP_NACK_TLS_FAILED : COAP_NACK_NOT_DELIVERABLE, |
699 | 0 | q->id); |
700 | 0 | } |
701 | 0 | coap_log_debug("** %s: mid=0x%04x: removed\n", |
702 | 0 | coap_session_str(s), q->pdu->mid); |
703 | 0 | if (p) { |
704 | 0 | p->next = q->next; |
705 | 0 | } else { |
706 | 0 | s->delayqueue = q->next; |
707 | 0 | } |
708 | 0 | coap_delete_node_lkd(q); |
709 | 0 | break; |
710 | 0 | } |
711 | 0 | p = q; |
712 | 0 | } |
713 | 0 | coap_remove_from_queue(&ctx->sendqueue, s, s->remote_test_mid, &sent); |
714 | 0 | if (sent && sent->pdu && sent->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(s->proto)) { |
715 | 0 | if (s->con_active) |
716 | 0 | s->con_active--; |
717 | 0 | } |
718 | 0 | coap_reset_doing_first(s); |
719 | 0 | if (s->state == COAP_SESSION_STATE_ESTABLISHED) { |
720 | | /* Flush out any entries on session->delayqueue */ |
721 | 0 | coap_session_connected(s); |
722 | 0 | } |
723 | 0 | } |
724 | 0 | } |
725 | |
|
726 | 0 | #if COAP_Q_BLOCK_SUPPORT |
727 | | /* |
728 | | * Check if any client large transmits have hit MAX_PAYLOAD and need |
729 | | * restarting |
730 | | */ |
731 | 0 | if (s->lg_xmit) { |
732 | 0 | if (coap_block_check_q_block1_xmit(s, now, &s_timeout)) { |
733 | 0 | if (s_timeout < timeout) |
734 | 0 | timeout = s_timeout; |
735 | 0 | } |
736 | 0 | } |
737 | 0 | #endif /* COAP_Q_BLOCK_SUPPORT */ |
738 | |
|
739 | | #if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION) |
740 | | assert(s->ref > 1); |
741 | | if (s->sock.flags & (COAP_SOCKET_WANT_READ | |
742 | | COAP_SOCKET_WANT_WRITE | |
743 | | COAP_SOCKET_WANT_CONNECT)) { |
744 | | if (*num_sockets < max_sockets && !(s->sock.flags & COAP_SOCKET_SLAVE)) |
745 | | sockets[(*num_sockets)++] = &s->sock; |
746 | | } |
747 | | #endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */ |
748 | 0 | release_2: |
749 | 0 | coap_session_release_lkd(s); |
750 | 0 | } |
751 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
752 | | |
753 | 0 | return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND); |
754 | 0 | } |
755 | | |
756 | | /* |
757 | | * return 0 Insufficient space to hold fds, or fds not supported |
758 | | * 1 All fds found |
759 | | */ |
760 | | COAP_API unsigned int |
761 | | coap_io_get_fds(coap_context_t *ctx, |
762 | | coap_fd_t read_fds[], |
763 | | unsigned int *have_read_fds, |
764 | | unsigned int max_read_fds, |
765 | | coap_fd_t write_fds[], |
766 | | unsigned int *have_write_fds, |
767 | | unsigned int max_write_fds, |
768 | 0 | unsigned int *rem_timeout_ms) { |
769 | 0 | unsigned int ret; |
770 | |
|
771 | 0 | coap_lock_lock(return 0); |
772 | 0 | ret = coap_io_get_fds_lkd(ctx, read_fds, have_read_fds, max_read_fds, write_fds, |
773 | 0 | have_write_fds, max_write_fds, rem_timeout_ms); |
774 | 0 | coap_lock_unlock(); |
775 | 0 | return ret; |
776 | 0 | } |
777 | | |
778 | | #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI) |
779 | | static int |
780 | | coap_add_fd(coap_fd_t fd, coap_fd_t this_fds[], unsigned int *have_this_fds, |
781 | 0 | unsigned int max_this_fds) { |
782 | 0 | if (*have_this_fds < max_this_fds) { |
783 | 0 | this_fds[(*have_this_fds)++] = fd; |
784 | 0 | return 1; |
785 | 0 | } |
786 | 0 | coap_log_warn("coap_io_get_fds: Insufficient space for new fd (%u >= %u)\n", *have_this_fds, |
787 | 0 | max_this_fds); |
788 | 0 | return 0; |
789 | 0 | } |
790 | | |
791 | | /* |
792 | | * return 0 Insufficient space to hold fds, or fds not supported |
793 | | * 1 All fds found |
794 | | */ |
795 | | unsigned int |
796 | | coap_io_get_fds_lkd(coap_context_t *ctx, |
797 | | coap_fd_t read_fds[], |
798 | | unsigned int *have_read_fds, |
799 | | unsigned int max_read_fds, |
800 | | coap_fd_t write_fds[], |
801 | | unsigned int *have_write_fds, |
802 | | unsigned int max_write_fds, |
803 | 0 | unsigned int *rem_timeout_ms) { |
804 | 0 | *have_read_fds = 0; |
805 | 0 | *have_write_fds = 0; |
806 | |
|
807 | 0 | #ifdef COAP_EPOLL_SUPPORT |
808 | 0 | (void)write_fds; |
809 | 0 | (void)max_write_fds;; |
810 | |
|
811 | 0 | if (!coap_add_fd(ctx->epfd, read_fds, have_read_fds, max_read_fds)) |
812 | 0 | return 0; |
813 | | /* epoll is making use of timerfd, so no need to return any timeout */ |
814 | 0 | *rem_timeout_ms = 0; |
815 | 0 | return 1; |
816 | | #else /* ! COAP_EPOLL_SUPPORT */ |
817 | | coap_session_t *s, *rtmp; |
818 | | coap_tick_t now; |
819 | | unsigned int timeout_ms; |
820 | | #if COAP_SERVER_SUPPORT |
821 | | coap_endpoint_t *ep; |
822 | | |
823 | | LL_FOREACH(ctx->endpoint, ep) { |
824 | | if (ep->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) { |
825 | | if (!coap_add_fd(ep->sock.fd, read_fds, have_read_fds, max_read_fds)) |
826 | | return 0; |
827 | | } |
828 | | if (ep->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) { |
829 | | if (!coap_add_fd(ep->sock.fd, write_fds, have_write_fds, max_write_fds)) |
830 | | return 0; |
831 | | } |
832 | | SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) { |
833 | | if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) { |
834 | | if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds)) |
835 | | return 0; |
836 | | } |
837 | | if (s->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) { |
838 | | if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds)) |
839 | | return 0; |
840 | | } |
841 | | } |
842 | | } |
843 | | #endif /* COAP_SERVER_SUPPORT */ |
844 | | |
845 | | #if COAP_CLIENT_SUPPORT |
846 | | SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) { |
847 | | if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) { |
848 | | if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds)) |
849 | | return 0; |
850 | | } |
851 | | if (s->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) { |
852 | | if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds)) |
853 | | return 0; |
854 | | } |
855 | | } |
856 | | #endif /* COAP_CLIENT_SUPPORT */ |
857 | | |
858 | | coap_ticks(&now); |
859 | | timeout_ms = (unsigned int)(ctx->next_timeout ? ctx->next_timeout > now ? |
860 | | ctx->next_timeout - now : 0 : 0) * |
861 | | 1000 / COAP_TICKS_PER_SECOND; |
862 | | *rem_timeout_ms = timeout_ms; |
863 | | return 1; |
864 | | #endif /* ! COAP_EPOLL_SUPPORT */ |
865 | 0 | } |
866 | | |
867 | | #else /* WITH_LWIP || WITH_CONTIKI */ |
868 | | |
869 | | /* |
870 | | * return 0 Insufficient space to hold fds, or fds not supported |
871 | | * 1 All fds found |
872 | | */ |
873 | | unsigned int |
874 | | coap_io_get_fds_lkd(coap_context_t *ctx, |
875 | | coap_fd_t read_fds[], |
876 | | unsigned int *have_read_fds, |
877 | | unsigned int max_read_fds, |
878 | | coap_fd_t write_fds[], |
879 | | unsigned int *have_write_fds, |
880 | | unsigned int max_write_fds, |
881 | | unsigned int *rem_timeout_ms) { |
882 | | (void)ctx; |
883 | | (void)read_fds; |
884 | | (void)max_read_fds; |
885 | | (void)write_fds; |
886 | | (void)max_write_fds; |
887 | | |
888 | | *have_read_fds = 0; |
889 | | *have_write_fds = 0; |
890 | | *rem_timeout_ms = 0; |
891 | | |
892 | | coap_log_warn("coap_io_get_fds: Not supported\n"); |
893 | | return 0; |
894 | | } |
895 | | #endif /* WITH_LWIP || WITH_CONTIKI */ |
896 | | |
897 | | COAP_API int |
898 | 0 | coap_io_pending(coap_context_t *context) { |
899 | 0 | int ret; |
900 | |
|
901 | 0 | coap_lock_lock(return 0); |
902 | 0 | ret = coap_io_pending_lkd(context); |
903 | 0 | coap_lock_unlock(); |
904 | 0 | return ret; |
905 | 0 | } |
906 | | |
907 | | /* |
908 | | * return 1 I/O pending |
909 | | * 0 No I/O pending |
910 | | */ |
911 | | int |
912 | 0 | coap_io_pending_lkd(coap_context_t *context) { |
913 | 0 | coap_session_t *s, *rtmp; |
914 | 0 | #if COAP_SERVER_SUPPORT |
915 | 0 | coap_endpoint_t *ep; |
916 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
917 | |
|
918 | 0 | if (!context) |
919 | 0 | return 0; |
920 | 0 | coap_lock_check_locked(); |
921 | 0 | if (coap_io_process_lkd(context, COAP_IO_NO_WAIT) < 0) |
922 | 0 | return 0; |
923 | | |
924 | 0 | if (context->sendqueue) |
925 | 0 | return 1; |
926 | 0 | #if COAP_SERVER_SUPPORT |
927 | 0 | LL_FOREACH(context->endpoint, ep) { |
928 | 0 | SESSIONS_ITER(ep->sessions, s, rtmp) { |
929 | 0 | if (s->delayqueue) |
930 | 0 | return 1; |
931 | 0 | if (s->lg_xmit) |
932 | 0 | return 1; |
933 | 0 | if (s->lg_srcv) |
934 | 0 | return 1; |
935 | 0 | } |
936 | 0 | } |
937 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
938 | 0 | #if COAP_CLIENT_SUPPORT |
939 | 0 | SESSIONS_ITER(context->sessions, s, rtmp) { |
940 | 0 | if (s->delayqueue) |
941 | 0 | return 1; |
942 | 0 | if (s->lg_xmit) |
943 | 0 | return 1; |
944 | 0 | if (s->lg_crcv) |
945 | 0 | return 1; |
946 | 0 | } |
947 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
948 | 0 | return 0; |
949 | 0 | } |
950 | | |
951 | | const char * |
952 | 0 | coap_socket_format_errno(int error) { |
953 | 0 | return strerror(error); |
954 | 0 | } |
955 | | #ifdef _WIN32 |
956 | | const char * |
957 | | coap_socket_strerror(void) { |
958 | | coap_win_error_to_errno(); |
959 | | return coap_socket_format_errno(errno); |
960 | | } |
961 | | #else /* _WIN32 */ |
962 | | const char * |
963 | 0 | coap_socket_strerror(void) { |
964 | 0 | return coap_socket_format_errno(errno); |
965 | 0 | } |
966 | | #endif /* _WIN32 */ |
967 | | |
968 | | COAP_API coap_fd_t |
969 | 0 | coap_socket_get_fd(coap_socket_t *sock) { |
970 | 0 | #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI) |
971 | 0 | return sock->fd; |
972 | | #else |
973 | | (void)(sock); |
974 | | return COAP_INVALID_SOCKET; |
975 | | #endif |
976 | 0 | } |
977 | | |
978 | | COAP_API coap_socket_flags_t |
979 | 0 | coap_socket_get_flags(coap_socket_t *sock) { |
980 | 0 | return sock->flags; |
981 | 0 | } |
982 | | |
983 | | COAP_API void |
984 | 0 | coap_socket_set_flags(coap_socket_t *sock, coap_socket_flags_t flags) { |
985 | 0 | sock->flags = flags; |
986 | 0 | } |