libcoap  4.3.0beta
coap_io_riot.c
Go to the documentation of this file.
1 /* coap_io_riot.c -- Default network I/O functions for libcoap on RIOT
2  *
3  * Copyright (C) 2019 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_internal.h"
10 
11 #ifdef HAVE_STDIO_H
12 # include <stdio.h>
13 #endif
14 
15 #ifdef HAVE_SYS_SOCKET_H
16 # include <sys/socket.h>
17 # define OPTVAL_T(t) (t)
18 # define OPTVAL_GT(t) (t)
19 #endif
20 #ifdef HAVE_SYS_IOCTL_H
21  #include <sys/ioctl.h>
22 #endif
23 #ifdef HAVE_NETINET_IN_H
24 # include <netinet/in.h>
25 #endif
26 #ifdef HAVE_SYS_UIO_H
27 # include <sys/uio.h>
28 #endif
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <errno.h>
33 
34 #include "net/gnrc.h"
35 #include "net/gnrc/ipv6.h"
36 #include "net/gnrc/netreg.h"
37 #include "net/udp.h"
38 
39 #include "coap_riot.h"
40 
41 ssize_t
43  const coap_session_t *session,
44  const uint8_t *data,
45  size_t datalen) {
46  ssize_t bytes_written = 0;
47 
48  if (!coap_debug_send_packet()) {
49  bytes_written = (ssize_t)datalen;
50  } else if (sock->flags & COAP_SOCKET_CONNECTED) {
51  bytes_written = send(sock->fd, data, datalen, 0);
52  } else {
53  bytes_written = sendto(sock->fd, data, datalen, 0,
54  &session->addr_info.remote.addr.sa,
55  session->addr_info.remote.size);
56  }
57 
58  if (bytes_written < 0)
59  coap_log(LOG_CRIT, "coap_network_send: %s\n", coap_socket_strerror());
60 
61  return bytes_written;
62 }
63 
64 static udp_hdr_t *
65 get_udp_header(gnrc_pktsnip_t *pkt) {
66  gnrc_pktsnip_t *udp = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
67  return udp ? (udp_hdr_t *)udp->data : NULL;
68 }
69 
70 ssize_t
72  size_t len;
73  ipv6_hdr_t *ipv6_hdr;
74  /* The GNRC API currently only supports UDP. */
75  gnrc_pktsnip_t *udp;
76  udp_hdr_t *udp_hdr;
77  const gnrc_nettype_t type = GNRC_NETTYPE_UDP;
78 
79  assert(sock);
80  assert(packet);
81 
82  if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
83  coap_log(LOG_DEBUG, "coap_network_read: COAP_SOCKET_CAN_READ not set\n");
84  return -1;
85  } else {
86  /* clear has-data flag */
87  sock->flags &= ~COAP_SOCKET_CAN_READ;
88  }
89 
90  /* Search for the transport header in the packet received from the
91  * network interface driver. */
92  udp = gnrc_pktsnip_search_type(sock->pkt, type);
93  ipv6_hdr = gnrc_ipv6_get_header(sock->pkt);
94 
95  if (!ipv6_hdr || !udp || !(udp_hdr = (udp_hdr_t *)udp->data)) {
96  coap_log(LOG_DEBUG, "no UDP header found in packet\n");
97  return -EFAULT;
98  }
99  udp_hdr_print(udp_hdr);
100 
101  len = (size_t)gnrc_pkt_len_upto(sock->pkt, type) - sizeof(udp_hdr_t);
102  coap_log(LOG_DEBUG, "coap_network_read: recvfrom got %zd bytes\n", len);
103  if (len > COAP_RXBUFFER_SIZE) {
104  coap_log(LOG_WARNING, "packet exceeds buffer size, truncated\n");
105  len = COAP_RXBUFFER_SIZE;
106  }
107  packet->ifindex = sock->fd;
108 
109  assert(sizeof(struct in6_addr) == sizeof(ipv6_addr_t));
110  packet->addr_info.remote.size = sizeof(struct sockaddr_in6);
111  memset(&packet->addr_info.remote.addr, 0,
112  sizeof(packet->addr_info.remote.addr));
113  packet->addr_info.remote.addr.sin6.sin6_family = AF_INET6;
114  memcpy(&packet->addr_info.remote.addr.sin6.sin6_addr,
115  &ipv6_hdr->src, sizeof(ipv6_addr_t));
116  memcpy(&packet->addr_info.remote.addr.sin6.sin6_port,
117  &udp_hdr->src_port, sizeof(udp_hdr->src_port));
118 
119  packet->addr_info.local.size = sizeof(struct sockaddr_in6);
120  memset(&packet->addr_info.local.addr, 0, sizeof(packet->addr_info.local.addr));
121  packet->addr_info.local.addr.sin6.sin6_family = AF_INET6;
122  memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
123  &ipv6_hdr->dst, sizeof(ipv6_addr_t));
124  memcpy(&packet->addr_info.local
125  .addr.sin6.sin6_port, &udp_hdr->dst_port, sizeof(udp_hdr->src_port));
126 
127  packet->ifindex = sock->fd;
128  packet->length = (len > 0) ? len : 0;
129  memcpy(packet->payload, (uint8_t*)udp_hdr + sizeof(udp_hdr_t), len);
130  if (LOG_DEBUG <= coap_get_log_level()) {
131  unsigned char addr_str[INET6_ADDRSTRLEN + 8];
132 
133  if (coap_print_addr(&packet->addr_info.remote, addr_str, INET6_ADDRSTRLEN + 8)) {
134  coap_log(LOG_DEBUG, "received %zd bytes from %s\n", len, addr_str);
135  }
136  }
137 
138  return len;
139 }
140 
142 
143 void
145  msg_init_queue(_msg_q, LIBCOAP_MSG_QUEUE_SIZE);
146 }
147 
151 static uint16_t
152 get_port(const coap_address_t *addr) {
153  if (addr) {
154  switch (addr->addr.sa.sa_family) {
155  case AF_INET: return addr->addr.sin.sin_port;
156  case AF_INET6: return addr->addr.sin6.sin6_port;
157  default:
158  ;
159  }
160  }
161  return 0;
162 }
163 
164 static coap_socket_t *
165 find_socket(coap_fd_t fd, coap_socket_t *sockets[], unsigned int num_sockets) {
166  for (unsigned int i = 0; i < num_sockets; i++) {
167  if (fd == sockets[i]->fd)
168  return sockets[i];
169  }
170  return NULL;
171 }
172 
173 static bool
174 address_equals(const coap_address_t *a, const ipv6_addr_t *b) {
175  assert(a);
176  assert(b);
177  return IN6_IS_ADDR_UNSPECIFIED(&a->addr.sin6.sin6_addr) ||
178  (memcmp(&a->addr.sin6.sin6_addr, b->u8, sizeof(struct in6_addr)) == 0);
179 }
180 
181 int
183  coap_tick_t before, now;
185  unsigned int num_sockets = 0, timeout;
186  gnrc_netreg_entry_t coap_reg =
187  GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, thread_getpid());
188  msg_t msg;
189  bool found_port = false;
190 
191  coap_ticks(&before);
192 
193  timeout =
194  coap_io_prepare_io(ctx, sockets, ARRAY_SIZE(sockets), &num_sockets, before);
195  if (timeout == 0 || timeout_ms < timeout)
196  timeout = timeout_ms;
197 
198  if (num_sockets > 0) {
199  gnrc_netreg_register(GNRC_NETTYPE_UDP, &coap_reg);
200  }
201 
202  if (timeout == 0 || timeout_ms < timeout)
203  timeout = timeout_ms;
204 
205  xtimer_msg_receive_timeout(&msg, timeout_ms * US_PER_SEC);
206  switch (msg.type) {
207  case GNRC_NETAPI_MSG_TYPE_RCV: {
208  coap_log(LOG_DEBUG, "coap_run_once: GNRC_NETAPI_MSG_TYPE_RCV\n");
209 
210  coap_session_t *s, *rtmp;
211  udp_hdr_t *udp_hdr = get_udp_header((gnrc_pktsnip_t *)msg.content.ptr);
212  ipv6_hdr_t *ip6_hdr =
213  gnrc_ipv6_get_header((gnrc_pktsnip_t *)msg.content.ptr);
214  if (!udp_hdr || !ip6_hdr)
215  break;
216  coap_log(LOG_DEBUG, "coap_run_once: found UDP header\n");
217 
218  /* Traverse all sessions and set COAP_SOCKET_CAN_READ if the
219  * received packet's destination address matches. */
220  SESSIONS_ITER(ctx->sessions, s, rtmp) {
221  coap_log(LOG_DEBUG, "coap_run_once: check ctx->sessions %u == %u\n",
222  ntohs(get_port(&s->addr_info.local)),
223  ntohs(udp_hdr->dst_port.u16));
224  if ((get_port(&s->addr_info.local) == udp_hdr->dst_port.u16) &&
225  (address_equals(&s->addr_info.local, &ip6_hdr->dst))) {
226  coap_socket_t *sock = find_socket(s->sock.fd, sockets, num_sockets);
227 
228  if (sock && (sock->flags & (COAP_SOCKET_WANT_READ))) {
229  coap_log(LOG_DEBUG, "fd %d on port %u can read\n",
230  sock->fd, ntohs(get_port(&s->addr_info.local)));
231  sock->flags |= COAP_SOCKET_CAN_READ;
232  sock->pkt = msg.content.ptr;
233  found_port = true;
234  break; /* found session, finish loop */
235  }
236  }
237  }
238 
239  /* If no session was found for received packet, traverse all
240  * endpoints and set COAP_SOCKET_CAN_READ if the received packet's
241  * destination address matches the endpoint. */
242  if (!found_port) {
243  coap_endpoint_t *ep;
244  LL_FOREACH(ctx->endpoint, ep) {
245  if ((get_port(&ep->bind_addr) == udp_hdr->dst_port.u16) &&
246  (address_equals(&ep->bind_addr, &ip6_hdr->dst))) {
247  coap_socket_t *sock = find_socket(ep->sock.fd, sockets, num_sockets);
248 
249  if (sock && (sock->flags & (COAP_SOCKET_WANT_READ))) {
250  coap_log(LOG_DEBUG, "fd %d on port %u can read\n",
251  sock->fd, ntohs(get_port(&ep->bind_addr)));
252  sock->flags |= COAP_SOCKET_CAN_READ;
253  sock->pkt = msg.content.ptr;
254  found_port = true;
255  break; /* found session, finish loop */
256  }
257  }
258  }
259  }
260  break;
261  }
262  case GNRC_NETAPI_MSG_TYPE_SND:
263  break;
264  case GNRC_NETAPI_MSG_TYPE_SET:
265  /* fall through */
266  case GNRC_NETAPI_MSG_TYPE_GET:
267  break;
268  default:
269  break;
270  }
271 
272  coap_ticks(&now);
273  coap_io_do_io(ctx, now);
274 
275  /* cleanup */
276  gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &coap_reg);
277 
278  return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
279 }
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Definition: coap_debug.c:906
Pulls together all the internal only header files.
const char * coap_socket_strerror(void)
Definition: coap_io.c:1459
#define COAP_RXBUFFER_SIZE
Definition: coap_io.h:22
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
Definition: coap_io.h:83
int coap_fd_t
Definition: coap_io.h:40
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
Definition: coap_io.h:87
#define COAP_SOCKET_CONNECTED
the socket is connected
Definition: coap_io.h:82
static uint16_t get_port(const coap_address_t *addr)
Returns the port of addr in network byte order or 0 on error.
Definition: coap_io_riot.c:152
ssize_t coap_network_read(coap_socket_t *sock, struct coap_packet_t *packet)
Function interface for reading data.
Definition: coap_io_riot.c:71
static msg_t _msg_q[LIBCOAP_MSG_QUEUE_SIZE]
Definition: coap_io_riot.c:141
static udp_hdr_t * get_udp_header(gnrc_pktsnip_t *pkt)
Definition: coap_io_riot.c:65
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
Definition: coap_io_riot.c:42
static coap_socket_t * find_socket(coap_fd_t fd, coap_socket_t *sockets[], unsigned int num_sockets)
Definition: coap_io_riot.c:165
static bool address_equals(const coap_address_t *a, const ipv6_addr_t *b)
Definition: coap_io_riot.c:174
void coap_riot_startup(void)
This function must be called in the RIOT CoAP thread for RIOT-specific initialization.
Definition: coap_io_riot.c:144
#define LIBCOAP_MSG_QUEUE_SIZE
Size of the queue for passing messages between the network interface and the coap stack.
Definition: coap_riot.h:16
#define LIBCOAP_MAX_SOCKETS
Maximum number of sockets that are simultaneously considered for reading or writing.
Definition: coap_riot.h:23
#define INET6_ADDRSTRLEN
#define SESSIONS_ITER(e, el, rtmp)
Definition: coap_session.h:637
void coap_io_do_io(coap_context_t *ctx, coap_tick_t now)
Processes any outstanding read, write, accept or connect I/O as indicated in the coap_socket_t struct...
Definition: net.c:1589
unsigned int coap_io_prepare_io(coap_context_t *ctx, coap_socket_t *sockets[], unsigned int max_sockets, unsigned int *num_sockets, coap_tick_t now)
Iterates through all the coap_socket_t structures embedded in endpoints or sessions associated with t...
Definition: coap_io.c:1039
int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition: coap_io_riot.c:182
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:120
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition: coap_time.h:135
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:61
size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:167
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
@ LOG_CRIT
Critical.
Definition: coap_debug.h:52
@ LOG_WARNING
Warning.
Definition: coap_debug.h:54
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:57
coap_address_t remote
remote address and port
Definition: coap_io.h:49
coap_address_t local
local address and port
Definition: coap_io.h:50
multi-purpose address abstraction
Definition: address.h:94
socklen_t size
size of addr
Definition: address.h:95
struct sockaddr_in sin
Definition: address.h:98
struct sockaddr_in6 sin6
Definition: address.h:99
struct sockaddr sa
Definition: address.h:97
union coap_address_t::@0 addr
The CoAP stack's global state is stored in a coap_context_t object.
Definition: net.h:141
coap_session_t * sessions
client sessions
Definition: net.h:162
coap_endpoint_t * endpoint
the endpoints used for listening
Definition: net.h:161
Abstraction of virtual endpoint that can be attached to coap_context_t.
coap_address_t bind_addr
local interface address
coap_socket_t sock
socket object for the interface, if any
size_t length
length of payload
Definition: coap_io.h:208
coap_addr_tuple_t addr_info
local and remote addresses
Definition: coap_io.h:206
unsigned char payload[COAP_RXBUFFER_SIZE]
payload
Definition: coap_io.h:209
int ifindex
the interface index
Definition: coap_io.h:207
coap_socket_t sock
socket object for the session, if any
Definition: coap_session.h:71
coap_addr_tuple_t addr_info
key: remote/local address info
Definition: coap_session.h:69
coap_fd_t fd
Definition: coap_io.h:59
coap_socket_flags_t flags
Definition: coap_io.h:64
unsigned int uint32_t
Definition: uthash.h:78
unsigned char uint8_t
Definition: uthash.h:79
#define LL_FOREACH(head, el)
Definition: utlist.h:413