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