1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include "iotx_dm_internal.h"
6 
7 #if defined(LOG_REPORT_TO_CLOUD) && !defined(DEVICE_MODEL_RAWDATA_SOLO)
8 
9 #include "linkkit/dev_model_api.h"
10 
11 const char THING_LOG_POST_PARAMS_HEAD[] = "\"%.*s %s %ld ";
12 const char THING_LOG_POST_PARAMS_BODY[] = "%s %ld ";
13 const char THING_LOG_POST_PARAMS_END[] = "%s %ld\",";
14 
15 char *g_log_poll = NULL;
16 static char *current_log_pos = NULL;
17 
remove_log_poll()18 int remove_log_poll()
19 {
20     if (NULL != g_log_poll) {
21         HAL_Free(g_log_poll);
22         g_log_poll = NULL;
23         current_log_pos = NULL;
24     }
25     return 0;
26 }
27 
push_log(const char * input_log,int input_log_size)28 unsigned int push_log(const char *input_log, int input_log_size)
29 {
30     unsigned int len = 0;
31 
32     if (NULL == current_log_pos || NULL == input_log || input_log_size <= 0) {
33         dm_log_debug("invalid params");
34         return -1;
35     }
36     memcpy(current_log_pos, input_log, input_log_size);
37     current_log_pos += input_log_size;
38     len = current_log_pos - g_log_poll;
39 
40     return len;
41 }
42 
add_tail()43 unsigned int add_tail()
44 {
45     const char *tail = "]}";
46     current_log_pos -= 1;
47     return push_log(tail, strlen(tail));
48 }
49 
add_log_header()50 void add_log_header()
51 {
52     const char *subprefix =
53         "{\"template\": \"traceContext logContent\",\"contents\":[";
54     int sublen = strlen(subprefix);
55     push_log(subprefix, sublen);
56 }
57 
reset_log_poll()58 int reset_log_poll()
59 {
60     if (NULL == g_log_poll) {
61         dm_log_err("log buffer is NULL");
62         return -1;
63     }
64     memset(g_log_poll, 0, LOG_POLL_SIZE);
65     current_log_pos = g_log_poll;
66     add_log_header();
67     return 0;
68 }
69 
create_log_poll()70 int create_log_poll()
71 {
72     int ret;
73     remove_log_poll();
74     g_log_poll = HAL_Malloc(LOG_POLL_SIZE);
75     ret = reset_log_poll();
76     return ret;
77 }
78 
79 static int switch_status = 0; /* 0 for switch off; 1 for switch on */
80 static unsigned int sample_interval = 5;
81 static unsigned int sample_count = 1000;
82 
83 #define MSG_ID_LEN (64)
84 char msg_array[MSG_ID_LEN] = { 0 };
check_target_msg(const char * input,int len)85 int check_target_msg(const char *input, int len)
86 {
87     /* do not upload log when swith is off */
88     if (0 == switch_status) {
89         return -1;
90     }
91     if (NULL == input || len <= 0) {
92         dm_log_err("invalid params");
93         return -1;
94     }
95     return strncmp(input, msg_array, len);
96 }
97 
98 static unsigned int msg_num = 0;
99 /* return 0 for success; -1 for failure */
set_target_msg(const char * input,int len)100 int set_target_msg(const char *input, int len)
101 {
102     if (0 == switch_status) {
103         return -1;
104     }
105     if ((msg_num % sample_interval == 0) && (msg_num < sample_count)) {
106         if (NULL == input || len <= 0) {
107             dm_log_err("invalid params");
108             return -1;
109         }
110         strncpy(msg_array, input, len);
111         return 0;
112     }
113     return -1;
114 }
115 
parse_msg_id(_IN_ char * payload,_IN_ int payload_len,_OU_ dm_msg_request_payload_t * request)116 void parse_msg_id(_IN_ char *payload, _IN_ int payload_len,
117                   _OU_ dm_msg_request_payload_t *request)
118 {
119     lite_cjson_t lite;
120 
121     if (payload == NULL || payload_len <= 0 || request == NULL) {
122         return;
123     }
124 
125     dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite);
126     dm_utils_json_object_item(&lite, DM_MSG_KEY_ID, strlen(DM_MSG_KEY_ID),
127                               cJSON_String, &request->id);
128 }
129 
stop_sample()130 int stop_sample()
131 {
132     if (current_log_pos > g_log_poll) {
133         dm_mgr_upstream_thing_log_post(0, NULL, 0, 1);
134     }
135     switch_status = 0;
136     dm_log_info("stop sample");
137     return remove_log_poll();
138 }
139 
parse_switch_info(_IN_ char * payload,_IN_ int payload_len)140 void parse_switch_info(_IN_ char *payload, _IN_ int payload_len)
141 {
142     lite_cjson_t lite, lite_sample_count, lite_sample_interval,
143         lite_sample_target;
144     const char *c1 = "Count";
145     const char *c2 = "Interval";
146     const char *c3 = "ProfileTarget";
147     char *sample_target;
148     int sample_target_len;
149     const char *target = "propSet";
150     int ret = -1;
151 
152     if (payload == NULL || payload_len <= 0) {
153         return;
154     }
155     dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite);
156     ret = lite_cjson_object_item(&lite, c1, strlen(c1), &lite_sample_count);
157     if (ret < SUCCESS_RETURN) {
158         return;
159     }
160 
161     ret = lite_cjson_object_item(&lite, c2, strlen(c2), &lite_sample_interval);
162     if (ret < SUCCESS_RETURN) {
163         return;
164     }
165 
166     ret = lite_cjson_object_item(&lite, c3, strlen(c3), &lite_sample_target);
167     if (ret < SUCCESS_RETURN) {
168         return;
169     }
170 
171     sample_count = lite_sample_count.value_int;
172     sample_interval = lite_sample_interval.value_int;
173     sample_target = lite_sample_target.value;
174     sample_target_len = lite_sample_target.value_length;
175     dm_log_info("switch count is %d, interval is %d, target is %.*s\n",
176                 sample_count, sample_interval, sample_target_len,
177                 sample_target);
178     /* if the target is not property set, return */
179     if (0 != strncmp(sample_target, target, sample_target_len)) {
180         dm_log_info("target is not propSet, return\n");
181         return;
182     }
183     if (sample_interval <= 0) {
184         dm_log_err("invalid sample interval\n");
185         return;
186     }
187     msg_num = 0;
188     /* when it switch off, force upload the remaining log */
189     if (0 == sample_count) {
190         ret = stop_sample();
191     } else {
192         switch_status = 1;
193         ret = create_log_poll();
194     }
195 
196     dm_log_info("log switch run status is %d\n", ret);
197 }
198 
199 REPORT_STATE g_report_status = READY;
200 
send_permance_info(char * input,int input_len,char * comments,int report_format)201 void send_permance_info(char *input, int input_len, char *comments,
202                         int report_format)
203 {
204 #define LOCAL_POST_LEN (150)
205     char data[LOCAL_POST_LEN] = { 0 };
206     const char *format = NULL;
207     if (0 == switch_status) {
208         return;
209     }
210 
211     switch (report_format) {
212     case 0:
213         if (NULL == input || input_len <= 0) {
214             dm_log_err("invalid params");
215             return;
216         }
217         format = THING_LOG_POST_PARAMS_HEAD;
218         HAL_Snprintf(data, sizeof(data), format, input_len, input, comments,
219                      (long)HAL_UptimeMs());
220         break;
221     case 1:
222         format = THING_LOG_POST_PARAMS_BODY;
223         HAL_Snprintf(data, sizeof(data), format, comments,
224                      (long)HAL_UptimeMs());
225         break;
226     case 2:
227         format = THING_LOG_POST_PARAMS_END;
228         HAL_Snprintf(data, sizeof(data), format, comments,
229                      (long)HAL_UptimeMs());
230         g_report_status = DONE;
231         break;
232     default:
233         return;
234     }
235     iotx_dm_log_post(0, data, strlen((const char *)data));
236     if (2 == report_format) {
237         g_report_status = READY;
238     }
239 }
240 
get_msgid(char * payload,int is_cloud)241 void get_msgid(char *payload, int is_cloud)
242 {
243     const char *interest = "\"method\":\"thing.service.property.set";
244     char *found;
245     dm_msg_request_payload_t request;
246     if (0 == switch_status || NULL == payload) {
247         return;
248     }
249 
250     found = strstr(payload, interest);
251     if (NULL == found) {
252         return;
253     }
254     found = strstr(payload, "{");
255     if (NULL == found) {
256         return;
257     }
258     msg_num++;
259     parse_msg_id(found, strlen(found), &request);
260     if (RUNNING == g_report_status) {
261         dm_log_info("current working on a sample, return");
262         return;
263     }
264 
265     if (sample_count <= msg_num) {
266         stop_sample();
267         return;
268     }
269 
270     /* if it does not meet the sample conditions, do NOT take sample */
271     if (SUCCESS_RETURN !=
272         set_target_msg(request.id.value, request.id.value_length)) {
273         return;
274     }
275 
276     g_report_status = RUNNING;
277 
278     if (1 == is_cloud) {
279         send_permance_info(request.id.value, request.id.value_length, "1_cloud",
280                            0);
281     } else if (0 == is_cloud) {
282         send_permance_info(request.id.value, request.id.value_length, "1_alcs",
283                            0);
284     }
285 }
286 #endif
287