1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include "alcs_internal.h"
8 #include "alcs_coap.h"
9 #include "CoAPPlatform.h"
10 #include "CoAPResource.h"
11 #include "alcs_api_internal.h"
12 #include "CoAPServer.h"
13
14 #define MAX_PATH_CHECKSUM_LEN (5)
15 typedef struct {
16 char path[MAX_PATH_CHECKSUM_LEN];
17 CoAPRecvMsgHandler cb;
18 struct list_head lst;
19 } resource_cb_item;
20
21 LIST_HEAD(resource_cb_head);
22
23 static uint32_t tokenSeed = 0;
getToken()24 uint32_t getToken()
25 {
26 if (tokenSeed == 0) {
27 HAL_Srandom((uint32_t)HAL_UptimeMs());
28 tokenSeed = HAL_Random(0xffffffff);
29 } else {
30 ++tokenSeed;
31 }
32
33 return tokenSeed;
34 }
35
alcs_msg_init(CoAPContext * ctx,CoAPMessage * message,int code,unsigned char type,int keep,CoAPLenString * payload,void * userdata)36 void alcs_msg_init(CoAPContext *ctx, CoAPMessage *message, int code,
37 unsigned char type, int keep, CoAPLenString *payload,
38 void *userdata)
39 {
40 uint32_t token = 0;
41
42 CoAPMessage_init(message);
43 message->header.code = code;
44 message->header.type = type;
45 message->user = userdata;
46 message->payload = payload->data;
47 message->payloadlen = payload->len;
48 message->keep = keep;
49
50 message->header.msgid = CoAPMessageId_gen(ctx);
51 message->header.tokenlen = 4;
52 token = getToken();
53 memcpy(&message->token, &token, 4);
54 }
55
alcs_msg_deinit(CoAPMessage * message)56 void alcs_msg_deinit(CoAPMessage *message)
57 {
58 CoAPMessage_destory(message);
59 }
60
do_sendmsg(CoAPContext * context,NetworkAddr * addr,CoAPMessage * message,char observe,unsigned short msgid,CoAPLenString * token)61 static int do_sendmsg(CoAPContext *context, NetworkAddr *addr,
62 CoAPMessage *message, char observe, unsigned short msgid,
63 CoAPLenString *token)
64 {
65 int ret = COAP_SUCCESS;
66 if (!context || !addr || !message) {
67 return COAP_ERROR_NULL;
68 }
69
70 if (msgid == 0) {
71 message->header.msgid = CoAPMessageId_gen(context);
72 } else {
73 message->header.msgid = msgid;
74 }
75
76 if (observe == 0) {
77 CoAPUintOption_add(message, COAP_OPTION_OBSERVE, observe);
78 }
79
80 if (token) {
81 message->header.tokenlen = token->len;
82 memcpy(&message->token, token->data, token->len);
83 }
84
85 ret = CoAPMessage_send(context, addr, message);
86 CoAPMessage_destory(message);
87 return ret;
88 }
89
alcs_sendmsg(CoAPContext * context,NetworkAddr * addr,CoAPMessage * message,char observe,CoAPSendMsgHandler handler)90 int alcs_sendmsg(CoAPContext *context, NetworkAddr *addr, CoAPMessage *message,
91 char observe, CoAPSendMsgHandler handler)
92 {
93 message->handler = handler;
94 return do_sendmsg(context, addr, message, observe, message->header.msgid,
95 NULL);
96 }
97
alcs_sendrsp(CoAPContext * context,NetworkAddr * addr,CoAPMessage * message,char observe,unsigned short msgid,CoAPLenString * token)98 int alcs_sendrsp(CoAPContext *context, NetworkAddr *addr, CoAPMessage *message,
99 char observe, unsigned short msgid, CoAPLenString *token)
100 {
101 return do_sendmsg(context, addr, message, observe, msgid, token);
102 }
103
104 /* observe */
alcs_observe_notify(CoAPContext * context,const char * path,CoAPLenString * payload)105 int alcs_observe_notify(CoAPContext *context, const char *path,
106 CoAPLenString *payload)
107 {
108 int needAuth = 0;
109 #ifdef USE_ALCS_SECURE
110 needAuth = alcs_resource_need_auth(context, path);
111 #endif
112 COAP_DEBUG("payload:%s", payload->data);
113 /* HEXDUMP_DEBUG(payload->data, payload->len); */
114 return CoAPObsServer_notify(context, path, payload->data, payload->len,
115 needAuth ? &observe_data_encrypt : NULL);
116 }
117
send_err_rsp(CoAPContext * ctx,NetworkAddr * addr,int code,CoAPMessage * fromMsg)118 static void send_err_rsp(CoAPContext *ctx, NetworkAddr *addr, int code,
119 CoAPMessage *fromMsg)
120 {
121 CoAPMessage sendMsg;
122 CoAPLenString payload = { 0 };
123 CoAPLenString token = { fromMsg->header.tokenlen, fromMsg->token };
124
125 alcs_msg_init(ctx, &sendMsg, code, COAP_MESSAGE_TYPE_ACK, 0, &payload,
126 NULL);
127 alcs_sendrsp(ctx, addr, &sendMsg, 1, fromMsg->header.msgid, &token);
128 }
129
recv_msg_handler(CoAPContext * context,const char * path,NetworkAddr * remote,CoAPMessage * message)130 static void recv_msg_handler(CoAPContext *context, const char *path,
131 NetworkAddr *remote, CoAPMessage *message)
132 {
133 unsigned int obsVal;
134 resource_cb_item *node = NULL, *next = NULL;
135 char path_calc[MAX_PATH_CHECKSUM_LEN] = { 0 };
136 CoAPPathMD5_sum(path, strlen(path), path_calc, MAX_PATH_CHECKSUM_LEN);
137
138 list_for_each_entry_safe(node, next, &resource_cb_head, lst,
139 resource_cb_item)
140 {
141 if (0 == memcmp(path_calc, node->path, MAX_PATH_CHECKSUM_LEN)) {
142 if (CoAPUintOption_get(message, COAP_OPTION_OBSERVE, &obsVal) ==
143 COAP_SUCCESS) {
144 if (obsVal == 0) {
145 CoAPObsServer_add(context, path, remote, message);
146 }
147 }
148 COAP_INFO("recv_msg_handler call callback");
149 node->cb(context, path, remote, message);
150 return;
151 }
152 }
153
154 COAP_ERR("receive unknown request, path:%s", path);
155 send_err_rsp(context, remote, COAP_MSG_CODE_401_UNAUTHORIZED, message);
156 }
157
158 /* resource */
alcs_resource_register(CoAPContext * context,const char * pk,const char * dn,const char * path,unsigned short permission,unsigned int ctype,unsigned int maxage,char needAuth,CoAPRecvMsgHandler callback)159 int alcs_resource_register(CoAPContext *context, const char *pk, const char *dn,
160 const char *path, unsigned short permission,
161 unsigned int ctype, unsigned int maxage,
162 char needAuth, CoAPRecvMsgHandler callback)
163 {
164 COAP_DEBUG("alcs_resource_register, ctx:%p", context);
165 COAP_DEBUG("ALCS Resource Register: %s", path);
166
167 if (!needAuth) {
168 resource_cb_item *item =
169 (resource_cb_item *)coap_malloc(sizeof(resource_cb_item));
170 CoAPPathMD5_sum(path, strlen(path), item->path, MAX_PATH_CHECKSUM_LEN);
171 item->cb = callback;
172 list_add_tail(&item->lst, &resource_cb_head);
173
174 return CoAPResource_register(context, path, permission, ctype, maxage,
175 &recv_msg_handler);
176 } else {
177 #ifdef USE_ALCS_SECURE
178 return alcs_resource_register_secure(context, pk, dn, path, permission,
179 ctype, maxage, callback);
180 #else
181 return -1;
182 #endif
183 }
184 }
185
alcs_resource_need_auth(CoAPContext * context,const char * path)186 int alcs_resource_need_auth(CoAPContext *context, const char *path)
187 {
188 resource_cb_item *node = NULL, *next = NULL;
189 char path_calc[MAX_PATH_CHECKSUM_LEN] = { 0 };
190 CoAPPathMD5_sum(path, strlen(path), path_calc, MAX_PATH_CHECKSUM_LEN);
191
192 list_for_each_entry_safe(node, next, &resource_cb_head, lst,
193 resource_cb_item)
194 {
195 if (memcmp(path_calc, node->path, MAX_PATH_CHECKSUM_LEN) == 0) {
196 return 0;
197 }
198 }
199
200 return 1;
201 }
202
203 typedef struct {
204 CoAPContext *ctx;
205 char loop;
206 bool inited;
207 struct list_head lst;
208 } ALCSContext;
209
210 #ifdef SUPPORT_MULTI_DEVICES
211 LIST_HEAD(context_head);
212
get_context(CoAPContext * ctx)213 ALCSContext *get_context(CoAPContext *ctx)
214 {
215 ALCSContext *node = NULL, *next = NULL;
216
217 list_for_each_entry_safe(node, next, &context_head, lst, ALCSContext)
218 {
219 if (node->ctx == ctx) {
220 return node;
221 }
222 }
223 return NULL;
224 }
225
alcs_context_create(CoAPInitParam * param)226 CoAPContext *alcs_context_create(CoAPInitParam *param)
227 {
228 ALCSContext *alcs_ctx = (ALCSContext *)coap_malloc(sizeof(ALCSContext));
229 alcs_ctx->ctx = CoAPContext_create(param);
230 COAP_INFO("CoAPContext_create return :%p", alcs_ctx->ctx);
231 alcs_ctx->loop = 0;
232 alcs_ctx->inited = 0;
233
234 list_add_tail(&alcs_ctx->lst, &context_head);
235 return alcs_ctx->ctx;
236 }
237
alcs_context_free(CoAPContext * ctx)238 void alcs_context_free(CoAPContext *ctx)
239 {
240 ALCSContext *alcs_ctx = get_context(ctx);
241 if (alcs_ctx) {
242 CoAPContext_free(alcs_ctx->ctx);
243 coap_free(alcs_ctx);
244 }
245 }
246
247 #else
248 ALCSContext *g_alcs_ctx = NULL;
get_context(CoAPContext * ctx)249 ALCSContext *get_context(CoAPContext *ctx)
250 {
251 return g_alcs_ctx;
252 }
253
alcs_context_init(CoAPInitParam * param)254 CoAPContext *alcs_context_init(CoAPInitParam *param)
255 {
256 if (g_alcs_ctx) {
257 return g_alcs_ctx->ctx;
258 }
259
260 g_alcs_ctx = (ALCSContext *)coap_malloc(sizeof(ALCSContext));
261 if (g_alcs_ctx) {
262 g_alcs_ctx->loop = 0;
263 g_alcs_ctx->inited = 0;
264 g_alcs_ctx->ctx = CoAPServer_init();
265 COAP_INFO("CoAPServer_init return :%p", g_alcs_ctx->ctx);
266 if (!g_alcs_ctx->ctx) {
267 coap_free(g_alcs_ctx);
268 g_alcs_ctx = NULL;
269 return NULL;
270 }
271 return g_alcs_ctx->ctx;
272 } else {
273 return NULL;
274 }
275 }
276
alcs_context_deinit()277 void alcs_context_deinit()
278 {
279 if (g_alcs_ctx) {
280 if (g_alcs_ctx->ctx) {
281 CoAPServer_deinit(g_alcs_ctx->ctx);
282 }
283 coap_free(g_alcs_ctx);
284 g_alcs_ctx = NULL;
285 }
286 }
287
alcs_get_context()288 CoAPContext *alcs_get_context()
289 {
290 return g_alcs_ctx ? g_alcs_ctx->ctx : NULL;
291 }
292
293 #endif
294
295 extern void on_auth_timer(void *arg);
296
thread_routine(void * arg)297 void *thread_routine(void *arg)
298 {
299 ALCSContext *ctx = (ALCSContext *)arg;
300 ctx->loop = 1;
301
302 COAP_INFO("thread_routine");
303
304 while (ctx->loop) {
305 CoAPMessage_cycle(ctx->ctx);
306 #ifdef USE_ALCS_SECURE
307 on_auth_timer(ctx->ctx);
308 #endif
309 }
310
311 return NULL;
312 }
313
alcs_start_loop(CoAPContext * ctx,int newThread)314 void alcs_start_loop(CoAPContext *ctx, int newThread)
315 {
316 #ifdef SUPPORT_MULTI_DEVICES
317 void *handle = NULL;
318 ALCSContext *alcs_ctx = get_context(ctx);
319 if (alcs_ctx && !alcs_ctx->loop) {
320 int stack_used = 0;
321 if (!newThread || 0 != HAL_ThreadCreate(&handle, thread_routine,
322 alcs_ctx, NULL, &stack_used)) {
323 thread_routine(alcs_ctx);
324 }
325 }
326 #else
327
328 #ifdef USE_ALCS_SECURE
329 CoAPServer_add_timer(on_auth_timer);
330 #endif
331 CoAPServer_loop(ctx);
332 #endif
333 }
334
alcs_stop_loop(CoAPContext * ctx)335 void alcs_stop_loop(CoAPContext *ctx)
336 {
337 #ifdef SUPPORT_MULTI_DEVICES
338 ALCSContext *alcs_ctx = get_context(ctx);
339 if (alcs_ctx) {
340 alcs_ctx->loop = 0;
341 }
342 #else
343 CoAPServer_deinit(ctx);
344 #endif
345 }
346
alcs_init()347 void alcs_init()
348 {
349 #ifdef SUPPORT_MULTI_DEVICES
350 INIT_LIST_HEAD(&context_head);
351 #endif
352 INIT_LIST_HEAD(&resource_cb_head);
353 }
354
alcs_deinit()355 void alcs_deinit()
356 {
357 resource_cb_item *del_item = NULL;
358
359 list_for_each_entry(del_item, &resource_cb_head, lst, resource_cb_item)
360 {
361 list_del(&del_item->lst);
362 coap_free(del_item);
363 del_item = list_entry(&resource_cb_head, resource_cb_item, lst);
364 }
365 }
366
path_2_option(const char * uri,CoAPMessage * message)367 static int path_2_option(const char *uri, CoAPMessage *message)
368 {
369 const char *ptr = NULL;
370 const char *pstr = NULL;
371 char path[COAP_MSG_MAX_PATH_LEN] = { 0 };
372
373 if (256 < strlen(uri)) {
374 COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri));
375 return COAP_ERROR_INVALID_LENGTH;
376 }
377 COAP_DEBUG("The uri is %s", uri);
378 ptr = pstr = uri;
379 while ('\0' != *ptr) {
380 if ('/' == *ptr) {
381 if (ptr != pstr) {
382 memset(path, 0x00, sizeof(path));
383 strncpy(path, pstr, ptr - pstr);
384 COAP_DEBUG("path: %s,len=%d", path, (int)(ptr - pstr));
385 CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
386 (unsigned char *)path, (int)strlen(path));
387 }
388 pstr = ptr + 1;
389 }
390 if ('\0' == *(ptr + 1) && '\0' != *pstr) {
391 memset(path, 0x00, sizeof(path));
392 strncpy(path, pstr, sizeof(path) - 1);
393 COAP_DEBUG("path: %s,len=%d", path, (int)strlen(path));
394 CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
395 (unsigned char *)path, (int)strlen(path));
396 }
397 ptr++;
398 }
399 return COAP_SUCCESS;
400 }
401
alcs_msg_setAddr(CoAPMessage * message,const char * path,const char * query)402 int alcs_msg_setAddr(CoAPMessage *message, const char *path, const char *query)
403 {
404 int rt = 0;
405
406 if (NULL == path || NULL == message) {
407 COAP_ERR("Invalid paramter p_path %p, p_message %p", path, message);
408 return COAP_ERROR_INVALID_PARAM;
409 }
410
411 if (255 < strlen(path)) {
412 COAP_ERR("The uri length is too loog,len = %d", (int)strlen(path));
413 return COAP_ERROR_INVALID_LENGTH;
414 }
415
416 rt = path_2_option(path, message);
417 if (query) {
418 CoAPStrOption_add(message, COAP_OPTION_URI_QUERY,
419 (unsigned char *)query, strlen(query));
420 }
421
422 return rt;
423 }
424