coap_client.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * File : coap_client.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2009-2018 RT-Thread Develop Team
  5. */
  6. #include <rtthread.h>
  7. #include "finsh.h"
  8. #include <string.h>
  9. #include <sys/socket.h>
  10. #include <netdb.h>
  11. #include "coap.h"
  12. #include "coap_config.h"
  13. #define COAP_DEFAULT_DEMO_URI "coap://coap.me/test"
  14. #define COAP_DEFAULT_TIME_SEC 5
  15. #define COAP_DEFAULT_TIME_USEC 0
  16. static uint8_t coap_request_mode = 0;
  17. static char coap_uri[64] = {0};
  18. static coap_uri_t uri;
  19. static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote,
  20. coap_pdu_t *sent, coap_pdu_t *received,
  21. const coap_tid_t id)
  22. {
  23. unsigned char *data = NULL;
  24. size_t data_len;
  25. coap_opt_t *block_opt;
  26. coap_pdu_t *request = NULL;
  27. unsigned char buf[4];
  28. coap_opt_iterator_t opt_iter;
  29. coap_tid_t tid;
  30. if (COAP_RESPONSE_CLASS(received->hdr->code) == 2)
  31. {
  32. if (coap_get_data(received, &data_len, &data))
  33. {
  34. rt_kprintf("%.*s", data_len, data);
  35. }
  36. /* Got some data, check if block option is set. Behavior is undefined if
  37. * both, Block1 and Block2 are present. */
  38. block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter);
  39. if (block_opt)
  40. { /* handle Block2 */
  41. unsigned short blktype = opt_iter.type;
  42. if (COAP_OPT_BLOCK_MORE(block_opt))
  43. {
  44. request = coap_new_pdu();
  45. if (request)
  46. {
  47. // CoAP message type
  48. request->hdr->type = COAP_MESSAGE_CON;
  49. request->hdr->id = coap_new_message_id(ctx);
  50. // CoAP request methods
  51. request->hdr->code = coap_request_mode;
  52. coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
  53. coap_add_option(request,
  54. blktype,
  55. coap_encode_var_bytes(buf,
  56. ((coap_opt_block_num(block_opt) + 1) << 4) |
  57. COAP_OPT_BLOCK_SZX(block_opt)),
  58. buf);
  59. tid = coap_send_confirmed(ctx, local_interface, remote, request);
  60. if (tid == COAP_INVALID_TID)
  61. {
  62. rt_kprintf("message_handler: error sending new request\n");
  63. coap_delete_pdu(request);
  64. return;
  65. }
  66. }
  67. }
  68. }
  69. }
  70. }
  71. static void coap_client_task(void *arg)
  72. {
  73. struct hostent *hp;
  74. struct ip4_addr *ip4_addr;
  75. coap_tick_t now;
  76. coap_context_t *ctx = NULL;
  77. coap_address_t dst_addr, src_addr;
  78. fd_set readfds;
  79. struct timeval tv;
  80. int result;
  81. coap_pdu_t *request = NULL;
  82. const char *server_uri = RT_NULL;
  83. char server_host[64] = {0};
  84. if (strlen(coap_uri) != 0)
  85. server_uri = coap_uri;
  86. else
  87. server_uri = COAP_DEFAULT_DEMO_URI;
  88. /* CoAP request methods */
  89. uint8_t get_method = coap_request_mode; // COAP_REQUEST_GET
  90. if (coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri) == -1)
  91. {
  92. rt_kprintf("CoAP server uri error\n");
  93. goto _exit;
  94. }
  95. char *str_s = (char *)uri.host.s;
  96. char *dlm_s = (char *)"/";
  97. char *str_t = RT_NULL, *saveptr = RT_NULL;
  98. str_t = strtok_r(str_s, dlm_s, &saveptr);
  99. if (str_t != RT_NULL)
  100. {
  101. rt_memset(server_host, 0, sizeof(server_host));
  102. strncpy((char *)server_host, str_t, sizeof(server_host));
  103. rt_kprintf("server_host = %s\n", server_host);
  104. }
  105. else
  106. {
  107. strncpy((char *)server_host, (const char *)uri.host.s, sizeof(server_host));
  108. rt_kprintf("server_host = %s\n", server_host);
  109. }
  110. while (1)
  111. {
  112. // It may take several iterations for getting DNS success
  113. hp = gethostbyname((const char *)server_host); // getaddrinfo
  114. if (hp == NULL)
  115. {
  116. rt_kprintf("DNS lookup failed\n");
  117. rt_thread_delay(1000);
  118. continue; // Duplicate DNS GET
  119. }
  120. ip4_addr = (struct ip4_addr *)hp->h_addr;
  121. rt_kprintf("DNS lookup succeeded. IP=%s\n", inet_ntoa(*ip4_addr));
  122. // Reset the given coap_address_t object to its default values
  123. coap_address_init(&src_addr);
  124. src_addr.addr.sin.sin_family = AF_INET;
  125. src_addr.addr.sin.sin_port = htons(0);
  126. src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
  127. // Create a new object for holding coap stack status
  128. ctx = coap_new_context(&src_addr);
  129. if (ctx)
  130. {
  131. // Init destination addr
  132. coap_address_init(&dst_addr);
  133. dst_addr.addr.sin.sin_family = AF_INET;
  134. dst_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
  135. dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
  136. coap_register_option(ctx, COAP_OPTION_BLOCK2);
  137. // Register a received message handler
  138. coap_register_response_handler(ctx, message_handler);
  139. request = coap_new_pdu();
  140. if (request)
  141. {
  142. // CoAP message type
  143. request->hdr->type = COAP_MESSAGE_CON;
  144. request->hdr->id = coap_new_message_id(ctx);
  145. // CoAP request methods
  146. request->hdr->code = get_method;
  147. if (uri.path.length != 0)
  148. {
  149. coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
  150. }
  151. // Sends a confirmed CoAP message to given destination
  152. int coap_ret = coap_send_confirmed(ctx, ctx->endpoint, &dst_addr, request);
  153. tv.tv_usec = COAP_DEFAULT_TIME_USEC;
  154. tv.tv_sec = COAP_DEFAULT_TIME_SEC;
  155. coap_queue_t *nextpdu;
  156. for (;;)
  157. {
  158. FD_ZERO(&readfds);
  159. FD_SET(ctx->sockfd, &readfds);
  160. nextpdu = coap_peek_next(ctx);
  161. coap_ticks(&now);
  162. while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime)
  163. {
  164. coap_retransmit(ctx, coap_pop_next(ctx));
  165. rt_kprintf("\nCoAP retransmit...\n");
  166. nextpdu = coap_peek_next(ctx);
  167. }
  168. if (!nextpdu)
  169. {
  170. rt_kprintf("\nTransmit end.\n");
  171. goto _exit;
  172. }
  173. result = select(ctx->sockfd + 1, &readfds, RT_NULL, RT_NULL, &tv);
  174. if (result > 0)
  175. {
  176. if (FD_ISSET(ctx->sockfd, &readfds))
  177. coap_read(ctx);
  178. }
  179. else if (result < 0)
  180. {
  181. break;
  182. }
  183. else
  184. {
  185. rt_kprintf("\nselect timeout...\n");
  186. }
  187. }
  188. }
  189. }
  190. goto _exit;
  191. }
  192. _exit:
  193. if (ctx != RT_NULL)
  194. coap_free_context(ctx);
  195. return;
  196. }
  197. static void usage(const char *program, const char *version)
  198. {
  199. rt_kprintf("\nHelp:\nlibcoap %s -- a small CoAP implementation\n"
  200. "usage: %s [-m type...] [Uri text]\n",
  201. version, program);
  202. rt_kprintf("\t\t type: get; post; put; delete.\n"
  203. "Example: %s -m get coap://wsncoap.org\n",
  204. program);
  205. }
  206. static uint8_t cmdline_method(char *arg)
  207. {
  208. static char *methods[] = {0, "get", "post", "put", "delete", 0};
  209. unsigned char i;
  210. for (i = 1; methods[i] && strcasecmp(arg, methods[i]) != 0; ++i)
  211. ;
  212. return i; /* note that we do not prevent illegal methods */
  213. }
  214. static int cmdline_option_parser(int argc, char **argv)
  215. {
  216. int8_t ret = -1;
  217. if (argc < 4)
  218. {
  219. rt_kprintf("\n======= CoAP client usage: ========\n");
  220. usage(argv[0], PACKAGE_VERSION);
  221. return ret;
  222. }
  223. else if (strstr(argv[3], "coap://") == RT_NULL) // judge uri format
  224. {
  225. rt_kprintf("Warning: param three is not allowed!\n");
  226. usage(argv[0], PACKAGE_VERSION);
  227. return ret;
  228. }
  229. else if (strcmp(argv[1], "-m") != 0)
  230. {
  231. rt_kprintf("Warning: in param is error, please use '-m' param.\n");
  232. usage(argv[0], PACKAGE_VERSION);
  233. return ret;
  234. }
  235. coap_request_mode = cmdline_method(argv[2]); //1:GET; 2:POST; 3:PUT; 4:DELETE
  236. if (strlen(argv[3]) < sizeof(coap_uri))
  237. strncpy((char *)coap_uri, (const char *)argv[3], sizeof(coap_uri));
  238. else
  239. {
  240. rt_kprintf("Warning: coap uri is too long. The length of the limit is %d\n", sizeof(coap_uri) - 1);
  241. return ret;
  242. }
  243. rt_kprintf("coap uri = %s\n", coap_uri);
  244. ret = 0;
  245. return ret;
  246. }
  247. static int coap_client(int argc, char **argv)
  248. {
  249. rt_thread_t tid;
  250. int8_t ret = 0;
  251. ret = cmdline_option_parser(argc, argv);
  252. if (ret != 0)
  253. return ret;
  254. tid = rt_thread_create("CoAPClient",
  255. coap_client_task, RT_NULL,
  256. 4096,
  257. RT_THREAD_PRIORITY_MAX - 2,
  258. 10);
  259. if (tid != RT_NULL)
  260. rt_thread_startup(tid);
  261. return ret;
  262. }
  263. MSH_CMD_EXPORT(coap_client, Using coap_client to get usage);