1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 
6 #include <string.h>
7 #include "CoAPPlatform.h"
8 #include "CoAPExport.h"
9 #include "CoAPServer.h"
10 
11 #define COAP_INIT_TOKEN (0x01020304)
12 
13 static unsigned int g_coap_running = 0;
14 #ifdef COAP_SERV_MULTITHREAD
15 static void *g_coap_thread = NULL;
16 static void *g_semphore = NULL;
17 #endif
18 static CoAPContext *g_context = NULL;
19 
CoAPServerToken_get(unsigned char * p_encoded_data)20 static unsigned int CoAPServerToken_get(unsigned char *p_encoded_data)
21 {
22     static unsigned int value = COAP_INIT_TOKEN;
23     p_encoded_data[0] = (unsigned char)((value & 0x00FF) >> 0);
24     p_encoded_data[1] = (unsigned char)((value & 0xFF00) >> 8);
25     p_encoded_data[2] = (unsigned char)((value & 0xFF0000) >> 16);
26     p_encoded_data[3] = (unsigned char)((value & 0xFF000000) >> 24);
27     value++;
28     return sizeof(unsigned int);
29 }
30 
CoAPServerPath_2_option(char * uri,CoAPMessage * message)31 static int CoAPServerPath_2_option(char *uri, CoAPMessage *message)
32 {
33     char *ptr = NULL;
34     char *pstr = NULL;
35     char path[COAP_MSG_MAX_PATH_LEN] = { 0 };
36 
37     if (NULL == uri || NULL == message) {
38         COAP_ERR("Invalid paramter p_path %p, p_message %p", uri, message);
39         return COAP_ERROR_INVALID_PARAM;
40     }
41     if (COAP_MSG_MAX_PATH_LEN <= strlen(uri)) {
42         COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri));
43         return COAP_ERROR_INVALID_LENGTH;
44     }
45 
46     COAP_DEBUG("The uri is %s", uri);
47 
48     ptr = pstr = uri;
49     while ('\0' != *ptr) {
50         if ('/' == *ptr) {
51             if (ptr != pstr) {
52                 memset(path, 0x00, sizeof(path));
53                 strncpy(path, pstr, ptr - pstr);
54                 CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
55                                   (unsigned char *)path, (int)strlen(path));
56             }
57             pstr = ptr + 1;
58         }
59         if ('\0' == *(ptr + 1) && '\0' != *pstr) {
60             memset(path, 0x00, sizeof(path));
61             strncpy(path, pstr, sizeof(path) - 1);
62             CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
63                               (unsigned char *)path, (int)strlen(path));
64         }
65         ptr++;
66     }
67     return COAP_SUCCESS;
68 }
69 
CoAPServer_thread_leave()70 void CoAPServer_thread_leave()
71 {
72     g_coap_running = 0;
73 }
74 
75 void *coap_yield_mutex = NULL;
76 
CoAPServer_yield(void * param)77 static void *CoAPServer_yield(void *param)
78 {
79     CoAPContext *context = (CoAPContext *)param;
80 #ifndef AWSS_DISABLE_REGISTRAR
81     extern int registar_yield();
82 #endif
83     COAP_DEBUG("Enter to CoAP daemon task");
84 
85     while (g_coap_running) {
86         CoAPMessage_cycle(context);
87 #if defined(WIFI_PROVISION_ENABLED) && !defined(AWSS_DISABLE_REGISTRAR)
88         registar_yield();
89 #endif
90     }
91 
92 #ifdef COAP_SERV_MULTITHREAD
93     HAL_SemaphorePost(g_semphore);
94     COAP_INFO("Exit the CoAP daemon task, Post semphore");
95 
96     g_coap_thread = NULL;
97 #endif
98     return NULL;
99 }
100 
101 typedef void (*func_v_v)(void *);
102 static func_v_v coapserver_timer = NULL;
CoAPServer_add_timer(void (* on_timer)(void *))103 void CoAPServer_add_timer(void (*on_timer)(void *))
104 {
105     coapserver_timer = on_timer;
106 }
107 
108 static void *coap_init_mutex = NULL;
CoAPServer_init()109 CoAPContext *CoAPServer_init()
110 {
111     CoAPInitParam param = { 0 };
112 #ifdef COAP_SERV_MULTITHREAD
113     int stack_used;
114     hal_os_thread_param_t task_parms = { 0 };
115 #endif
116     if (NULL == coap_init_mutex) {
117         coap_init_mutex = HAL_MutexCreate();
118 
119         if (NULL == coap_init_mutex) {
120             return NULL;
121         }
122     }
123     HAL_MutexLock(coap_init_mutex);
124 
125     if (NULL == g_context) {
126         param.appdata = NULL;
127         param.group = "224.0.1.187";
128         param.notifier = NULL;
129         param.obs_maxcount = 16;
130         param.res_maxcount = 255;
131         param.port = 5683;
132         param.send_maxcount = 16;
133         param.waittime = 50;
134 
135 #ifdef COAP_SERV_MULTITHREAD
136         g_semphore = HAL_SemaphoreCreate();
137         if (NULL == g_semphore) {
138             COAP_ERR("Semaphore Create failed");
139             HAL_MutexUnlock(coap_init_mutex);
140             return NULL;
141         }
142 
143         coap_yield_mutex = HAL_MutexCreate();
144         if (NULL == coap_yield_mutex) {
145             COAP_ERR("coap_yield_mutex Create failed");
146             HAL_SemaphoreDestroy(g_semphore);
147             g_semphore = NULL;
148             HAL_MutexUnlock(coap_init_mutex);
149             return NULL;
150         }
151 #endif
152 
153         g_context = CoAPContext_create(&param);
154         if (NULL == g_context) {
155 #ifdef COAP_SERV_MULTITHREAD
156             HAL_SemaphoreDestroy(g_semphore);
157             HAL_MutexDestroy(coap_yield_mutex);
158             g_semphore = NULL;
159             coap_yield_mutex = NULL;
160 #endif
161             COAP_ERR("CoAP Context Create failed");
162             HAL_MutexUnlock(coap_init_mutex);
163             return NULL;
164         }
165 #ifdef COAP_SERV_MULTITHREAD
166         g_coap_running = 1;
167         task_parms.stack_size = 4608;
168         task_parms.name = "CoAPServer_yield";
169         HAL_ThreadCreate(&g_coap_thread, CoAPServer_yield, (void *)g_context,
170                          &task_parms, &stack_used);
171 #endif
172 
173     } else {
174         COAP_INFO("The CoAP Server already init");
175     }
176     HAL_MutexUnlock(coap_init_mutex);
177     return (CoAPContext *)g_context;
178 }
179 
CoAPServer_deinit(CoAPContext * context)180 void CoAPServer_deinit(CoAPContext *context)
181 {
182     if (context != g_context) {
183         COAP_INFO("Invalid CoAP Server context");
184         return;
185     }
186 
187     if (NULL == coap_init_mutex) {
188         COAP_ERR("CoAP init mutex is NULL");
189         return;
190     }
191     HAL_MutexLock(coap_init_mutex);
192 
193     COAP_INFO("CoAP Server deinit");
194     g_coap_running = 0;
195 
196 #ifdef COAP_SERV_MULTITHREAD
197     if (NULL != g_semphore) {
198         HAL_SemaphoreWait(g_semphore, PLATFORM_WAIT_INFINITE);
199         COAP_INFO("Wait Semaphore, will exit task");
200         HAL_SemaphoreDestroy(g_semphore);
201         g_semphore = NULL;
202     }
203     if (NULL != coap_yield_mutex) {
204         HAL_MutexDestroy(coap_yield_mutex);
205         coap_yield_mutex = NULL;
206     }
207 #endif
208     if (NULL != context) {
209         CoAPContext_free(context);
210         g_context = NULL;
211     }
212 
213     HAL_MutexUnlock(coap_init_mutex);
214     HAL_MutexDestroy(coap_init_mutex);
215     coap_init_mutex = NULL;
216 }
217 
CoAPServer_register(CoAPContext * context,const char * uri,CoAPRecvMsgHandler callback)218 int CoAPServer_register(CoAPContext *context, const char *uri,
219                         CoAPRecvMsgHandler callback)
220 {
221     if (NULL == context || g_context != context) {
222         return COAP_ERROR_INVALID_PARAM;
223     }
224 
225     return CoAPResource_register(context, uri, COAP_PERM_GET, COAP_CT_APP_JSON,
226                                  60, callback);
227 }
228 
CoAPServerMultiCast_send(CoAPContext * context,NetworkAddr * remote,const char * uri,unsigned char * buff,unsigned short len,CoAPSendMsgHandler callback,unsigned short * msgid)229 int CoAPServerMultiCast_send(CoAPContext *context, NetworkAddr *remote,
230                              const char *uri, unsigned char *buff,
231                              unsigned short len, CoAPSendMsgHandler callback,
232                              unsigned short *msgid)
233 {
234     int ret = COAP_SUCCESS;
235     CoAPMessage message;
236     unsigned char tokenlen;
237     unsigned char token[COAP_MSG_MAX_TOKEN_LEN] = { 0 };
238 
239     if (NULL == context || g_context != context || NULL == remote ||
240         NULL == uri || NULL == buff) {
241         return COAP_ERROR_INVALID_PARAM;
242     }
243 
244     CoAPMessage_init(&message);
245     CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_NON);
246     CoAPMessageCode_set(&message, COAP_MSG_CODE_POST);
247     CoAPMessageId_set(&message, CoAPMessageId_gen(context));
248     tokenlen = CoAPServerToken_get(token);
249     CoAPMessageToken_set(&message, token, tokenlen);
250     CoAPMessageHandler_set(&message, callback);
251     CoAPMessageKeep_Set(&message, 1);
252 
253     CoAPServerPath_2_option((char *)uri, &message);
254     CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON);
255     CoAPMessagePayload_set(&message, buff, len);
256     if (msgid) {
257         *msgid = message.header.msgid;
258     }
259     ret = CoAPMessage_send(context, remote, &message);
260 
261     CoAPMessage_destory(&message);
262 
263     return ret;
264 }
265 
CoAPServerResp_send(CoAPContext * context,NetworkAddr * remote,unsigned char * buff,unsigned short len,void * req,const char * paths,CoAPSendMsgHandler callback,unsigned short * msgid,char qos)266 int CoAPServerResp_send(CoAPContext *context, NetworkAddr *remote,
267                         unsigned char *buff, unsigned short len, void *req,
268                         const char *paths, CoAPSendMsgHandler callback,
269                         unsigned short *msgid, char qos)
270 {
271     int ret = COAP_SUCCESS;
272     CoAPMessage response;
273     unsigned int observe = 0;
274     CoAPMessage *request = (CoAPMessage *)req;
275 
276     if (NULL == context || g_context != context || NULL == remote ||
277         NULL == buff || NULL == paths || NULL == req) {
278         return COAP_ERROR_INVALID_PARAM;
279     }
280 
281     CoAPMessage_init(&response);
282     CoAPMessageType_set(
283         &response, qos == 0 ? COAP_MESSAGE_TYPE_NON : COAP_MESSAGE_TYPE_CON);
284     CoAPMessageCode_set(&response, COAP_MSG_CODE_205_CONTENT);
285     CoAPMessageId_set(&response, request->header.msgid);
286     CoAPMessageToken_set(&response, request->token, request->header.tokenlen);
287     CoAPMessageHandler_set(&response, callback);
288     if (msgid) {
289         *msgid = response.header.msgid;
290     }
291 
292     ret = CoAPUintOption_get(request, COAP_OPTION_OBSERVE, &observe);
293     if (COAP_SUCCESS == ret && 0 == observe) {
294         CoAPObsServer_add(context, paths, remote, request);
295         CoAPUintOption_add(&response, COAP_OPTION_OBSERVE, 0);
296     }
297 
298     CoAPUintOption_add(&response, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON);
299     CoAPMessagePayload_set(&response, buff, len);
300 
301     COAP_DEBUG("Send a response message");
302     ret = CoAPMessage_send(context, remote, &response);
303     CoAPMessage_destory(&response);
304 
305     return ret;
306 }
307 
CoAPServer_loop(CoAPContext * context)308 void CoAPServer_loop(CoAPContext *context)
309 {
310     if (g_context != context || 1 == g_coap_running) {
311         COAP_INFO("The CoAP Server is already running");
312         return;
313     }
314 
315 #ifndef COAP_SERV_MULTITHREAD
316     g_coap_running = 1;
317     CoAPServer_yield((void *)context);
318 #endif
319 }
320