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