coap_io_rt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /* coap_io_rt.h -- Default network I/O functions for libcoap
  2. *
  3. * Copyright (C) 2012,2014 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. #include "coap_config.h"
  9. #include <rtthread.h>
  10. #ifdef HAVE_STDIO_H
  11. # include <stdio.h>
  12. #endif
  13. #ifdef HAVE_SYS_SELECT_H
  14. # include <sys/select.h>
  15. #endif
  16. #ifdef HAVE_SYS_SOCKET_H
  17. # include <sys/socket.h>
  18. #endif
  19. #ifdef HAVE_NETINET_IN_H
  20. # include <netinet/in.h>
  21. #endif
  22. #ifdef HAVE_SYS_UIO_H
  23. # include <sys/uio.h>
  24. #endif
  25. #ifdef HAVE_UNISTD_H
  26. # include <unistd.h>
  27. #endif
  28. #include <errno.h>
  29. #ifdef WITH_CONTIKI
  30. # include "uip.h"
  31. #endif
  32. #include "debug.h"
  33. #include "mem.h"
  34. #include "coap_io.h"
  35. #ifdef WITH_POSIX
  36. /* define generic PKTINFO for IPv4 */
  37. #if defined(IP_PKTINFO)
  38. # define GEN_IP_PKTINFO IP_PKTINFO
  39. #elif defined(IP_RECVDSTADDR)
  40. # define GEN_IP_PKTINFO IP_RECVDSTADDR
  41. #else
  42. # error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
  43. #endif /* IP_PKTINFO */
  44. /* define generic KTINFO for IPv6 */
  45. // #ifdef IPV6_RECVPKTINFO
  46. // # define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
  47. // #elif defined(IPV6_PKTINFO)
  48. // # define GEN_IPV6_PKTINFO IPV6_PKTINFO
  49. // #else
  50. // # error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
  51. // #endif /* IPV6_RECVPKTINFO */
  52. struct coap_packet_t {
  53. coap_if_handle_t hnd; /**< the interface handle */
  54. coap_address_t src; /**< the packet's source address */
  55. coap_address_t dst; /**< the packet's destination address */
  56. const coap_endpoint_t *interface;
  57. int ifindex;
  58. void *session; /**< opaque session data */
  59. size_t length; /**< length of payload */
  60. unsigned char payload[]; /**< payload */
  61. };
  62. #endif
  63. #ifdef CUSTOM_COAP_NETWORK_ENDPOINT
  64. #ifdef WITH_CONTIKI
  65. static int ep_initialized = 0;
  66. static inline struct coap_endpoint_t *
  67. coap_malloc_contiki_endpoint() {
  68. static struct coap_endpoint_t ep;
  69. if (ep_initialized) {
  70. return NULL;
  71. } else {
  72. ep_initialized = 1;
  73. return &ep;
  74. }
  75. }
  76. static inline void
  77. coap_free_contiki_endpoint(struct coap_endpoint_t *ep) {
  78. ep_initialized = 0;
  79. }
  80. coap_endpoint_t *
  81. coap_new_endpoint(const coap_address_t *addr, int flags) {
  82. struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint();
  83. if (ep) {
  84. memset(ep, 0, sizeof(struct coap_endpoint_t));
  85. ep->handle.conn = udp_new(NULL, 0, NULL);
  86. if (!ep->handle.conn) {
  87. coap_free_endpoint(ep);
  88. return NULL;
  89. }
  90. coap_address_init(&ep->addr);
  91. uip_ipaddr_copy(&ep->addr.addr, &addr->addr);
  92. ep->addr.port = addr->port;
  93. udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port);
  94. }
  95. return ep;
  96. }
  97. void
  98. coap_free_endpoint(coap_endpoint_t *ep) {
  99. if (ep) {
  100. if (ep->handle.conn) {
  101. uip_udp_remove((struct uip_udp_conn *)ep->handle.conn);
  102. }
  103. coap_free_contiki_endpoint(ep);
  104. }
  105. }
  106. #else /* WITH_CONTIKI */
  107. static inline struct coap_endpoint_t *
  108. coap_malloc_posix_endpoint(void) {
  109. return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t));
  110. }
  111. static inline void
  112. coap_free_posix_endpoint(struct coap_endpoint_t *ep) {
  113. coap_free(ep);
  114. }
  115. coap_endpoint_t *
  116. coap_new_endpoint(const coap_address_t *addr, int flags) {
  117. int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0);
  118. int on = 1;
  119. struct coap_endpoint_t *ep;
  120. if (sockfd < 0) {
  121. coap_log(LOG_WARNING, "coap_new_endpoint: socket");
  122. return NULL;
  123. }
  124. if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
  125. coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR");
  126. if (bind(sockfd, &addr->addr.sa, addr->size) < 0) {
  127. coap_log(LOG_WARNING, "coap_new_endpoint: bind");
  128. close (sockfd);
  129. return NULL;
  130. }
  131. ep = coap_malloc_posix_endpoint();
  132. if (!ep) {
  133. coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
  134. close(sockfd);
  135. return NULL;
  136. }
  137. memset(ep, 0, sizeof(struct coap_endpoint_t));
  138. ep->handle.fd = sockfd;
  139. ep->flags = flags;
  140. ep->addr.size = addr->size;
  141. if (getsockname(sockfd, &ep->addr.addr.sa, &ep->addr.size) < 0) {
  142. coap_log(LOG_WARNING, "coap_new_endpoint: cannot determine local address");
  143. close (sockfd);
  144. return NULL;
  145. }
  146. #ifndef NDEBUG
  147. if (LOG_DEBUG <= coap_get_log_level()) {
  148. #ifndef INET6_ADDRSTRLEN
  149. #define INET6_ADDRSTRLEN 40
  150. #endif
  151. unsigned char addr_str[INET6_ADDRSTRLEN+8];
  152. if (coap_print_addr(&ep->addr, addr_str, INET6_ADDRSTRLEN+8)) {
  153. debug("created %sendpoint %s\n",
  154. ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "",
  155. addr_str);
  156. }
  157. }
  158. #endif /* NDEBUG */
  159. return (coap_endpoint_t *)ep;
  160. }
  161. void
  162. coap_free_endpoint(coap_endpoint_t *ep) {
  163. if(ep) {
  164. if (ep->handle.fd >= 0)
  165. close(ep->handle.fd);
  166. coap_free_posix_endpoint((struct coap_endpoint_t *)ep);
  167. }
  168. }
  169. #endif /* WITH_CONTIKI */
  170. #endif /* CUSTOM_COAP_NETWORK_ENDPOINT */
  171. #ifdef CUSTOM_COAP_NETWORK_SEND
  172. #if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H)
  173. /* define struct in6_pktinfo and struct in_pktinfo if not available
  174. FIXME: check with configure
  175. */
  176. struct in6_pktinfo {
  177. struct in6_addr ipi6_addr; /* src/dst IPv6 address */
  178. unsigned int ipi6_ifindex; /* send/recv interface index */
  179. };
  180. struct in_pktinfo {
  181. int ipi_ifindex;
  182. struct in_addr ipi_spec_dst;
  183. struct in_addr ipi_addr;
  184. };
  185. #endif
  186. #if defined(WITH_POSIX) && !defined(SOL_IP)
  187. /* Solaris expects level IPPROTO_IP for ancillary data. */
  188. #define SOL_IP IPPROTO_IP
  189. #endif
  190. #ifdef __GNUC__
  191. #define UNUSED_PARAM __attribute__ ((unused))
  192. #else /* not a GCC */
  193. #define UNUSED_PARAM
  194. #endif /* GCC */
  195. ssize_t
  196. coap_network_send(struct coap_context_t *context UNUSED_PARAM,
  197. const coap_endpoint_t *local_interface,
  198. const coap_address_t *dst,
  199. unsigned char *data,
  200. size_t datalen) {
  201. struct coap_endpoint_t *ep =
  202. (struct coap_endpoint_t *)local_interface;
  203. #ifndef WITH_CONTIKI
  204. return sendto(ep->handle.fd, data, datalen, 0, (struct sockaddr*)&dst->addr.sa, sizeof(struct sockaddr));
  205. #else /* WITH_CONTIKI */
  206. /* FIXME: untested */
  207. /* FIXME: is there a way to check if send was successful? */
  208. uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen,
  209. &dst->addr, dst->port);
  210. return datalen;
  211. #endif /* WITH_CONTIKI */
  212. }
  213. #endif /* CUSTOM_COAP_NETWORK_SEND */
  214. #ifdef CUSTOM_COAP_NETWORK_READ
  215. #define SIN6(A) ((struct sockaddr_in6 *)(A))
  216. #ifdef WITH_POSIX
  217. static coap_packet_t *
  218. coap_malloc_packet(void) {
  219. coap_packet_t *packet;
  220. const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE;
  221. packet = (coap_packet_t *)coap_malloc(need);
  222. if (packet) {
  223. memset(packet, 0, need);
  224. }
  225. return packet;
  226. }
  227. void
  228. coap_free_packet(coap_packet_t *packet) {
  229. coap_free(packet);
  230. }
  231. #endif /* WITH_POSIX */
  232. #ifdef WITH_CONTIKI
  233. static inline coap_packet_t *
  234. coap_malloc_packet(void) {
  235. return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0);
  236. }
  237. void
  238. coap_free_packet(coap_packet_t *packet) {
  239. coap_free_type(COAP_PACKET, packet);
  240. }
  241. #endif /* WITH_CONTIKI */
  242. static inline size_t
  243. coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) {
  244. return COAP_MAX_PDU_SIZE;
  245. }
  246. void
  247. coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
  248. {
  249. target->handle = packet->interface->handle;
  250. memcpy(&target->addr, &packet->dst, sizeof(target->addr));
  251. target->ifindex = packet->ifindex;
  252. target->flags = 0; /* FIXME */
  253. }
  254. void
  255. coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
  256. {
  257. memcpy(target, &packet->src, sizeof(coap_address_t));
  258. }
  259. void
  260. coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
  261. {
  262. *address = packet->payload;
  263. *length = packet->length;
  264. }
  265. /**
  266. * Checks if a message with destination address @p dst matches the
  267. * local interface with address @p local. This function returns @c 1
  268. * if @p dst is a valid match, and @c 0 otherwise.
  269. */
  270. static inline int
  271. is_local_if(const coap_address_t *local, const coap_address_t *dst) {
  272. return coap_address_isany(local) || coap_address_equals(dst, local) ||
  273. coap_is_mcast(dst);
  274. }
  275. ssize_t
  276. coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) {
  277. ssize_t len = -1;
  278. #ifdef WITH_POSIX
  279. #define SOCK_BUFFER_LEN (1024 + 512)
  280. char *sock_buffer = NULL;
  281. struct sockaddr_in sock_addr_src;
  282. socklen_t socklen_src = sizeof(struct sockaddr_in);
  283. #endif /* WITH_POSIX */
  284. assert(ep);
  285. assert(packet);
  286. *packet = coap_malloc_packet();
  287. if (!*packet) {
  288. warn("coap_network_read: insufficient memory, drop packet\n");
  289. return -1;
  290. }
  291. coap_address_init(&(*packet)->dst); /* the local interface address */
  292. coap_address_init(&(*packet)->src); /* the remote peer */
  293. #ifdef WITH_POSIX
  294. sock_buffer = coap_malloc(SOCK_BUFFER_LEN);
  295. if (sock_buffer){
  296. len = recvfrom(ep->handle.fd, sock_buffer, SOCK_BUFFER_LEN, 0, (struct sockaddr *)&sock_addr_src, (socklen_t *)&socklen_src);
  297. if (len < 0){
  298. coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno));
  299. goto error;
  300. } else {
  301. /* use getsockname() to get the local port */
  302. (*packet)->dst.size = sizeof((*packet)->dst.addr);
  303. if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) {
  304. coap_log(LOG_DEBUG, "cannot determine local port\n");
  305. goto error;
  306. }
  307. /* local interface for IPv4 */
  308. (*packet)->src.size = sizeof((*packet)->src.addr);
  309. memcpy(&(*packet)->src.addr.sa, &sock_addr_src, (*packet)->src.size);
  310. if (len > coap_get_max_packetlength(*packet)) {
  311. /* FIXME: we might want to send back a response */
  312. warn("discarded oversized packet\n");
  313. goto error;
  314. }
  315. if (!is_local_if(&ep->addr, &(*packet)->dst)) {
  316. coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
  317. printf("error 3\n");
  318. goto error;
  319. }
  320. (*packet)->length = len;
  321. memcpy(&(*packet)->payload, sock_buffer, len);
  322. }
  323. coap_free(sock_buffer);
  324. sock_buffer = NULL;
  325. } else {
  326. goto error;
  327. }
  328. #endif /* WITH_POSIX */
  329. #ifdef WITH_CONTIKI
  330. /* FIXME: untested, make this work */
  331. #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
  332. #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
  333. if(uip_newdata()) {
  334. uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr);
  335. (*packet)->src.port = UIP_UDP_BUF->srcport;
  336. uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr);
  337. (*packet)->dst.port = UIP_UDP_BUF->destport;
  338. if (!is_local_if(&ep->addr, &(*packet)->dst)) {
  339. coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
  340. goto error;
  341. }
  342. len = uip_datalen();
  343. if (len > coap_get_max_packetlength(*packet)) {
  344. /* FIXME: we might want to send back a response */
  345. warn("discarded oversized packet\n");
  346. return -1;
  347. }
  348. ((char *)uip_appdata)[len] = 0;
  349. #ifndef NDEBUG
  350. if (LOG_DEBUG <= coap_get_log_level()) {
  351. #ifndef INET6_ADDRSTRLEN
  352. #define INET6_ADDRSTRLEN 40
  353. #endif
  354. unsigned char addr_str[INET6_ADDRSTRLEN+8];
  355. if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) {
  356. debug("received %zd bytes from %s\n", len, addr_str);
  357. }
  358. }
  359. #endif /* NDEBUG */
  360. (*packet)->length = len;
  361. memcpy(&(*packet)->payload, uip_appdata, len);
  362. }
  363. #undef UIP_IP_BUF
  364. #undef UIP_UDP_BUF
  365. #endif /* WITH_CONTIKI */
  366. #ifdef WITH_LWIP
  367. #error "coap_network_read() not implemented on this platform"
  368. #endif
  369. (*packet)->interface = ep;
  370. return len;
  371. error:
  372. #ifdef WITH_POSIX
  373. if (sock_buffer)
  374. coap_free(sock_buffer);
  375. sock_buffer = NULL;
  376. #endif
  377. coap_free_packet(*packet);
  378. *packet = NULL;
  379. return -1;
  380. }
  381. #undef SIN6
  382. #endif /* CUSTOM_COAP_NETWORK_READ */