1 /**
2  * @file aiot_devinfo_api.c
3  * @brief devinfo模块的API接口实现, 提供更新和删除设备标签的能力
4  *
5  * @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
6  *
7  */
8 
9 #include "devinfo_private.h"
10 
11 #include "core_string.h"
12 #include "core_log.h"
13 #include "core_global.h"
14 #include "core_mqtt.h"
15 
_core_devinfo_exec_inc(devinfo_handle_t * devinfo_handle)16 static void _core_devinfo_exec_inc(devinfo_handle_t *devinfo_handle)
17 {
18     devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
19     devinfo_handle->exec_count++;
20     devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
21 }
22 
_core_devinfo_exec_dec(devinfo_handle_t * devinfo_handle)23 static void _core_devinfo_exec_dec(devinfo_handle_t *devinfo_handle)
24 {
25     devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
26     devinfo_handle->exec_count--;
27     devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
28 }
29 
_devinfo_find_pk_dn(devinfo_handle_t * devinfo_handle,char * topic,uint16_t topic_len,char ** product_key,char ** device_name)30 static void _devinfo_find_pk_dn(devinfo_handle_t *devinfo_handle, char *topic, uint16_t topic_len, char **product_key, char **device_name)
31 {
32     uint16_t idx = 0, prev_slash = 0, slash = 0, pk_len = 0, dn_len = 0;
33     char *pk_pos = NULL, *dn_pos = NULL, *tmp_pk = NULL, *tmp_dn = NULL;
34 
35     for (idx = 0;idx < topic_len;idx++) {
36         if (topic[idx] == '/') {
37             slash++;
38             if (slash == 2) {
39                 pk_pos = &topic[idx + 1];
40                 prev_slash = idx;
41             } else if (slash == 3) {
42                 dn_pos = &topic[idx + 1];
43                 pk_len = idx - prev_slash - 1;
44                 prev_slash = idx;
45             } else if (slash == 4) {
46                 dn_len = idx - prev_slash - 1;
47                 break;
48             }
49         }
50     }
51 
52     if (pk_len == 0 || dn_len == 0) {
53         return;
54     }
55 
56     tmp_pk = devinfo_handle->sysdep->core_sysdep_malloc(pk_len + 1, DEVINFO_MODULE_NAME);
57     if (tmp_pk == NULL) {
58         return;
59     }
60     memset(tmp_pk, 0, pk_len + 1);
61     memcpy(tmp_pk, pk_pos, pk_len);
62 
63     tmp_dn = devinfo_handle->sysdep->core_sysdep_malloc(dn_len + 1, DEVINFO_MODULE_NAME);
64     if (tmp_dn == NULL) {
65         devinfo_handle->sysdep->core_sysdep_free(tmp_pk);
66         return;
67     }
68     memset(tmp_dn, 0, dn_len + 1);
69     memcpy(tmp_dn, dn_pos, dn_len);
70 
71     *product_key = tmp_pk;
72     *device_name = tmp_dn;
73 }
74 
_devinfo_mqtt_recv_handler(void * handle,const aiot_mqtt_recv_t * packet,void * userdata)75 static void _devinfo_mqtt_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
76 {
77     devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)userdata;
78     aiot_devinfo_event_t event;
79     char *product_key = NULL, *device_name = NULL;
80     char *code_key = "code", *id_key = "id", *data_key = "data", *message_key = "message";
81     char *code_value = NULL, *id_value = NULL, *data_value = NULL, *message_value = NULL;
82     uint32_t code_value_len = 0, id_value_len = 0, data_value_len = 0, message_value_len = 0;
83 
84     if (devinfo_handle->recv_handler == NULL) {
85         return;
86     }
87 
88     _devinfo_find_pk_dn(devinfo_handle, packet->data.pub.topic, packet->data.pub.topic_len, &product_key, &device_name);
89     if (product_key == NULL || device_name == NULL) {
90         if (devinfo_handle->event_handler != NULL) {
91             memset(&event, 0, sizeof(aiot_devinfo_event_t));
92             event.type = AIOT_DEVINFOEVT_INVALID_DEVINFO;
93             devinfo_handle->event_handler(devinfo_handle, &event, devinfo_handle->userdata);
94         }
95         return;
96     }
97 
98     if (core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
99                     code_key, (uint32_t)strlen(code_key) ,&code_value, &code_value_len) == STATE_SUCCESS &&
100         core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
101                     id_key, (uint32_t)strlen(id_key) ,&id_value, &id_value_len) == STATE_SUCCESS &&
102         core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
103                     data_key, (uint32_t)strlen(data_key) ,&data_value, &data_value_len) == STATE_SUCCESS &&
104         core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
105                     message_key, (uint32_t)strlen(message_key) ,&message_value, &message_value_len) == STATE_SUCCESS) {
106         uint32_t code = 0, id = 0;
107         if (core_str2uint(code_value, code_value_len, &code) == STATE_SUCCESS &&
108             core_str2uint(id_value, id_value_len, &id) == STATE_SUCCESS) {
109             aiot_devinfo_recv_t recv;
110 
111             memset(&recv, 0, sizeof(aiot_devinfo_recv_t));
112             recv.product_key = product_key;
113             recv.device_name = device_name;
114             recv.type = AIOT_DEVINFORECV_GENERIC_REPLY;
115             recv.data.generic_reply.code = code;
116             recv.data.generic_reply.msg_id = id;
117             recv.data.generic_reply.data = data_value;
118             recv.data.generic_reply.data_len = data_value_len;
119             recv.data.generic_reply.message = message_value;
120             recv.data.generic_reply.message_len = message_value_len;
121 
122             devinfo_handle->recv_handler(devinfo_handle, &recv, devinfo_handle->userdata);
123         } else {
124             if (devinfo_handle->event_handler != NULL) {
125                 memset(&event, 0, sizeof(aiot_devinfo_event_t));
126                 event.type = AIOT_DEVINFOEVT_INVALID_RESPONSE_FORMAT;
127                 devinfo_handle->event_handler(devinfo_handle, &event, devinfo_handle->userdata);
128             }
129         }
130     } else {
131         if (devinfo_handle->event_handler != NULL) {
132             memset(&event, 0, sizeof(aiot_devinfo_event_t));
133             event.type = AIOT_DEVINFOEVT_INVALID_RESPONSE;
134             devinfo_handle->event_handler(devinfo_handle, &event, devinfo_handle->userdata);
135         }
136     }
137     devinfo_handle->sysdep->core_sysdep_free(product_key);
138     devinfo_handle->sysdep->core_sysdep_free(device_name);
139 }
140 
_devinfo_operate_topic_map(devinfo_handle_t * devinfo_handle,aiot_mqtt_option_t option)141 static int32_t _devinfo_operate_topic_map(devinfo_handle_t *devinfo_handle, aiot_mqtt_option_t option)
142 {
143     int32_t res = STATE_SUCCESS;
144     aiot_mqtt_topic_map_t map;
145 
146     if (option == AIOT_MQTTOPT_NETWORK_CRED) {
147         return STATE_USER_INPUT_OUT_RANGE;
148     }
149 
150     memset(&map, 0, sizeof(aiot_mqtt_topic_map_t));
151     map.topic = DEVINFO_UPDATE_REPLY_TOPIC;
152     map.handler = _devinfo_mqtt_recv_handler;
153     map.userdata = devinfo_handle;
154 
155     res = aiot_mqtt_setopt(devinfo_handle->mqtt_handle, option, &map);
156     if (res < STATE_SUCCESS) {
157         return res;
158     }
159 
160     map.topic = DEVINFO_DELETE_REPLY_TOPIC;
161     map.handler = _devinfo_mqtt_recv_handler;
162     map.userdata = devinfo_handle;
163 
164     res = aiot_mqtt_setopt(devinfo_handle->mqtt_handle, option, &map);
165     if (res < STATE_SUCCESS) {
166         return res;
167     }
168 
169     return STATE_SUCCESS;
170 }
171 
_devinfo_send(devinfo_handle_t * devinfo_handle,char * product_key,char * device_name,aiot_devinfo_msg_data_t * data,char * topic_fmt)172 static int32_t _devinfo_send(devinfo_handle_t *devinfo_handle, char *product_key, char *device_name, aiot_devinfo_msg_data_t *data, char *topic_fmt)
173 {
174     int32_t res = STATE_SUCCESS, alink_id = 0;
175     char *topic = NULL, *payload = NULL;
176     char *topic_src[] = { product_key, device_name };
177     char alink_id_str[11] = {0}, *payload_src[] = { alink_id_str, data->params };
178     char *payload_fmt = "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":%s}";
179 
180     res = core_global_alink_id_next(devinfo_handle->sysdep, &alink_id);
181     if (res < STATE_SUCCESS) {
182         return res;
183     }
184 
185     res = core_int2str(alink_id, alink_id_str, NULL);
186     if (res < STATE_SUCCESS) {
187         return res;
188     }
189 
190     res = core_sprintf(devinfo_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src)/sizeof(char *), DEVINFO_MODULE_NAME);
191     if (res < STATE_SUCCESS) {
192         return res;
193     }
194 
195     res = core_sprintf(devinfo_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src)/sizeof(char *), DEVINFO_MODULE_NAME);
196     if (res < STATE_SUCCESS) {
197         devinfo_handle->sysdep->core_sysdep_free(topic);
198         return res;
199     }
200 
201     res = aiot_mqtt_pub(devinfo_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
202     devinfo_handle->sysdep->core_sysdep_free(topic);
203     devinfo_handle->sysdep->core_sysdep_free(payload);
204 
205     if (res >= STATE_SUCCESS) {
206         res = alink_id;
207     }
208 
209     return res;
210 }
211 
_devinfo_core_mqtt_process_handler(void * context,aiot_mqtt_event_t * event,core_mqtt_event_t * core_event)212 static void _devinfo_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
213 {
214     devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)context;
215 
216     if (core_event != NULL) {
217         switch (core_event->type) {
218             case CORE_MQTTEVT_DEINIT: {
219                 devinfo_handle->mqtt_handle = NULL;
220                 return;
221             }
222             break;
223             default: {
224 
225             }
226             break;
227         }
228     }
229 }
230 
_devinfo_core_mqtt_operate_process_handler(devinfo_handle_t * devinfo_handle,core_mqtt_option_t option)231 static int32_t _devinfo_core_mqtt_operate_process_handler(devinfo_handle_t *devinfo_handle, core_mqtt_option_t option)
232 {
233     core_mqtt_process_data_t process_data;
234 
235     memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
236     process_data.handler = _devinfo_core_mqtt_process_handler;
237     process_data.context = devinfo_handle;
238 
239     return core_mqtt_setopt(devinfo_handle->mqtt_handle, option, &process_data);
240 }
241 
aiot_devinfo_init(void)242 void *aiot_devinfo_init(void)
243 {
244     int32_t res = STATE_SUCCESS;
245     devinfo_handle_t *devinfo_handle = NULL;
246     aiot_sysdep_portfile_t *sysdep = NULL;
247 
248     sysdep = aiot_sysdep_get_portfile();
249     if (sysdep == NULL) {
250         return NULL;
251     }
252 
253     res = core_global_init(sysdep);
254     if (res < STATE_SUCCESS) {
255         return NULL;
256     }
257 
258     devinfo_handle = sysdep->core_sysdep_malloc(sizeof(devinfo_handle_t), DEVINFO_MODULE_NAME);
259     if (devinfo_handle == NULL) {
260         core_global_deinit(sysdep);
261         return NULL;
262     }
263     memset(devinfo_handle, 0, sizeof(devinfo_handle_t));
264 
265     devinfo_handle->sysdep = sysdep;
266     devinfo_handle->deinit_timeout_ms = DEVINFO_DEFAULT_DEINIT_TIMEOUT_MS;
267 
268     devinfo_handle->data_mutex = sysdep->core_sysdep_mutex_init();
269 
270     devinfo_handle->exec_enabled = 1;
271 
272     return devinfo_handle;
273 }
274 
aiot_devinfo_setopt(void * handle,aiot_devinfo_option_t option,void * data)275 int32_t aiot_devinfo_setopt(void *handle, aiot_devinfo_option_t option, void *data)
276 {
277     int32_t res = STATE_SUCCESS;
278     devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)handle;
279 
280     if (handle == NULL || data == NULL) {
281         return STATE_USER_INPUT_NULL_POINTER;
282     }
283 
284     if (option >= AIOT_DEVINFOOPT_MAX) {
285         return STATE_USER_INPUT_OUT_RANGE;
286     }
287 
288     if (devinfo_handle->exec_enabled == 0) {
289         return STATE_USER_INPUT_EXEC_DISABLED;
290     }
291 
292     _core_devinfo_exec_inc(devinfo_handle);
293 
294     devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
295     switch (option) {
296         case AIOT_DEVINFOOPT_MQTT_HANDLE: {
297             devinfo_handle->mqtt_handle = data;
298             devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
299             res = _devinfo_operate_topic_map(devinfo_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP);
300             if (res >= STATE_SUCCESS) {
301                 res = _devinfo_core_mqtt_operate_process_handler(devinfo_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
302             }
303             devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
304         }
305         break;
306         case AIOT_DEVINFOOPT_RECV_HANDLER: {
307             devinfo_handle->recv_handler = (aiot_devinfo_recv_handler_t)data;
308         }
309         break;
310         case AIOT_DEVINFOOPT_EVENT_HANDLER: {
311             devinfo_handle->event_handler = (aiot_devinfo_event_handler_t)data;
312         }
313         break;
314         case AIOT_DEVINFOOPT_USERDATA: {
315             devinfo_handle->userdata = data;
316         }
317         break;
318         case AIOT_DEVINFOOPT_DEINIT_TIMEOUT_MS: {
319             devinfo_handle->deinit_timeout_ms = *(uint32_t *)data;
320         }
321         break;
322         default: {
323             res = STATE_USER_INPUT_UNKNOWN_OPTION;
324         }
325     }
326     devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
327 
328     _core_devinfo_exec_dec(devinfo_handle);
329 
330     return res;
331 }
332 
aiot_devinfo_deinit(void ** handle)333 int32_t aiot_devinfo_deinit(void **handle)
334 {
335     uint64_t deinit_timestart = 0;
336     devinfo_handle_t *devinfo_handle = NULL;
337 
338     if (handle == NULL || *handle == NULL) {
339         return STATE_USER_INPUT_NULL_POINTER;
340     }
341 
342     devinfo_handle = *(devinfo_handle_t **)handle;
343 
344     if (devinfo_handle->exec_enabled == 0) {
345         return STATE_USER_INPUT_EXEC_DISABLED;
346     }
347 
348     devinfo_handle->exec_enabled = 0;
349 
350     _devinfo_core_mqtt_operate_process_handler(devinfo_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
351     _devinfo_operate_topic_map(devinfo_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP);
352 
353     deinit_timestart = devinfo_handle->sysdep->core_sysdep_time();
354     do {
355         if (devinfo_handle->exec_count == 0) {
356             break;
357         }
358         devinfo_handle->sysdep->core_sysdep_sleep(DEVINFO_DEINIT_INTERVAL_MS);
359     } while ((devinfo_handle->sysdep->core_sysdep_time() - deinit_timestart) < devinfo_handle->deinit_timeout_ms);
360 
361     if (devinfo_handle->exec_count != 0) {
362         return STATE_MQTT_DEINIT_TIMEOUT;
363     }
364 
365     *handle = NULL;
366 
367     devinfo_handle->sysdep->core_sysdep_mutex_deinit(&devinfo_handle->data_mutex);
368 
369     core_global_deinit(devinfo_handle->sysdep);
370 
371     devinfo_handle->sysdep->core_sysdep_free(devinfo_handle);
372 
373     return STATE_SUCCESS;
374 }
375 
aiot_devinfo_send(void * handle,aiot_devinfo_msg_t * msg)376 int32_t aiot_devinfo_send(void *handle, aiot_devinfo_msg_t *msg)
377 {
378     int32_t res = STATE_SUCCESS;
379     devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)handle;
380 
381     if (handle == NULL || msg == NULL) {
382         return STATE_USER_INPUT_NULL_POINTER;
383     }
384 
385     if (devinfo_handle->mqtt_handle == NULL) {
386         return STATE_DEVINFO_MISSING_MQTT_HANDLE;
387     }
388 
389     if (msg->product_key == NULL) {
390         return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
391     }
392 
393     if (msg->device_name == NULL) {
394         return STATE_USER_INPUT_MISSING_DEVICE_NAME;
395     }
396 
397     switch (msg->type) {
398         case AIOT_DEVINFO_MSG_UPDATE: {
399             if (msg->data.update.params == NULL) {
400                 res = STATE_USER_INPUT_NULL_POINTER;
401             }else{
402                 res = _devinfo_send(devinfo_handle, msg->product_key, msg->device_name, &msg->data.update, DEVINFO_UPDATE_TOPIC_FMT);
403             }
404         }
405         break;
406         case AIOT_DEVINFO_MSG_DELETE: {
407             if (msg->data.delete.params == NULL) {
408                 res = STATE_USER_INPUT_NULL_POINTER;
409             }else{
410                 res = _devinfo_send(devinfo_handle, msg->product_key, msg->device_name, &msg->data.delete, DEVINFO_DELETE_TOPIC_FMT);
411             }
412         }
413         break;
414         default: {
415             res = STATE_USER_INPUT_UNKNOWN_OPTION;
416         }
417     }
418 
419     return res;
420 }
421 
422