1 /**
2  * @file aiot_ntp_api.c
3  * @brief ntp模块的API接口实现, 提供获取utc时间的能力
4  *
5  * @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
6  *
7  */
8 
9 /* TODO: 对本模块的头文件, 仅需包含ntp_private.h, 不需包含aiot_ntp_api.h */
10 #include "ntp_private.h"
11 
12 /* TODO: 列出对core模块需要包含的头文件 */
13 #include "core_string.h"
14 #include "core_log.h"
15 #include "core_global.h"
16 #include "core_mqtt.h"
17 
_core_ntp_exec_inc(ntp_handle_t * ntp_handle)18 static void _core_ntp_exec_inc(ntp_handle_t *ntp_handle)
19 {
20     ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
21     ntp_handle->exec_count++;
22     ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
23 }
24 
_core_ntp_exec_dec(ntp_handle_t * ntp_handle)25 static void _core_ntp_exec_dec(ntp_handle_t *ntp_handle)
26 {
27     ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
28     ntp_handle->exec_count--;
29     ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
30 }
31 
_ntp_recv_handler(void * handle,const aiot_mqtt_recv_t * packet,void * userdata)32 static void _ntp_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
33 {
34     ntp_handle_t *ntp_handle = (ntp_handle_t *)userdata;
35 
36     switch (packet->type) {
37         case AIOT_MQTTRECV_PUB: {
38             char *dst_key = "deviceSendTime", *srt_key = "serverRecvTime", *sst_key = "serverSendTime";
39             char *dst_value = NULL, *srt_value = NULL, *sst_value = NULL;
40             uint32_t dst_value_len = 0, srt_value_len = 0, sst_value_len = 0;
41             uint64_t dst = 0, srt = 0, sst = 0, utc = 0;
42 
43             if (core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, dst_key, (uint32_t)strlen(dst_key),
44                                 &dst_value, &dst_value_len) == STATE_SUCCESS &&
45                 core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, srt_key, (uint32_t)strlen(srt_key),
46                                 &srt_value, &srt_value_len) == STATE_SUCCESS &&
47                 core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, sst_key, (uint32_t)strlen(sst_key),
48                                 &sst_value, &sst_value_len) == STATE_SUCCESS) {
49                 if (core_str2uint64(dst_value, (uint8_t)dst_value_len, &dst) == STATE_SUCCESS &&
50                     core_str2uint64(srt_value, (uint8_t)srt_value_len, &srt) == STATE_SUCCESS &&
51                     core_str2uint64(sst_value, (uint8_t)sst_value_len, &sst) == STATE_SUCCESS) {
52                     core_date_t date;
53                     utc = (srt + sst + ntp_handle->sysdep->core_sysdep_time() - dst) / 2;
54 
55                     core_log_set_timestamp(ntp_handle->sysdep, utc);
56 
57                     memset(&date, 0, sizeof(core_date_t));
58                     core_utc2date(utc, ntp_handle->time_zone, &date);
59                     if (ntp_handle->recv_handler != NULL) {
60                         aiot_ntp_recv_t recv;
61 
62                         memset(&recv, 0, sizeof(aiot_ntp_recv_t));
63                         recv.type = AIOT_NTPRECV_LOCAL_TIME;
64                         recv.data.local_time.timestamp = utc;
65                         recv.data.local_time.year = date.year;
66                         recv.data.local_time.mon = date.mon;
67                         recv.data.local_time.day = date.day;
68                         recv.data.local_time.hour = date.hour;
69                         recv.data.local_time.min = date.min;
70                         recv.data.local_time.sec = date.sec;
71                         recv.data.local_time.msec = date.msec;
72 
73                         ntp_handle->recv_handler(ntp_handle, &recv, ntp_handle->userdata);
74                     }
75                 } else {
76                     if (ntp_handle->event_handler != NULL) {
77                         aiot_ntp_event_t event;
78 
79                         memset(&event, 0, sizeof(aiot_ntp_event_t));
80                         event.type = AIOT_NTPEVT_INVALID_TIME_FORMAT;
81                         ntp_handle->event_handler(ntp_handle, &event, ntp_handle->userdata);
82                     }
83                 }
84             } else {
85                 if (ntp_handle->event_handler != NULL) {
86                     aiot_ntp_event_t event;
87 
88                     memset(&event, 0, sizeof(aiot_ntp_event_t));
89                     event.type = AIOT_NTPEVT_INVALID_RESPONSE;
90                     ntp_handle->event_handler(ntp_handle, &event, ntp_handle->userdata);
91                 }
92             }
93         }
94         default: {
95 
96         }
97         break;
98     }
99 }
100 
_ntp_operate_topic_map(ntp_handle_t * ntp_handle,aiot_mqtt_option_t option)101 static int32_t _ntp_operate_topic_map(ntp_handle_t *ntp_handle, aiot_mqtt_option_t option)
102 {
103     int32_t res = STATE_SUCCESS;
104     aiot_mqtt_topic_map_t map;
105     char *topic = NULL;
106     char *topic_src[] = { core_mqtt_get_product_key(ntp_handle->mqtt_handle), core_mqtt_get_device_name(ntp_handle->mqtt_handle) };
107     char *topic_fmt = NTP_RESPONSE_TOPIC_FMT;
108 
109     memset(&map, 0, sizeof(aiot_mqtt_topic_map_t));
110 
111     res = core_sprintf(ntp_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
112                        NTP_MODULE_NAME);
113     if (res < STATE_SUCCESS) {
114         return res;
115     }
116 
117     map.topic = topic;
118     map.handler = _ntp_recv_handler;
119     map.userdata = (void *)ntp_handle;
120 
121     res = aiot_mqtt_setopt(ntp_handle->mqtt_handle, option, &map);
122     ntp_handle->sysdep->core_sysdep_free(topic);
123 
124     return res;
125 }
126 
_ntp_core_mqtt_process_handler(void * context,aiot_mqtt_event_t * event,core_mqtt_event_t * core_event)127 static void _ntp_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
128 {
129     ntp_handle_t *ntp_handle = (ntp_handle_t *)context;
130 
131     if (core_event != NULL) {
132         switch (core_event->type) {
133             case CORE_MQTTEVT_DEINIT: {
134                 ntp_handle->mqtt_handle = NULL;
135                 return;
136             }
137             break;
138             default: {
139 
140             }
141             break;
142         }
143     }
144 }
145 
_ntp_core_mqtt_operate_process_handler(ntp_handle_t * ntp_handle,core_mqtt_option_t option)146 static int32_t _ntp_core_mqtt_operate_process_handler(ntp_handle_t *ntp_handle, core_mqtt_option_t option)
147 {
148     core_mqtt_process_data_t process_data;
149 
150     memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
151     process_data.handler = _ntp_core_mqtt_process_handler;
152     process_data.context = ntp_handle;
153 
154     return core_mqtt_setopt(ntp_handle->mqtt_handle, option, &process_data);
155 }
156 
aiot_ntp_init(void)157 void *aiot_ntp_init(void)
158 {
159     ntp_handle_t *ntp_handle = NULL;
160     aiot_sysdep_portfile_t *sysdep = NULL;
161 
162     sysdep = aiot_sysdep_get_portfile();
163     if (sysdep == NULL) {
164         return NULL;
165     }
166 
167     ntp_handle = sysdep->core_sysdep_malloc(sizeof(ntp_handle_t), NTP_MODULE_NAME);
168     if (ntp_handle == NULL) {
169         return NULL;
170     }
171     memset(ntp_handle, 0, sizeof(ntp_handle_t));
172 
173     ntp_handle->sysdep = sysdep;
174     ntp_handle->deinit_timeout_ms = NTP_DEFAULT_DEINIT_TIMEOUT_MS;
175 
176     ntp_handle->data_mutex = sysdep->core_sysdep_mutex_init();
177 
178     ntp_handle->exec_enabled = 1;
179 
180     return ntp_handle;
181 }
182 
aiot_ntp_setopt(void * handle,aiot_ntp_option_t option,void * data)183 int32_t aiot_ntp_setopt(void *handle, aiot_ntp_option_t option, void *data)
184 {
185     int32_t res = STATE_SUCCESS;
186     ntp_handle_t *ntp_handle = (ntp_handle_t *)handle;
187 
188     if (handle == NULL || data == NULL) {
189         return STATE_USER_INPUT_NULL_POINTER;
190     }
191 
192     if (option >= AIOT_NTPOPT_MAX) {
193         return STATE_USER_INPUT_OUT_RANGE;
194     }
195 
196     if (ntp_handle->exec_enabled == 0) {
197         return STATE_USER_INPUT_EXEC_DISABLED;
198     }
199 
200     _core_ntp_exec_inc(ntp_handle);
201 
202     ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
203     switch (option) {
204         case AIOT_NTPOPT_MQTT_HANDLE: {
205             ntp_handle->mqtt_handle = data;
206             ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
207             res = _ntp_operate_topic_map(ntp_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP);
208             if (res >= STATE_SUCCESS) {
209                 res = _ntp_core_mqtt_operate_process_handler(ntp_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
210             }
211             ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
212         }
213         break;
214         case AIOT_NTPOPT_TIME_ZONE: {
215             ntp_handle->time_zone = *(int8_t *)data;
216         }
217         break;
218         case AIOT_NTPOPT_RECV_HANDLER: {
219             ntp_handle->recv_handler = (aiot_ntp_recv_handler_t)data;
220         }
221         break;
222         case AIOT_NTPOPT_EVENT_HANDLER: {
223             ntp_handle->event_handler = (aiot_ntp_event_handler_t)data;
224         }
225         break;
226         case AIOT_NTPOPT_USERDATA: {
227             ntp_handle->userdata = data;
228         }
229         break;
230         case AIOT_NTPOPT_DEINIT_TIMEOUT_MS: {
231             ntp_handle->deinit_timeout_ms = *(uint32_t *)data;
232         }
233         break;
234         default: {
235             res = STATE_USER_INPUT_UNKNOWN_OPTION;
236         }
237         break;
238     }
239     ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
240 
241     _core_ntp_exec_dec(ntp_handle);
242 
243     return res;
244 }
245 
aiot_ntp_deinit(void ** handle)246 int32_t aiot_ntp_deinit(void **handle)
247 {
248     uint64_t deinit_timestart = 0;
249     ntp_handle_t *ntp_handle = NULL;
250 
251     if (handle == NULL || *handle == NULL) {
252         return STATE_USER_INPUT_NULL_POINTER;
253     }
254 
255     ntp_handle = *(ntp_handle_t **)handle;
256 
257     if (ntp_handle->exec_enabled == 0) {
258         return STATE_USER_INPUT_EXEC_DISABLED;
259     }
260 
261     ntp_handle->exec_enabled = 0;
262 
263     _ntp_core_mqtt_operate_process_handler(ntp_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
264     _ntp_operate_topic_map(ntp_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP);
265 
266     deinit_timestart = ntp_handle->sysdep->core_sysdep_time();
267     do {
268         if (ntp_handle->exec_count == 0) {
269             break;
270         }
271         ntp_handle->sysdep->core_sysdep_sleep(NTP_DEINIT_INTERVAL_MS);
272     } while ((ntp_handle->sysdep->core_sysdep_time() - deinit_timestart) < ntp_handle->deinit_timeout_ms);
273 
274     if (ntp_handle->exec_count != 0) {
275         return STATE_MQTT_DEINIT_TIMEOUT;
276     }
277 
278     *handle = NULL;
279 
280     ntp_handle->sysdep->core_sysdep_mutex_deinit(&ntp_handle->data_mutex);
281 
282     ntp_handle->sysdep->core_sysdep_free(ntp_handle);
283 
284     return STATE_SUCCESS;
285 }
286 
aiot_ntp_send_request(void * handle)287 int32_t aiot_ntp_send_request(void *handle)
288 {
289     int32_t res = STATE_SUCCESS;
290     char *topic = NULL, *payload = NULL;
291     ntp_handle_t *ntp_handle = (ntp_handle_t *)handle;
292 
293     if (handle == NULL) {
294         return STATE_USER_INPUT_NULL_POINTER;
295     }
296 
297     if (ntp_handle->mqtt_handle == NULL) {
298         return STATE_NTP_MISSING_MQTT_HANDLE;
299     }
300 
301     if (ntp_handle->exec_enabled == 0) {
302         return STATE_USER_INPUT_EXEC_DISABLED;
303     }
304 
305     _core_ntp_exec_inc(ntp_handle);
306 
307     {
308         char *topic_src[] = { core_mqtt_get_product_key(ntp_handle->mqtt_handle), core_mqtt_get_device_name(ntp_handle->mqtt_handle) };
309         char *topic_fmt = NTP_REQUEST_TOPIC_FMT;
310         char time_str[21] = {0};
311         char *payload_src[] = { time_str };
312         char *payload_fmt = NTP_REQUEST_PAYLOAD_FMT;
313 
314         res = core_sprintf(ntp_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
315                            NTP_MODULE_NAME);
316         if (res < STATE_SUCCESS) {
317             _core_ntp_exec_dec(ntp_handle);
318             return res;
319         }
320 
321         core_uint642str(ntp_handle->sysdep->core_sysdep_time(), time_str, NULL);
322         res = core_sprintf(ntp_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
323                            NTP_MODULE_NAME);
324         if (res < STATE_SUCCESS) {
325             ntp_handle->sysdep->core_sysdep_free(topic);
326             _core_ntp_exec_dec(ntp_handle);
327             return res;
328         }
329     }
330 
331     res = aiot_mqtt_pub(ntp_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
332     ntp_handle->sysdep->core_sysdep_free(topic);
333     ntp_handle->sysdep->core_sysdep_free(payload);
334     if (res < STATE_SUCCESS) {
335         _core_ntp_exec_dec(ntp_handle);
336         return res;
337     }
338 
339     _core_ntp_exec_dec(ntp_handle);
340 
341     return STATE_SUCCESS;
342 }
343 
344