1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "iotx_coap_internal.h"
10 #include "ctype.h"
11 #include "Cloud_CoAPPlatform.h"
12 #include "Cloud_CoAPNetwork.h"
13 #include "Cloud_CoAPExport.h"
14 
15 #define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */
16 #define COAPS_DEFAULT_PORT \
17     5684 /* CoAP default UDP port for secure transmission */
18 
19 #define COAP_DEFAULT_SCHEME       "coap" /* the default scheme for CoAP URIs */
20 #define COAP_DEFAULT_HOST_LEN     128
21 #define COAP_DEFAULT_WAIT_TIME_MS 2000
22 
Cloud_CoAPUri_parse(char * p_uri,coap_endpoint_type * p_endpoint_type,char host[COAP_DEFAULT_HOST_LEN],unsigned short * port)23 unsigned int Cloud_CoAPUri_parse(char *p_uri,
24                                  coap_endpoint_type *p_endpoint_type,
25                                  char host[COAP_DEFAULT_HOST_LEN],
26                                  unsigned short *port)
27 {
28     int len = 0;
29     char *p = NULL, *q = NULL;
30     if (NULL == p_uri || NULL == p_endpoint_type) {
31         return COAP_ERROR_INVALID_PARAM;
32     }
33 
34     COAP_DEBUG("The uri is %s", p_uri);
35     len = strlen(p_uri);
36     p = p_uri;
37     q = (char *)COAP_DEFAULT_SCHEME;
38     while (len && *q && tolower(*p) == *q) {
39         ++p;
40         ++q;
41         --len;
42     }
43 
44     if (*q) {
45         return COAP_ERROR_INVALID_URI;
46     }
47     if (tolower(*p) == 's') {
48         ++p;
49         --len;
50         *p_endpoint_type = COAP_ENDPOINT_DTLS;
51         *port = COAPS_DEFAULT_PORT;
52     } else if (*p == '-') {
53         ++p;
54         --len;
55         q = (char *)"psk";
56         while (len && *q && tolower(*p) == *q) {
57             ++p;
58             ++q;
59             --len;
60         }
61         if (*q) {
62             return COAP_ERROR_INVALID_URI;
63         }
64         *p_endpoint_type = COAP_ENDPOINT_PSK;
65         *port = COAP_DEFAULT_PORT;
66     } else {
67         *p_endpoint_type = COAP_ENDPOINT_NOSEC;
68         *port = COAP_DEFAULT_PORT;
69     }
70     COAP_DEBUG("The endpoint type is: %d", *p_endpoint_type);
71 
72     q = (char *)"://";
73     while (len && *q && tolower(*p) == *q) {
74         ++p;
75         ++q;
76         --len;
77     }
78 
79     if (*q) {
80         return COAP_ERROR_INVALID_URI;
81     }
82 
83     q = p;
84     while (len && *q != ':') {
85         ++q;
86         --len;
87     }
88     if (p == q) {
89         return COAP_ERROR_INVALID_URI;
90     }
91 
92     if (COAP_DEFAULT_HOST_LEN - 1 < (q - p)) {
93         return COAP_ERROR_INVALID_URI;
94     } else {
95         memset(host, 0x00, COAP_DEFAULT_HOST_LEN);
96         strncpy(host, p, q - p);
97     }
98     COAP_DEBUG("The host name is: %s", host);
99     if (len && *q == ':') {
100         p = ++q;
101         --len;
102 
103         while (len && isdigit(*q)) {
104             ++q;
105             --len;
106         }
107 
108         if (p < q) {
109             int uri_port = 0;
110 
111             while (p < q) {
112                 uri_port = uri_port * 10 + (*p++ - '0');
113             }
114 
115             if (uri_port > 65535) {
116                 return COAP_ERROR_INVALID_URI;
117             }
118             *port = uri_port;
119         }
120     }
121     COAP_DEBUG("The port is: %d", *port);
122 
123     return COAP_SUCCESS;
124 }
125 
Cloud_CoAPContext_create(Cloud_CoAPInitParam * param)126 Cloud_CoAPContext *Cloud_CoAPContext_create(Cloud_CoAPInitParam *param)
127 {
128     unsigned int ret = COAP_SUCCESS;
129     Cloud_CoAPContext *p_ctx = NULL;
130     coap_network_init_t network_param;
131     char host[COAP_DEFAULT_HOST_LEN] = { 0 };
132 
133     memset(&network_param, 0x00, sizeof(coap_network_init_t));
134     p_ctx = coap_malloc(sizeof(Cloud_CoAPContext));
135     if (NULL == p_ctx) {
136         COAP_ERR("malloc for coap context failed");
137         goto err;
138     }
139 
140     memset(p_ctx, 0, sizeof(Cloud_CoAPContext));
141     p_ctx->message_id = 1;
142     p_ctx->notifier = param->notifier;
143     p_ctx->sendbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN);
144     if (NULL == p_ctx->sendbuf) {
145         COAP_ERR("not enough memory");
146         goto err;
147     }
148 
149     p_ctx->recvbuf = coap_malloc(COAP_MSG_MAX_PDU_LEN);
150     if (NULL == p_ctx->recvbuf) {
151         COAP_ERR("not enough memory");
152         goto err;
153     }
154 
155     if (0 == param->waittime) {
156         p_ctx->waittime = COAP_DEFAULT_WAIT_TIME_MS;
157     } else {
158         p_ctx->waittime = param->waittime;
159     }
160 
161     /*CoAP message send list*/
162     INIT_LIST_HEAD(&p_ctx->list.sendlist);
163     p_ctx->list.count = 0;
164     p_ctx->list.maxcount = param->maxcount;
165 
166     /*set the endpoint type by uri schema*/
167     if (NULL != param->url) {
168         ret = Cloud_CoAPUri_parse(param->url, &network_param.ep_type, host,
169                                   &network_param.port);
170     }
171 
172     if (COAP_SUCCESS != ret) {
173         goto err;
174     }
175 
176 #ifdef COAP_DTLS_SUPPORT
177     if (COAP_ENDPOINT_DTLS == network_param.ep_type) {
178         extern const char *iotx_ca_crt;
179         network_param.p_ca_cert_pem = (unsigned char *)iotx_ca_crt;
180     }
181 #endif
182     if (COAP_ENDPOINT_NOSEC == network_param.ep_type ||
183         COAP_ENDPOINT_PSK == network_param.ep_type) {
184         network_param.p_ca_cert_pem = NULL;
185     }
186     network_param.p_host = host;
187 
188     /*CoAP network init*/
189     ret = Cloud_CoAPNetwork_init(&network_param, &p_ctx->network);
190 
191     if (COAP_SUCCESS != ret) {
192         goto err;
193     }
194 
195     return p_ctx;
196 err:
197     if (NULL == p_ctx) {
198         return p_ctx;
199     }
200 
201     if (NULL != p_ctx->recvbuf) {
202         coap_free(p_ctx->recvbuf);
203         p_ctx->recvbuf = NULL;
204     }
205 
206     if (NULL != p_ctx->sendbuf) {
207         coap_free(p_ctx->sendbuf);
208         p_ctx->sendbuf = NULL;
209     }
210 
211     coap_free(p_ctx);
212     p_ctx = NULL;
213 
214     return p_ctx;
215 }
216 
Cloud_CoAPContext_free(Cloud_CoAPContext * p_ctx)217 void Cloud_CoAPContext_free(Cloud_CoAPContext *p_ctx)
218 {
219     Cloud_CoAPSendNode *cur, *next;
220 
221     if (NULL == p_ctx) {
222         return;
223     }
224 
225     Cloud_CoAPNetwork_deinit(&p_ctx->network);
226 
227     list_for_each_entry_safe(cur, next, &p_ctx->list.sendlist, sendlist,
228                              Cloud_CoAPSendNode)
229     {
230         if (NULL != cur) {
231             if (NULL != cur->message) {
232                 coap_free(cur->message);
233                 cur->message = NULL;
234             }
235             coap_free(cur);
236             cur = NULL;
237         }
238     }
239 
240     if (NULL != p_ctx->recvbuf) {
241         coap_free(p_ctx->recvbuf);
242         p_ctx->recvbuf = NULL;
243     }
244 
245     if (NULL != p_ctx->sendbuf) {
246         coap_free(p_ctx->sendbuf);
247         p_ctx->sendbuf = NULL;
248     }
249 
250     if (NULL != p_ctx) {
251         coap_free(p_ctx);
252         p_ctx = NULL;
253     }
254 }
255