1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include "CoAPExport.h"
6 #include "CoAPResource.h"
7 #include "CoAPObserve.h"
8 #include "CoAPMessage.h"
9 #include "iotx_coap_internal.h"
10 #include "CoAPPlatform.h"
11 #include "CoAPInternal.h"
12 
13 #ifndef COAP_OBSERVE_SERVER_DISABLE
CoAPObsServer_init(CoAPContext * context,unsigned char obs_maxcount)14 int CoAPObsServer_init(CoAPContext *context, unsigned char obs_maxcount)
15 {
16     CoAPIntContext *ctx = (CoAPIntContext *)context;
17 
18     ctx->obsserver.list_mutex = HAL_MutexCreate();
19 
20     HAL_MutexLock(ctx->obsserver.list_mutex);
21     INIT_LIST_HEAD(&ctx->obsserver.list);
22     ctx->obsserver.count = 0;
23     ctx->obsserver.maxcount = obs_maxcount;
24     HAL_MutexUnlock(ctx->obsserver.list_mutex);
25 
26     return COAP_SUCCESS;
27 }
28 
CoAPObsServer_deinit(CoAPContext * context)29 int CoAPObsServer_deinit(CoAPContext *context)
30 {
31     CoAPIntContext *ctx = (CoAPIntContext *)context;
32     CoapObserver *node = NULL, *next = NULL;
33 
34     HAL_MutexLock(ctx->obsserver.list_mutex);
35     list_for_each_entry_safe(node, next, &ctx->obsserver.list, obslist,
36                              CoapObserver)
37     {
38         list_del(&node->obslist);
39         COAP_DEBUG("Delete %s:%d from observe server", node->remote.addr,
40                    node->remote.port);
41         coap_free(node);
42     }
43     ctx->obsserver.count = 0;
44     ctx->obsserver.maxcount = 0;
45     HAL_MutexUnlock(ctx->obsserver.list_mutex);
46 
47     HAL_MutexDestroy(ctx->obsserver.list_mutex);
48     ctx->obsserver.list_mutex = NULL;
49 
50     return COAP_SUCCESS;
51 }
52 
CoAPObsServer_add(CoAPContext * context,const char * path,NetworkAddr * remote,CoAPMessage * request)53 int CoAPObsServer_add(CoAPContext *context, const char *path,
54                       NetworkAddr *remote, CoAPMessage *request)
55 {
56     int ret = COAP_SUCCESS;
57     unsigned int observe;
58     unsigned int acceptype = 0;
59     CoapObserver *obs = NULL;
60     CoAPResource *resource = NULL;
61     CoapObserver *node = NULL;
62     CoAPIntContext *ctx = (CoAPIntContext *)context;
63 
64     resource = CoAPResourceByPath_get(ctx, path);
65 
66     ret = CoAPUintOption_get(request, COAP_OPTION_OBSERVE, &observe);
67 
68     if (NULL != resource && COAP_SUCCESS == ret && 0 == observe) {
69         /*Check if the observe client already exist*/
70         HAL_MutexLock(ctx->obsserver.list_mutex);
71         list_for_each_entry(node, &ctx->obsserver.list, obslist, CoapObserver)
72         {
73             if ((node->p_resource_of_interest == resource) &&
74                 (node->remote.port == remote->port) &&
75                 (0 ==
76                  memcmp(node->remote.addr, remote->addr, NETWORK_ADDR_LEN))) {
77                 COAP_DEBUG("The observe client %s:%d already exist,update it",
78                            node->remote.addr, node->remote.port);
79                 memcpy(node->token, request->token, request->header.tokenlen);
80                 node->tokenlen = request->header.tokenlen;
81                 HAL_MutexUnlock(ctx->obsserver.list_mutex);
82                 return COAP_ERROR_OBJ_ALREADY_EXIST;
83             }
84         }
85         HAL_MutexUnlock(ctx->obsserver.list_mutex);
86 
87         obs = coap_malloc(sizeof(CoapObserver));
88         if (NULL == obs) {
89             COAP_ERR("Allocate memory failed");
90             return COAP_ERROR_MALLOC;
91         }
92 
93         memset(obs, 0x00, sizeof(CoapObserver));
94         obs->msg_type = request->header.type;
95         obs->p_resource_of_interest = resource;
96         memcpy(&obs->remote, remote, sizeof(NetworkAddr));
97         memcpy(obs->token, request->token, request->header.tokenlen);
98         obs->tokenlen = request->header.tokenlen;
99 
100         CoAPUintOption_get(request, COAP_OPTION_ACCEPT, &acceptype);
101         obs->ctype = (acceptype == 0) ? COAP_CT_APP_JSON : acceptype;
102         obs->observer_sequence_num = 0;
103 
104         /* TODO: */
105         /* CoAPObsServer_find(); */
106 
107         HAL_MutexLock(ctx->obsserver.list_mutex);
108         if (ctx->obsserver.count >= ctx->obsserver.maxcount) {
109             HAL_MutexUnlock(ctx->obsserver.list_mutex);
110             coap_free(obs);
111             COAP_INFO("Cur have %d observer, max allow %d",
112                       ctx->obsserver.count, ctx->obsserver.maxcount);
113             return COAP_ERROR_DATA_SIZE;
114         } else {
115             list_add_tail(&obs->obslist, &ctx->obsserver.list);
116             ctx->obsserver.count++;
117             COAP_DEBUG("Create a observe node, cur have %d nodes",
118                        ctx->obsserver.count);
119             HAL_MutexUnlock(ctx->obsserver.list_mutex);
120             return COAP_SUCCESS;
121         }
122     }
123 
124     return COAP_ERROR_NOT_FOUND;
125 }
126 
CoapObsServer_delete(CoAPContext * context,NetworkAddr * remote,CoAPResource * resource)127 int CoapObsServer_delete(CoAPContext *context, NetworkAddr *remote,
128                          CoAPResource *resource)
129 {
130     CoapObserver *node = NULL, *next = NULL;
131     CoAPIntContext *ctx = (CoAPIntContext *)context;
132 
133     HAL_MutexLock(ctx->obsserver.list_mutex);
134     list_for_each_entry_safe(node, next, &ctx->obsserver.list, obslist,
135                              CoapObserver)
136     {
137         if ((node->p_resource_of_interest == resource) &&
138             (node->remote.port == remote->port) &&
139             (0 == memcmp(node->remote.addr, remote->addr, NETWORK_ADDR_LEN))) {
140             ctx->obsserver.count--;
141             list_del(&node->obslist);
142             COAP_DEBUG("Delete %s:%d from observe server", node->remote.addr,
143                        node->remote.port);
144             coap_free(node);
145             break;
146         }
147     }
148     HAL_MutexUnlock(ctx->obsserver.list_mutex);
149 
150     return COAP_SUCCESS;
151 }
152 
CoapObsServerAll_delete(CoAPContext * context,NetworkAddr * remote)153 int CoapObsServerAll_delete(CoAPContext *context, NetworkAddr *remote)
154 {
155     CoapObserver *node = NULL, *next = NULL;
156     CoAPIntContext *ctx = (CoAPIntContext *)context;
157 
158     HAL_MutexLock(ctx->obsserver.list_mutex);
159     list_for_each_entry_safe(node, next, &ctx->obsserver.list, obslist,
160                              CoapObserver)
161     {
162         if (NULL != node && (node->remote.port == remote->port) &&
163             (0 == memcmp(node->remote.addr, remote->addr, NETWORK_ADDR_LEN))) {
164             ctx->obsserver.count--;
165             list_del(&node->obslist);
166             COAP_DEBUG("Delete %s:%d from observe server, cur observe count %d",
167                        node->remote.addr, node->remote.port,
168                        ctx->obsserver.count);
169             coap_free(node);
170         }
171     }
172     HAL_MutexUnlock(ctx->obsserver.list_mutex);
173 
174     return COAP_SUCCESS;
175 }
176 
CoAPObsServer_notify(CoAPContext * context,const char * path,unsigned char * payload,unsigned short payloadlen,CoAPDataEncrypt handler)177 int CoAPObsServer_notify(CoAPContext *context, const char *path,
178                          unsigned char *payload, unsigned short payloadlen,
179                          CoAPDataEncrypt handler)
180 {
181     unsigned int ret = COAP_SUCCESS;
182     CoAPResource *resource = NULL;
183     CoapObserver *node = NULL;
184     CoAPLenString src;
185     CoAPLenString dest;
186     CoAPIntContext *ctx = (CoAPIntContext *)context;
187 
188     resource = CoAPResourceByPath_get(ctx, path);
189 
190     if (NULL != resource) {
191         HAL_MutexLock(ctx->obsserver.list_mutex);
192         list_for_each_entry(node, &ctx->obsserver.list, obslist, CoapObserver)
193         {
194             if (node->p_resource_of_interest == resource) {
195                 CoAPMessage message;
196                 CoAPMessage_init(&message);
197                 CoAPMessageType_set(&message, node->msg_type);
198                 CoAPMessageCode_set(&message, COAP_MSG_CODE_205_CONTENT);
199                 CoAPMessageId_set(&message, CoAPMessageId_gen(ctx));
200                 CoAPMessageHandler_set(&message, NULL);
201                 CoAPMessageUserData_set(&message, node->p_resource_of_interest);
202                 CoAPMessageToken_set(&message, node->token, node->tokenlen);
203                 CoAPUintOption_add(&message, COAP_OPTION_OBSERVE,
204                                    node->observer_sequence_num++);
205                 CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT,
206                                    node->ctype);
207                 CoAPUintOption_add(&message, COAP_OPTION_MAXAGE,
208                                    resource->maxage);
209                 COAP_DEBUG("Send notify message path %s to remote %s:%d ", path,
210                            node->remote.addr, node->remote.port);
211 
212                 memset(&dest, 0x00, sizeof(CoAPLenString));
213                 if (NULL != handler) {
214                     src.len = payloadlen;
215                     src.data = payload;
216                     ret = handler(context, path, &node->remote, &message, &src,
217                                   &dest);
218                     if (COAP_SUCCESS == ret) {
219                         CoAPMessagePayload_set(&message, dest.data, dest.len);
220                     } else {
221                         COAP_INFO("Encrypt payload failed");
222                     }
223                 } else {
224                     CoAPMessagePayload_set(&message, payload, payloadlen);
225                 }
226                 ret = CoAPMessage_send(ctx, &node->remote, &message);
227                 if (NULL != handler && 0 != dest.len && NULL != dest.data) {
228                     coap_free(dest.data);
229                     dest.len = 0;
230                 }
231                 CoAPMessage_destory(&message);
232             }
233         }
234 
235         HAL_MutexUnlock(ctx->obsserver.list_mutex);
236     }
237     return ret;
238 }
239 
240 #endif
241 
242 #ifndef COAP_OBSERVE_CLIENT_DISABLE
CoAPObsClient_init(CoAPContext * context,unsigned char obs_maxcount)243 int CoAPObsClient_init(CoAPContext *context, unsigned char obs_maxcount)
244 {
245     CoAPIntContext *ctx = (CoAPIntContext *)context;
246 
247     ctx->obsclient.list_mutex = HAL_MutexCreate();
248 
249     HAL_MutexLock(ctx->obsclient.list_mutex);
250     INIT_LIST_HEAD(&ctx->obsclient.list);
251     ctx->obsclient.count = 0;
252     ctx->obsclient.maxcount = obs_maxcount;
253     HAL_MutexUnlock(ctx->obsclient.list_mutex);
254 
255     return COAP_SUCCESS;
256 }
257 
CoAPObsClient_deinit(CoAPContext * context)258 int CoAPObsClient_deinit(CoAPContext *context)
259 {
260     CoAPObservable *node = NULL, *next = NULL;
261     CoAPIntContext *ctx = (CoAPIntContext *)context;
262 
263     HAL_MutexLock(ctx->obsclient.list_mutex);
264     list_for_each_entry_safe(node, next, &ctx->obsclient.list, obslist,
265                              CoAPObservable)
266     {
267         list_del(&node->obslist);
268         coap_free(node);
269     }
270     ctx->obsclient.count = 0;
271     ctx->obsclient.maxcount = 0;
272     HAL_MutexUnlock(ctx->obsclient.list_mutex);
273 
274     HAL_MutexDestroy(ctx->obsclient.list_mutex);
275     ctx->obsclient.list_mutex = NULL;
276     return COAP_SUCCESS;
277 }
278 
CoAPObsClient_add(CoAPContext * context,CoAPMessage * message,NetworkAddr * remote,CoAPSendNode * sendnode)279 int CoAPObsClient_add(CoAPContext *context, CoAPMessage *message,
280                       NetworkAddr *remote, CoAPSendNode *sendnode)
281 {
282     CoAPObservable *node = NULL, *next = NULL;
283     CoAPIntContext *ctx = (CoAPIntContext *)context;
284 
285     if (COAP_SUCCESS == CoAPOption_present(message, COAP_OPTION_OBSERVE)) {
286         COAP_DEBUG("There is Observe option in message, handle it");
287         if (NULL == sendnode) { /* Not the first response */
288 
289             HAL_MutexLock(ctx->obsclient.list_mutex);
290             list_for_each_entry(node, &ctx->obsclient.list, obslist,
291                                 CoAPObservable)
292             {
293                 if (0 != node->tokenlen &&
294                     node->tokenlen == message->header.tokenlen &&
295                     0 == memcmp(node->token, message->token, node->tokenlen)) {
296                     CoAPUintOption_get(message, COAP_OPTION_MAXAGE,
297                                        &node->max_age);
298                     if (NULL != node->callback) {
299                         COAP_DEBUG("Call the observe client callback %p",
300                                    node->callback);
301                         node->callback(ctx, COAP_REQUEST_SUCCESS,
302                                        node->userdata, remote, message);
303                     } else {
304                         COAP_INFO("The observe client callback is NULL");
305                     }
306                     break;
307                 }
308             }
309             HAL_MutexUnlock(ctx->obsclient.list_mutex);
310 
311         } else {
312             int found = 0;
313             HAL_MutexLock(ctx->obsclient.list_mutex);
314             list_for_each_entry(node, &ctx->obsclient.list, obslist,
315                                 CoAPObservable)
316             {
317                 if (0 != node->tokenlen &&
318                     node->tokenlen == message->header.tokenlen &&
319                     0 == memcmp(node->token, message->token, node->tokenlen)) {
320                     found = 1;
321                     break;
322                 }
323             }
324             if (!found && ctx->obsclient.count < ctx->obsclient.maxcount) {
325                 CoAPObservable *newnode = coap_malloc(sizeof(CoAPObservable));
326                 if (NULL != newnode) {
327                     memset(newnode, 0x00, sizeof(CoAPObservable));
328                     newnode->tokenlen = message->header.tokenlen;
329                     memcpy(newnode->token, message->token,
330                            message->header.tokenlen);
331                     memcpy(&newnode->remote, remote, sizeof(NetworkAddr));
332                     newnode->callback = sendnode->handler;
333                     newnode->userdata = sendnode->user;
334                     CoAPUintOption_get(message, COAP_OPTION_MAXAGE,
335                                        &newnode->max_age);
336                     list_add_tail(&newnode->obslist, &ctx->obsclient.list);
337                     ctx->obsclient.count++;
338                     COAP_DEBUG("Add a new obsclient");
339                 }
340             } else {
341                 COAP_INFO("Cur have %d obsclient, max allow %d",
342                           ctx->obsclient.count, ctx->obsclient.maxcount);
343             }
344             HAL_MutexUnlock(ctx->obsclient.list_mutex);
345         }
346     } else {
347         HAL_MutexLock(ctx->obsclient.list_mutex);
348         list_for_each_entry_safe(node, next, &ctx->obsclient.list, obslist,
349                                  CoAPObservable)
350         {
351             if (0 != node->tokenlen &&
352                 node->tokenlen == message->header.tokenlen &&
353                 0 == memcmp(node->token, message->token, node->tokenlen)) {
354                 list_del(&node->obslist);
355                 ctx->obsclient.count--;
356                 coap_free(node);
357                 break;
358             }
359         }
360         HAL_MutexUnlock(ctx->obsclient.list_mutex);
361     }
362 
363     return COAP_SUCCESS;
364 }
365 
CoAPObsClient_delete(CoAPContext * context,CoAPMessage * message)366 int CoAPObsClient_delete(CoAPContext *context, CoAPMessage *message)
367 {
368     int ret = COAP_SUCCESS;
369     unsigned int observe_option = 0;
370     CoAPObservable *node = NULL, *next = NULL;
371     CoAPIntContext *ctx = (CoAPIntContext *)context;
372 
373     if (NULL == ctx || NULL == message) {
374         return COAP_ERROR_INVALID_PARAM;
375     }
376     if (COAP_MSG_CODE_GET == message->header.code) {
377         if (COAP_SUCCESS == CoAPOption_present(message, COAP_OPTION_OBSERVE)) {
378             ret = CoAPUintOption_get(message, COAP_OPTION_OBSERVE,
379                                      &observe_option);
380             if (COAP_SUCCESS == ret && 1 == observe_option) {
381                 HAL_MutexLock(ctx->obsclient.list_mutex);
382                 list_for_each_entry_safe(node, next, &ctx->obsclient.list,
383                                          obslist, CoAPObservable)
384                 {
385                     if (0 != node->tokenlen &&
386                         node->tokenlen == message->header.tokenlen &&
387                         0 == memcmp(node->token, message->token,
388                                     node->tokenlen)) {
389                         list_del(&node->obslist);
390                         ctx->obsclient.count--;
391                         coap_free(node);
392                         break;
393                     }
394                 }
395                 HAL_MutexUnlock(ctx->obsclient.list_mutex);
396             }
397         }
398     }
399     return COAP_SUCCESS;
400 }
401 
402 #endif
403