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(¶m);
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