coap_transport_socket.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * Copyright (c) 2014 - 2019, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include <sys/socket.h>
  41. #include <sys/select.h>
  42. #include <netinet/in.h>
  43. #ifdef UNIX
  44. #include <fcntl.h>
  45. #endif
  46. #include <errno.h>
  47. #include <stdint.h>
  48. #include "mem_manager.h"
  49. #include "sdk_errors.h"
  50. #include "sdk_config.h"
  51. #include "iot_common.h"
  52. #include "nordic_common.h"
  53. #include "coap_transport.h"
  54. #include "coap.h"
  55. /**@brief UDP port information. */
  56. typedef struct
  57. {
  58. int socket_fd; /**< Socket information provided by UDP. */
  59. uint16_t port_number; /**< Associated port number. */
  60. } udp_port_t;
  61. static udp_port_t m_port_table[COAP_PORT_COUNT]; /**< Table maintaining association between CoAP ports and corresponding UDP socket identifiers. */
  62. static fd_set m_readfds;
  63. static int m_max_sd = 0;
  64. /**@brief Creates port as requested in p_port.
  65. *
  66. * @details Creates port as requested in p_port.
  67. *
  68. * @param[in] index Index to the m_port_table where entry of the port created is to be made.
  69. * @param[in] p_port Port information to be created.
  70. *
  71. * @retval NRF_SUCCESS Indicates if port was created successfully, else an an error code
  72. * indicating reason for failure.
  73. */
  74. static uint32_t port_create(uint32_t index, coap_port_t * p_port)
  75. {
  76. // Request new socket creation.
  77. int socket_fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  78. if (socket_fd != -1)
  79. {
  80. // Bind the socket to the local port.
  81. struct sockaddr_in6 sin6;
  82. memset(&sin6, 0, sizeof(struct sockaddr_in6));
  83. sin6.sin6_family = AF_INET6;
  84. sin6.sin6_port = htons(p_port->port_number);
  85. sin6.sin6_addr = in6addr_any;
  86. int retval = bind(socket_fd, (struct sockaddr *)&sin6, sizeof(sin6));
  87. if (retval != -1)
  88. {
  89. m_port_table[index].port_number = p_port->port_number;
  90. m_port_table[index].socket_fd = socket_fd;
  91. }
  92. else
  93. {
  94. // Not all procedures succeeded with allocated socket, hence free it.
  95. UNUSED_VARIABLE(close(socket_fd));
  96. return NRF_ERROR_INVALID_PARAM;
  97. }
  98. }
  99. // Configure socket to be non-blocking.
  100. int flags = fcntl(socket_fd, F_GETFL, 0);
  101. flags |= O_NONBLOCK;
  102. UNUSED_VARIABLE(fcntl(m_port_table[index].socket_fd, F_SETFL, flags));
  103. // Add socket to file descriptor set.
  104. FD_SET(m_port_table[index].socket_fd, &m_readfds);
  105. // If enumeration is having a gap, increase the max fd count.
  106. if (socket_fd >= m_max_sd)
  107. {
  108. m_max_sd = (socket_fd + 1);
  109. }
  110. return NRF_SUCCESS;
  111. }
  112. uint32_t coap_transport_init(const coap_transport_init_t * p_param)
  113. {
  114. uint32_t err_code = NRF_SUCCESS;
  115. uint32_t index;
  116. NULL_PARAM_CHECK(p_param);
  117. NULL_PARAM_CHECK(p_param->p_port_table);
  118. FD_ZERO(&m_readfds);
  119. err_code = nrf_mem_init();
  120. if (err_code == NRF_SUCCESS) {
  121. for (index = 0; index < COAP_PORT_COUNT; index++)
  122. {
  123. // Create end point for each of the COAP ports.
  124. err_code = port_create(index, &p_param->p_port_table[index]);
  125. if (err_code != NRF_SUCCESS)
  126. {
  127. break;
  128. }
  129. }
  130. }
  131. return err_code;
  132. }
  133. uint32_t coap_transport_write(const coap_port_t * p_port,
  134. const coap_remote_t * p_remote,
  135. const uint8_t * p_data,
  136. uint16_t datalen)
  137. {
  138. uint32_t err_code = NRF_ERROR_NOT_FOUND;
  139. uint32_t index;
  140. NULL_PARAM_CHECK(p_port);
  141. NULL_PARAM_CHECK(p_remote);
  142. NULL_PARAM_CHECK(p_data);
  143. // Search for the corresponding port.
  144. for (index = 0; index < COAP_PORT_COUNT; index++)
  145. {
  146. if (m_port_table[index].port_number == p_port->port_number)
  147. {
  148. COAP_MUTEX_UNLOCK();
  149. static struct sockaddr_in6 dest_address_in6;
  150. memset(&dest_address_in6, 0, sizeof(struct sockaddr_in6));
  151. dest_address_in6.sin6_family = AF_INET6;
  152. dest_address_in6.sin6_port = htons(p_remote->port_number);
  153. memcpy(&dest_address_in6.sin6_addr, p_remote->addr, sizeof(struct in6_addr));
  154. // Send on UDP port.
  155. int retval = sendto(m_port_table[index].socket_fd,
  156. p_data,
  157. datalen,
  158. 0,
  159. (struct sockaddr *)&dest_address_in6,
  160. sizeof(dest_address_in6));
  161. if (retval == -1)
  162. {
  163. // Error in sendto.
  164. err_code = NRF_ERROR_INTERNAL;
  165. }
  166. else
  167. {
  168. err_code = NRF_SUCCESS;
  169. }
  170. COAP_MUTEX_LOCK();
  171. break;
  172. }
  173. }
  174. return err_code;
  175. }
  176. void coap_transport_process(void)
  177. {
  178. return;
  179. }
  180. uint32_t coap_security_setup(uint16_t local_port,
  181. nrf_tls_role_t role,
  182. coap_remote_t * const p_remote,
  183. nrf_tls_key_settings_t * const p_settings)
  184. {
  185. return SDK_ERR_API_NOT_IMPLEMENTED;
  186. }
  187. uint32_t coap_security_destroy(uint16_t local_port,
  188. coap_remote_t * const p_remote)
  189. {
  190. return SDK_ERR_API_NOT_IMPLEMENTED;
  191. }
  192. void coap_transport_input(void)
  193. {
  194. int retval = select(m_max_sd, &m_readfds, NULL, NULL, NULL);
  195. if (retval == -1)
  196. {
  197. // Error in select().
  198. // Placeholder for debugging.
  199. }
  200. else if (retval >= 1) // Number of file descriptiors with activity.
  201. {
  202. uint32_t index = 0;
  203. int socket_fd = m_port_table[index].socket_fd;
  204. // The descriptor has data.
  205. if (FD_ISSET(socket_fd, &m_readfds)) // If socket_fd is set to read.
  206. {
  207. static uint8_t read_mem[COAP_MESSAGE_DATA_MAX_SIZE];
  208. static struct sockaddr_in6 client_address_in6;
  209. socklen_t address_length = sizeof(struct sockaddr_in6);
  210. int bytes_read = recvfrom(socket_fd,
  211. read_mem,
  212. sizeof(read_mem),
  213. 0,
  214. (struct sockaddr *)&client_address_in6,
  215. (socklen_t *)&address_length); // Blocking call, waiting for incoming transaction.
  216. if (bytes_read >= 0)
  217. {
  218. coap_port_t port;
  219. port.port_number = m_port_table[index].port_number;
  220. coap_remote_t remote_endpoint;
  221. memcpy(remote_endpoint.addr, &client_address_in6.sin6_addr, sizeof(struct in6_addr));
  222. remote_endpoint.port_number = ntohs(client_address_in6.sin6_port);
  223. uint32_t result = NRF_SUCCESS;
  224. // Notify the CoAP module of received data.
  225. retval = coap_transport_read(&port,
  226. &remote_endpoint,
  227. NULL,
  228. result,
  229. read_mem,
  230. (uint16_t)bytes_read);
  231. // Nothing much to do if CoAP could not interpret the datagram.
  232. UNUSED_VARIABLE(retval);
  233. }
  234. else
  235. {
  236. // Error in readfrom().
  237. // Placeholder for debugging.
  238. // If select() indicated this socket file descriptor to have pending
  239. // data, this case should not occur.
  240. }
  241. }
  242. }
  243. else
  244. {
  245. // In case of socket() returning 0, timeout.
  246. // Not implemented.
  247. }
  248. }