• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* coap_io_contiki.c -- Network I/O functions for libcoap on Contiki-NG
2  *
3  * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
4  *               2014 chrysn <chrysn@fsfe.org>
5  *
6  * SPDX-License-Identifier: BSD-2-Clause
7  *
8  * This file is part of the CoAP library libcoap. Please see
9  * README for terms of use.
10  */
11 
12 /**
13  * @file coap_io_contiki.c
14  * @brief Contiki-NG-specific functions
15  */
16 
17 #include "coap3/coap_internal.h"
18 #include "contiki-net.h"
19 
20 PROCESS(libcoap_io_process, "libcoap I/O");
21 static int was_io_process_stopped;
22 
23 void
coap_start_io_process(void)24 coap_start_io_process(void) {
25   was_io_process_stopped = 0;
26   process_start(&libcoap_io_process, NULL);
27 }
28 
29 void
coap_stop_io_process(void)30 coap_stop_io_process(void) {
31   was_io_process_stopped = 1;
32   process_poll(&libcoap_io_process);
33 }
34 
35 static void
on_prepare_timer_expired(void * ptr)36 on_prepare_timer_expired(void *ptr) {
37   coap_context_t *ctx;
38   coap_tick_t now;
39   coap_socket_t *sockets[1];
40   unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
41   unsigned int num_sockets;
42   unsigned timeout;
43 
44   ctx = (coap_context_t *)ptr;
45   coap_ticks(&now);
46   timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now);
47   if (!timeout) {
48     return;
49   }
50   ctimer_set(&ctx->prepare_timer,
51              CLOCK_SECOND * timeout / 1000,
52              on_prepare_timer_expired,
53              ctx);
54 }
55 
PROCESS_THREAD(libcoap_io_process,ev,data)56 PROCESS_THREAD(libcoap_io_process, ev, data) {
57   coap_socket_t *coap_socket;
58 
59   PROCESS_BEGIN();
60   while (!was_io_process_stopped) {
61     PROCESS_WAIT_EVENT();
62     if (was_io_process_stopped) {
63       break;
64     }
65     if (ev == tcpip_event) {
66       coap_socket = (struct coap_socket_t *)data;
67       if (!coap_socket) {
68         coap_log_crit("libcoap_io_process: data should never be NULL\n");
69         continue;
70       }
71       if (uip_newdata()) {
72         coap_socket->flags |= COAP_SOCKET_CAN_READ;
73         coap_io_process(coap_socket->context, 0);
74         ctimer_stop(&coap_socket->context->prepare_timer);
75         on_prepare_timer_expired(coap_socket->context);
76       }
77     }
78   }
79   PROCESS_END();
80 }
81 
82 int
coap_socket_bind_udp(coap_socket_t * sock,const coap_address_t * listen_addr,coap_address_t * bound_addr)83 coap_socket_bind_udp(coap_socket_t *sock,
84                      const coap_address_t *listen_addr,
85                      coap_address_t *bound_addr) {
86   uip_ds6_addr_t *addr;
87 
88   addr = uip_ds6_get_global(ADDR_PREFERRED);
89   if (!addr) {
90     coap_log_err("coap_socket_bind_udp: called before getting an IPv6 address\n");
91     return 0;
92   }
93   PROCESS_CONTEXT_BEGIN(&libcoap_io_process);
94   sock->udp_conn = udp_new(NULL, 0, sock);
95   PROCESS_CONTEXT_END();
96   if (!sock->udp_conn) {
97     coap_log_err("coap_socket_bind_udp: udp_new returned NULL\n");
98     return 0;
99   }
100   udp_bind(sock->udp_conn, listen_addr->port);
101   uip_ipaddr_copy(&bound_addr->addr, &addr->ipaddr);
102   bound_addr->port = sock->udp_conn->lport;
103   return 1;
104 }
105 
106 int
coap_socket_connect_udp(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)107 coap_socket_connect_udp(coap_socket_t *sock,
108                         const coap_address_t *local_if,
109                         const coap_address_t *server,
110                         int default_port,
111                         coap_address_t *local_addr,
112                         coap_address_t *remote_addr) {
113   uip_ds6_addr_t *addr;
114 
115   if (local_if) {
116     coap_log_warn("coap_socket_connect_udp: ignoring local_if parameter\n");
117   }
118   addr = uip_ds6_get_global(ADDR_PREFERRED);
119   if (!addr) {
120     coap_log_err("coap_socket_connect_udp: called before getting an IPv6 address\n");
121     return 0;
122   }
123   PROCESS_CONTEXT_BEGIN(&libcoap_io_process);
124   sock->udp_conn = udp_new(&server->addr, server->port ? server->port : default_port, sock);
125   PROCESS_CONTEXT_END();
126   if (!sock->udp_conn) {
127     coap_log_err("coap_socket_connect_udp: udp_new returned NULL\n");
128     return 0;
129   }
130   uip_ipaddr_copy(&local_addr->addr, &addr->ipaddr);
131   local_addr->port = sock->udp_conn->lport;
132   uip_ipaddr_copy(&remote_addr->addr, &server->addr);
133   remote_addr->port = sock->udp_conn->rport;
134   sock->flags |= COAP_SOCKET_CONNECTED;
135   return 1;
136 }
137 
138 ssize_t
coap_socket_write(coap_socket_t * sock,const uint8_t * data,size_t data_len)139 coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
140   return -1;
141 }
142 
143 ssize_t
coap_socket_read(coap_socket_t * sock,uint8_t * data,size_t data_len)144 coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
145   return -1;
146 }
147 
148 void
coap_socket_close(coap_socket_t * sock)149 coap_socket_close(coap_socket_t *sock) {
150   uip_udp_remove(sock->udp_conn);
151   sock->udp_conn = NULL;
152   sock->flags = COAP_SOCKET_EMPTY;
153 }
154 
155 /*
156  * dgram
157  * return +ve Number of bytes written.
158  *         -1 Error error in errno).
159  */
160 ssize_t
coap_socket_send(coap_socket_t * sock,const coap_session_t * session,const uint8_t * data,size_t datalen)161 coap_socket_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data,
162                  size_t datalen) {
163   ssize_t bytes_written = 0;
164 
165   if (!coap_debug_send_packet()) {
166     bytes_written = (ssize_t)datalen;
167   } else {
168     uip_udp_packet_sendto(sock->udp_conn, data, datalen,
169                           &session->addr_info.remote.addr, session->addr_info.remote.port);
170     bytes_written = datalen;
171   }
172 
173   if (bytes_written < 0) {
174     coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
175   }
176 
177   return bytes_written;
178 }
179 
180 /*
181  * dgram
182  * return +ve Number of bytes written.
183  *         -1 Error error in errno).
184  *         -2 ICMP error response
185  */
186 ssize_t
coap_socket_recv(coap_socket_t * sock,coap_packet_t * packet)187 coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet) {
188   ssize_t len;
189 
190   assert(sock);
191   assert(packet);
192 
193   if (!(sock->flags & COAP_SOCKET_CAN_READ)) {
194     return -1;
195   }
196   /* clear has-data flag */
197   sock->flags &= ~COAP_SOCKET_CAN_READ;
198 
199   uip_ipaddr_copy(&packet->addr_info.remote.addr, &UIP_IP_BUF->srcipaddr);
200   packet->addr_info.remote.port = UIP_UDP_BUF->srcport;
201   uip_ipaddr_copy(&packet->addr_info.local.addr, &UIP_IP_BUF->destipaddr);
202   packet->addr_info.local.port = UIP_UDP_BUF->destport;
203 
204   len = uip_datalen();
205 
206   if (len > COAP_RXBUFFER_SIZE) {
207     coap_log_warn("Received message does not fit within buffer\n");
208     return -1;
209   }
210   packet->length = len;
211   packet->payload = uip_appdata;
212 
213   return len;
214 }
215 
216 int
coap_io_process(coap_context_t * ctx,uint32_t timeout_ms)217 coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
218   coap_tick_t before, now;
219 
220   coap_ticks(&before);
221   coap_io_do_io(ctx, before);
222   coap_ticks(&now);
223   return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
224 }
225