1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "iotx_dm_internal.h"
5 
6 #ifdef DEPRECATED_LINKKIT
7 
8 #include "linkkit/infra/infra_json_parser.h"
9 #include "linkkit/mqtt_api.h"
10 #include "impl_ntp.h"
11 
12 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
13 extern "C" {
14 #endif
15 
16 #ifdef INFRA_MEM_STATS
17 #include "linkkit/infra/infra_mem_stats.h"
18 #define IMPL_NTP_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "impl.ntp")
19 #define IMPL_NTP_FREE(ptr)    LITE_free(ptr)
20 #else
21 #define IMPL_NTP_MALLOC(size) HAL_Malloc(size)
22 #define IMPL_NTP_FREE(ptr)     \
23     {                          \
24         HAL_Free((void *)ptr); \
25         ptr = NULL;            \
26     }
27 #endif
28 
29 typedef void (*ntp_reply_cb_t)(const char *);
30 static ntp_reply_cb_t g_ntp_reply_cb = NULL;
31 static char g_ntp_time[NTP_TIME_STR_MAX_LEN + 1] = { 0 };
32 
linkkit_ntp_time_reply(void * pcontext,void * pclient,void * mesg)33 static void linkkit_ntp_time_reply(void *pcontext, void *pclient, void *mesg)
34 {
35 #define DEV_TX_TIME    "deviceSendTime"
36 #define SERVER_RX_TIME "serverRecvTime"
37 #define SERVER_TX_TIME "serverSendTime"
38 
39     int len = 0;
40     char *elem = NULL;
41     char server_rx_time[NTP_TIME_STR_MAX_LEN + 1] = { 0 };
42     char server_tx_time[NTP_TIME_STR_MAX_LEN + 1] = { 0 };
43     uint32_t payload_len;
44     char *payload;
45     uint32_t tx = 0;
46     uint32_t rx = 0;
47     uint32_t diff = 0;
48 
49     iotx_mqtt_event_msg_pt msg = (iotx_mqtt_event_msg_pt)mesg;
50     iotx_mqtt_topic_info_pt ptopic_info = (iotx_mqtt_topic_info_pt)msg->msg;
51 
52     switch (msg->event_type) {
53     case IOTX_MQTT_EVENT_PUBLISH_RECEIVED:
54         payload_len = ptopic_info->payload_len;
55         payload = (char *)ptopic_info->payload;
56         break;
57     default:
58         goto NTP_FAIL;
59     }
60 
61     if (payload == NULL || payload_len == 0) {
62         goto NTP_FAIL;
63     }
64 
65     memset(g_ntp_time, 0, sizeof(g_ntp_time));
66     log_debug("[ntp]", "ntp reply len:%u, payload:%s\r\n", payload_len,
67               payload);
68 
69     /*
70      * get deviceSendTime, serverRecvTime, serverSendTime
71      */
72     elem = json_get_value_by_name(payload, payload_len, SERVER_TX_TIME, &len,
73                                   NULL);
74     if (elem == NULL || len <= 0 || len > NTP_TIME_STR_MAX_LEN) {
75         goto NTP_FAIL;
76     }
77 
78     memcpy(server_tx_time, elem, len);
79 
80     elem = json_get_value_by_name(payload, payload_len, SERVER_RX_TIME, &len,
81                                   NULL);
82     if (elem == NULL || len <= 0 || len > NTP_TIME_STR_MAX_LEN) {
83         goto NTP_FAIL;
84     }
85 
86     memcpy(server_rx_time, elem, len);
87 
88     elem =
89         json_get_value_by_name(payload, payload_len, DEV_TX_TIME, &len, NULL);
90     if (elem == NULL || len <= 0 || len > NTP_TIME_STR_MAX_LEN) {
91         goto NTP_FAIL;
92     }
93     /*
94      * atoi fails to convert string to integer
95      * so we convert manully
96      */
97     while (len-- > 0) {
98         tx *= 10;
99         tx += elem[0] - '0';
100         elem++;
101     }
102     rx = HAL_UptimeMs();
103     diff = (rx - tx) >> 1;
104     if (diff >= 1000000) {
105         goto NTP_FAIL;
106     }
107 
108     len = strlen(server_tx_time);
109     elem = &server_tx_time[len > 9 ? len - 9 : 0];
110     tx = atoi(elem);
111     tx += diff;
112 
113     if (tx > 999999999) {
114         tx = 999999999;
115     }
116 
117     if (len > 9) {
118         sprintf(elem, "%09u", (unsigned int)tx);
119     } else {
120         sprintf(elem, "%u", (unsigned int)tx);
121     }
122 
123     strncpy(g_ntp_time, (const char *)server_tx_time, sizeof(g_ntp_time) - 1);
124 
125 NTP_FAIL:
126     if (g_ntp_reply_cb != NULL) {
127         g_ntp_reply_cb(g_ntp_time);
128     }
129     return;
130 }
131 
linkkit_ntp_time_request(void (* ntp_reply)(const char * ntp_offset_time_ms))132 int linkkit_ntp_time_request(void (*ntp_reply)(const char *ntp_offset_time_ms))
133 {
134     int ret = -1;
135     int final_len = 0;
136     int packet_len = 64;
137     int topic_len = 128;
138     char *packet = NULL;
139     char *topic = NULL;
140 
141     do {
142         char pk[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
143         char dn[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
144 
145         HAL_GetProductKey(pk);
146         HAL_GetDeviceName(dn);
147 
148         topic = (char *)IMPL_NTP_MALLOC(topic_len + 1);
149         if (topic == NULL) {
150             goto NTP_REQ_ERR;
151         }
152         memset(topic, 0, topic_len + 1);
153 
154         HAL_Snprintf(topic, topic_len, TOPIC_NTP_REPLY, pk, dn);
155 #ifdef MQTT_AUTO_SUBSCRIBE
156         ret = IOT_MQTT_Subscribe_Sync(
157             NULL, topic, IOTX_MQTT_QOS3_SUB_LOCAL,
158             (iotx_mqtt_event_handle_func_fpt)linkkit_ntp_time_reply, NULL,
159             1000);
160 #else
161         ret = IOT_MQTT_Subscribe_Sync(
162             NULL, topic, IOTX_MQTT_QOS0,
163             (iotx_mqtt_event_handle_func_fpt)linkkit_ntp_time_reply, NULL,
164             1000);
165 #endif
166         if (ret < 0) {
167             goto NTP_REQ_ERR;
168         }
169 
170         memset(topic, 0, topic_len + 1);
171         HAL_Snprintf(topic, topic_len, TOPIC_NTP, pk, dn);
172     } while (0);
173 
174     packet = (char *)IMPL_NTP_MALLOC(packet_len + 1);
175     if (packet == NULL) {
176         ret = -1;
177         goto NTP_REQ_ERR;
178     }
179     memset(packet, 0, packet_len + 1);
180 
181     g_ntp_reply_cb = ntp_reply;
182     final_len = HAL_Snprintf(packet, packet_len, "{\"deviceSendTime\":\"%u\"}",
183                              (unsigned int)(HAL_UptimeMs()));
184 
185     log_debug("[ntp]", "report ntp:%s\r\n", packet);
186 
187     ret =
188         IOT_MQTT_Publish_Simple(NULL, topic, IOTX_MQTT_QOS0, packet, final_len);
189 
190 NTP_REQ_ERR:
191     if (topic) {
192         IMPL_NTP_FREE(topic);
193     }
194     if (packet) {
195         IMPL_NTP_FREE(packet);
196     }
197     return ret;
198 }
199 
200 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
201 }
202 #endif
203 #endif
204 
205