1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 
6 
7 
8 #include <string.h>
9 #include "CoAPExport.h"
10 #include "CoAPResource.h"
11 #include "CoAPPlatform.h"
12 #include "CoAPInternal.h"
13 #include "iotx_coap_internal.h"
14 
15 #define COAP_PATH_DEFAULT_SUM_LEN (5)
16 
CoAPPathMD5_sum(const char * path,int len,char outbuf[],int outlen)17 int CoAPPathMD5_sum(const char *path, int len, char outbuf[], int outlen)
18 {
19     unsigned char md5[16] = { 0 };
20     if (!path || !len || !outbuf || !outlen) {
21         return -1;
22     }
23 
24     utils_md5((unsigned char *)path, (size_t)len, md5);
25     memcpy(outbuf, md5, outlen > 16 ? 16 : outlen);
26     return 0;
27 }
28 
CoAPResource_init(CoAPContext * context,int res_maxcount)29 int CoAPResource_init(CoAPContext *context, int res_maxcount)
30 {
31     CoAPIntContext *ctx = (CoAPIntContext *)context;
32 
33     ctx->resource.list_mutex = HAL_MutexCreate();
34 
35     HAL_MutexLock(ctx->resource.list_mutex);
36     INIT_LIST_HEAD(&ctx->resource.list);
37     ctx->resource.count = 0;
38     ctx->resource.maxcount = res_maxcount;
39     HAL_MutexUnlock(ctx->resource.list_mutex);
40 
41     return COAP_SUCCESS;
42 }
43 
CoAPResource_deinit(CoAPContext * context)44 int CoAPResource_deinit(CoAPContext *context)
45 {
46     CoAPResource *node = NULL, *next = NULL;
47     CoAPIntContext *ctx = (CoAPIntContext *)context;
48     char tmpbuf[2 * COAP_MAX_PATH_CHECKSUM_LEN + 1] = { 0 };
49 
50     HAL_MutexLock(ctx->resource.list_mutex);
51     list_for_each_entry_safe(node, next, &ctx->resource.list, reslist,
52                              CoAPResource)
53     {
54         if (node->path_type == PATH_FILTER && node->filter_path) {
55             coap_free(node->filter_path);
56         }
57         list_del_init(&node->reslist);
58         infra_hex2str((unsigned char *)node->path, COAP_MAX_PATH_CHECKSUM_LEN,
59                       tmpbuf);
60         COAP_DEBUG("Release the resource %s", tmpbuf);
61         coap_free(node);
62     }
63     ctx->resource.count = 0;
64     ctx->resource.maxcount = 0;
65     HAL_MutexUnlock(ctx->resource.list_mutex);
66 
67     HAL_MutexDestroy(ctx->resource.list_mutex);
68     ctx->resource.list_mutex = NULL;
69     return COAP_SUCCESS;
70 }
71 
CoAPResource_create(const char * path,path_type_t path_type,unsigned short permission,unsigned int ctype,unsigned int maxage,CoAPRecvMsgHandler callback)72 CoAPResource *CoAPResource_create(const char *path, path_type_t path_type,
73                                   unsigned short permission, unsigned int ctype,
74                                   unsigned int maxage,
75                                   CoAPRecvMsgHandler callback)
76 {
77     CoAPResource *resource = NULL;
78 
79     if (NULL == path) {
80         return NULL;
81     }
82 
83     if (strlen(path) >= COAP_MSG_MAX_PATH_LEN) {
84         return NULL;
85     }
86 
87     resource = coap_malloc(sizeof(CoAPResource));
88     if (NULL == resource) {
89         return NULL;
90     }
91 
92     memset(resource, 0x00, sizeof(CoAPResource));
93     if (path_type == PATH_NORMAL) {
94         resource->path_type = PATH_NORMAL;
95         CoAPPathMD5_sum(path, strlen(path), resource->path,
96                         COAP_PATH_DEFAULT_SUM_LEN);
97     } else {
98         int len = strlen(path) + 1;
99         resource->filter_path = coap_malloc(len);
100         if (NULL == resource->filter_path) {
101             coap_free(resource);
102             return NULL;
103         }
104         resource->path_type = PATH_FILTER;
105         memset(resource->filter_path, 0, len);
106         strncpy(resource->filter_path, path, strlen(path));
107     }
108     resource->callback = callback;
109     resource->ctype = ctype;
110     resource->maxage = maxage;
111     resource->permission = permission;
112 
113     return resource;
114 }
115 
CoAPResource_register(CoAPContext * context,const char * path,unsigned short permission,unsigned int ctype,unsigned int maxage,CoAPRecvMsgHandler callback)116 int CoAPResource_register(CoAPContext *context, const char *path,
117                           unsigned short permission, unsigned int ctype,
118                           unsigned int maxage, CoAPRecvMsgHandler callback)
119 {
120     int exist = 0;
121     char path_calc[COAP_PATH_DEFAULT_SUM_LEN] = { 0 };
122     CoAPResource *node = NULL, *newnode = NULL;
123     CoAPIntContext *ctx = (CoAPIntContext *)context;
124     path_type_t type = PATH_NORMAL;
125 
126     if (context == NULL) {
127         return FAIL_RETURN;
128     }
129 
130     HAL_MutexLock(ctx->resource.list_mutex);
131     if (ctx->resource.count >= ctx->resource.maxcount) {
132         HAL_MutexUnlock(ctx->resource.list_mutex);
133         COAP_INFO("The resource count exceeds limit, cur %d, max %d",
134                   ctx->resource.count, ctx->resource.maxcount);
135         return COAP_ERROR_DATA_SIZE;
136     }
137 
138     if (strstr(path, "/#") != NULL) {
139         type = PATH_FILTER;
140     } else {
141         CoAPPathMD5_sum(path, strlen(path), path_calc,
142                         COAP_PATH_DEFAULT_SUM_LEN);
143     }
144 
145     list_for_each_entry(node, &ctx->resource.list, reslist, CoAPResource)
146     {
147         if (type == PATH_NORMAL && node->path_type == PATH_NORMAL) {
148             if (0 == memcmp(path_calc, node->path, COAP_PATH_DEFAULT_SUM_LEN)) {
149                 /*Alread exist, re-write it*/
150                 COAP_INFO("CoAPResource_register:Alread exist");
151                 exist = 1;
152                 node->callback = callback;
153                 node->ctype = ctype;
154                 node->maxage = maxage;
155                 node->permission = permission;
156                 COAP_INFO("The resource %s already exist, re-write it", path);
157                 break;
158             }
159         } else if (type == PATH_FILTER && node->path_type == PATH_FILTER) {
160             if (0 == strncmp((char *)path, node->filter_path, strlen(path))) {
161                 /*Alread exist, re-write it*/
162                 COAP_INFO("CoAPResource_register:Alread exist");
163                 exist = 1;
164                 node->callback = callback;
165                 node->ctype = ctype;
166                 node->maxage = maxage;
167                 node->permission = permission;
168                 COAP_INFO("The resource %s already exist, re-write it", path);
169                 break;
170             }
171         }
172     }
173 
174     if (0 == exist) {
175         newnode = CoAPResource_create(path, type, permission, ctype, maxage,
176                                       callback);
177         if (NULL != newnode) {
178             COAP_DEBUG("CoAPResource_register, context:%p, new node", ctx);
179             list_add_tail(&newnode->reslist, &ctx->resource.list);
180             ctx->resource.count++;
181             COAP_DEBUG("Register new resource %s success, count: %d", path,
182                        ctx->resource.count);
183         } else {
184             COAP_ERR("New resource create failed");
185         }
186     }
187 
188     HAL_MutexUnlock(ctx->resource.list_mutex);
189 
190     return COAP_SUCCESS;
191 }
192 
CoAPResource_unregister(CoAPContext * context,const char * path)193 int CoAPResource_unregister(CoAPContext *context, const char *path)
194 {
195     COAP_DEBUG("This feature isn't supported");
196     return COAP_ERROR_UNSUPPORTED;
197 }
198 
CoAPResource_topicFilterMatch(const char * filter,const char * topic)199 int CoAPResource_topicFilterMatch(const char *filter, const char *topic)
200 {
201     if (filter == NULL || topic == NULL) {
202         return -1;
203     }
204     if (strncmp(filter, topic, strlen(filter) - 1) == 0) {
205         if (strlen(topic) > strlen(filter) - 1) {
206             const char *more = topic + (strlen(filter) - 1);
207             if (strstr(more, "/") == NULL) {
208                 return 0;
209             }
210         }
211     }
212     return -1;
213 }
214 
CoAPResourceByPath_get(CoAPContext * context,const char * path)215 CoAPResource *CoAPResourceByPath_get(CoAPContext *context, const char *path)
216 {
217     char path_calc[COAP_PATH_DEFAULT_SUM_LEN] = { 0 };
218     CoAPResource *node = NULL;
219     CoAPIntContext *ctx = (CoAPIntContext *)context;
220 
221     if (NULL == context || NULL == path) {
222         COAP_INFO("%s\n", "NULL == context || NULL == path");
223         return NULL;
224     }
225     COAP_FLOW("CoAPResourceByPath_get, context:%p\n", ctx);
226 
227     CoAPPathMD5_sum(path, strlen(path), path_calc, COAP_PATH_DEFAULT_SUM_LEN);
228 
229     HAL_MutexLock(ctx->resource.list_mutex);
230     list_for_each_entry(node, &ctx->resource.list, reslist, CoAPResource)
231     {
232         if (0 == memcmp(path_calc, node->path, COAP_PATH_DEFAULT_SUM_LEN)) {
233             HAL_MutexUnlock(ctx->resource.list_mutex);
234             COAP_DEBUG("Found the resource: %s", path);
235             return node;
236         }
237         if (node->path_type == PATH_FILTER && strlen(node->filter_path) > 0) {
238             if (CoAPResource_topicFilterMatch(node->filter_path, path) == 0) {
239                 HAL_MutexUnlock(ctx->resource.list_mutex);
240                 COAP_DEBUG("Found the resource: %s", path);
241                 return node;
242             }
243         }
244     }
245     HAL_MutexUnlock(ctx->resource.list_mutex);
246 
247     return NULL;
248 }
249