/src/fluent-bit/src/flb_time.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2015-2022 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include "cmetrics/lib/mpack/src/mpack/mpack.h" |
21 | | #include <msgpack.h> |
22 | | #include <mpack/mpack.h> |
23 | | #include <fluent-bit/flb_compat.h> |
24 | | #include <fluent-bit/flb_macros.h> |
25 | | #include <fluent-bit/flb_log.h> |
26 | | #include <fluent-bit/flb_time.h> |
27 | | #include <stdint.h> |
28 | | #ifdef FLB_HAVE_CLOCK_GET_TIME |
29 | | # include <mach/clock.h> |
30 | | # include <mach/mach.h> |
31 | | #endif |
32 | | |
33 | | #include <string.h> |
34 | | #include <inttypes.h> |
35 | | #include <time.h> |
36 | | |
37 | 0 | #define ONESEC_IN_NSEC 1000000000 |
38 | | |
39 | | static int is_valid_format(int fmt) |
40 | 0 | { |
41 | 0 | return (FLB_TIME_ETFMT_INT <= fmt) && (fmt < FLB_TIME_ETFMT_OTHER) ? |
42 | 0 | FLB_TRUE : FLB_FALSE; |
43 | 0 | } |
44 | | |
45 | | static int _flb_time_get(struct flb_time *tm) |
46 | 0 | { |
47 | 0 | if (tm == NULL) { |
48 | 0 | return -1; |
49 | 0 | } |
50 | | #if defined FLB_TIME_FORCE_FMT_INT |
51 | | tm->tm.tv_sec = time(NULL); |
52 | | tm->tm.tv_nsec = 0; |
53 | | return 0; |
54 | | #elif defined FLB_HAVE_TIMESPEC_GET |
55 | | /* C11 supported! */ |
56 | 0 | return timespec_get(&tm->tm, TIME_UTC); |
57 | | #elif defined FLB_CLOCK_GET_TIME |
58 | | clock_serv_t cclock; |
59 | | mach_timespec_t mts; |
60 | | host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); |
61 | | clock_get_time(cclock, &mts); |
62 | | tm->tv_sec = mts.tv_sec; |
63 | | tm->tv_nsec = mts.tv_nsec; |
64 | | return mach_port_deallocate(mach_task_self(), cclock); |
65 | | #else /* __STDC_VERSION__ */ |
66 | | return clock_gettime(CLOCK_REALTIME, &tm->tm); |
67 | | #endif |
68 | 0 | } |
69 | | |
70 | | int flb_time_get(struct flb_time *tm) |
71 | 0 | { |
72 | 0 | return _flb_time_get(tm); |
73 | 0 | } |
74 | | |
75 | | /* A portable function to sleep N msec */ |
76 | | int flb_time_msleep(uint32_t ms) |
77 | 0 | { |
78 | | #ifdef _MSC_VER |
79 | | Sleep((DWORD) ms); |
80 | | return 0; |
81 | | #else |
82 | 0 | struct timespec ts; |
83 | 0 | ts.tv_sec = ms / 1000; |
84 | 0 | ts.tv_nsec = (ms % 1000) * 1000000; |
85 | 0 | return nanosleep(&ts, NULL); |
86 | 0 | #endif |
87 | 0 | } |
88 | | |
89 | | double flb_time_to_double(struct flb_time *tm) |
90 | 0 | { |
91 | 0 | return (double)(tm->tm.tv_sec) + ((double)tm->tm.tv_nsec/(double)ONESEC_IN_NSEC); |
92 | 0 | } |
93 | | |
94 | | uint64_t flb_time_to_nanosec(struct flb_time *tm) |
95 | 0 | { |
96 | 0 | return (((uint64_t)tm->tm.tv_sec * 1000000000L) + tm->tm.tv_nsec); |
97 | 0 | } |
98 | | |
99 | | uint64_t flb_time_to_millisec(struct flb_time *tm) |
100 | 0 | { |
101 | 0 | return (((uint64_t)tm->tm.tv_sec * 1000L) + tm->tm.tv_nsec / 1000000L); |
102 | 0 | } |
103 | | |
104 | | int flb_time_add(struct flb_time *base, struct flb_time *duration, struct flb_time *result) |
105 | 0 | { |
106 | 0 | if (base == NULL || duration == NULL|| result == NULL) { |
107 | 0 | return -1; |
108 | 0 | } |
109 | 0 | result->tm.tv_sec = base->tm.tv_sec + duration->tm.tv_sec; |
110 | 0 | result->tm.tv_nsec = base->tm.tv_nsec + duration->tm.tv_nsec; |
111 | |
|
112 | 0 | if (result->tm.tv_nsec > ONESEC_IN_NSEC) { |
113 | 0 | result->tm.tv_nsec -= ONESEC_IN_NSEC; |
114 | 0 | result->tm.tv_sec++; |
115 | 0 | } else if (result->tm.tv_nsec < 0) { |
116 | 0 | result->tm.tv_nsec += ONESEC_IN_NSEC; |
117 | 0 | result->tm.tv_sec--; |
118 | 0 | } |
119 | |
|
120 | 0 | return 0; |
121 | 0 | } |
122 | | |
123 | | int flb_time_diff(struct flb_time *time1, |
124 | | struct flb_time *time0,struct flb_time *result) |
125 | 0 | { |
126 | 0 | if (time1 == NULL || time0 == NULL || result == NULL) { |
127 | 0 | return -1; |
128 | 0 | } |
129 | | |
130 | 0 | if (time1->tm.tv_sec >= time0->tm.tv_sec) { |
131 | 0 | result->tm.tv_sec = time1->tm.tv_sec - time0->tm.tv_sec; |
132 | 0 | if (time1->tm.tv_nsec >= time0->tm.tv_nsec) { |
133 | 0 | result->tm.tv_nsec = time1->tm.tv_nsec - time0->tm.tv_nsec; |
134 | 0 | } |
135 | 0 | else if(result->tm.tv_sec == 0){ |
136 | | /* underflow */ |
137 | 0 | return -1; |
138 | 0 | } |
139 | 0 | else{ |
140 | 0 | result->tm.tv_nsec = ONESEC_IN_NSEC |
141 | 0 | + time1->tm.tv_nsec - time0->tm.tv_nsec; |
142 | 0 | result->tm.tv_sec--; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | else { |
146 | | /* underflow */ |
147 | 0 | return -1; |
148 | 0 | } |
149 | 0 | return 0; |
150 | 0 | } |
151 | | |
152 | | int flb_time_append_to_mpack(mpack_writer_t *writer, struct flb_time *tm, int fmt) |
153 | 0 | { |
154 | 0 | int ret = 0; |
155 | 0 | struct flb_time l_time; |
156 | 0 | char ext_data[8]; |
157 | 0 | uint32_t tmp; |
158 | |
|
159 | 0 | if (!is_valid_format(fmt)) { |
160 | | #ifdef FLB_TIME_FORCE_FMT_INT |
161 | | fmt = FLB_TIME_ETFMT_INT; |
162 | | #else |
163 | 0 | fmt = FLB_TIME_ETFMT_V1_FIXEXT; |
164 | 0 | #endif |
165 | 0 | } |
166 | |
|
167 | 0 | if (tm == NULL) { |
168 | 0 | if (fmt == FLB_TIME_ETFMT_INT) { |
169 | 0 | l_time.tm.tv_sec = time(NULL); |
170 | 0 | } |
171 | 0 | else { |
172 | 0 | _flb_time_get(&l_time); |
173 | 0 | } |
174 | 0 | tm = &l_time; |
175 | 0 | } |
176 | |
|
177 | 0 | switch(fmt) { |
178 | 0 | case FLB_TIME_ETFMT_INT: |
179 | 0 | mpack_write_uint(writer, tm->tm.tv_sec); |
180 | 0 | break; |
181 | | |
182 | 0 | case FLB_TIME_ETFMT_V0: |
183 | 0 | case FLB_TIME_ETFMT_V1_EXT: |
184 | | /* We can't set with msgpack-c !! */ |
185 | | /* see pack_template.h and msgpack_pack_inline_func(_ext) */ |
186 | 0 | case FLB_TIME_ETFMT_V1_FIXEXT: |
187 | 0 | tmp = htonl((uint32_t)tm->tm.tv_sec); /* second from epoch */ |
188 | 0 | memcpy(&ext_data, &tmp, 4); |
189 | 0 | tmp = htonl((uint32_t)tm->tm.tv_nsec);/* nanosecond */ |
190 | 0 | memcpy(&ext_data[4], &tmp, 4); |
191 | | |
192 | | /* https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#eventtime-ext-format */ |
193 | 0 | mpack_write_ext(writer, 0 /*ext type=0 */, ext_data, sizeof(ext_data)); |
194 | 0 | break; |
195 | | |
196 | 0 | default: |
197 | 0 | ret = -1; |
198 | 0 | } |
199 | | |
200 | 0 | return ret; |
201 | 0 | } |
202 | | |
203 | | int flb_time_append_to_msgpack(struct flb_time *tm, msgpack_packer *pk, int fmt) |
204 | 0 | { |
205 | 0 | int ret = 0; |
206 | 0 | struct flb_time l_time; |
207 | 0 | char ext_data[8]; |
208 | 0 | uint32_t tmp; |
209 | |
|
210 | 0 | if (!is_valid_format(fmt)) { |
211 | | #ifdef FLB_TIME_FORCE_FMT_INT |
212 | | fmt = FLB_TIME_ETFMT_INT; |
213 | | #else |
214 | 0 | fmt = FLB_TIME_ETFMT_V1_FIXEXT; |
215 | 0 | #endif |
216 | 0 | } |
217 | |
|
218 | 0 | if (tm == NULL) { |
219 | 0 | if (fmt == FLB_TIME_ETFMT_INT) { |
220 | 0 | l_time.tm.tv_sec = time(NULL); |
221 | 0 | } |
222 | 0 | else { |
223 | 0 | _flb_time_get(&l_time); |
224 | 0 | } |
225 | 0 | tm = &l_time; |
226 | 0 | } |
227 | |
|
228 | 0 | switch(fmt) { |
229 | 0 | case FLB_TIME_ETFMT_INT: |
230 | 0 | msgpack_pack_uint64(pk, tm->tm.tv_sec); |
231 | 0 | break; |
232 | | |
233 | 0 | case FLB_TIME_ETFMT_V0: |
234 | 0 | case FLB_TIME_ETFMT_V1_EXT: |
235 | | /* We can't set with msgpack-c !! */ |
236 | | /* see pack_template.h and msgpack_pack_inline_func(_ext) */ |
237 | 0 | case FLB_TIME_ETFMT_V1_FIXEXT: |
238 | 0 | tmp = htonl((uint32_t)tm->tm.tv_sec); /* second from epoch */ |
239 | 0 | memcpy(&ext_data, &tmp, 4); |
240 | 0 | tmp = htonl((uint32_t)tm->tm.tv_nsec);/* nanosecond */ |
241 | 0 | memcpy(&ext_data[4], &tmp, 4); |
242 | |
|
243 | 0 | msgpack_pack_ext(pk, 8/*fixext8*/, 0); |
244 | 0 | msgpack_pack_ext_body(pk, ext_data, sizeof(ext_data)); |
245 | |
|
246 | 0 | break; |
247 | | |
248 | 0 | default: |
249 | 0 | ret = -1; |
250 | 0 | } |
251 | | |
252 | 0 | return ret; |
253 | 0 | } |
254 | | |
255 | | static inline int is_eventtime(msgpack_object *obj) |
256 | 0 | { |
257 | 0 | if (obj->via.ext.type != 0 || obj->via.ext.size != 8) { |
258 | 0 | return FLB_FALSE; |
259 | 0 | } |
260 | 0 | return FLB_TRUE; |
261 | 0 | } |
262 | | |
263 | | int flb_time_msgpack_to_time(struct flb_time *time, msgpack_object *obj) |
264 | 0 | { |
265 | 0 | uint32_t tmp; |
266 | |
|
267 | 0 | switch(obj->type) { |
268 | 0 | case MSGPACK_OBJECT_POSITIVE_INTEGER: |
269 | 0 | time->tm.tv_sec = obj->via.u64; |
270 | 0 | time->tm.tv_nsec = 0; |
271 | 0 | break; |
272 | 0 | case MSGPACK_OBJECT_FLOAT: |
273 | 0 | time->tm.tv_sec = obj->via.f64; |
274 | 0 | time->tm.tv_nsec = ((obj->via.f64 - time->tm.tv_sec) * ONESEC_IN_NSEC); |
275 | 0 | break; |
276 | 0 | case MSGPACK_OBJECT_EXT: |
277 | 0 | if (is_eventtime(obj) != FLB_TRUE) { |
278 | 0 | flb_warn("[time] unknown ext type. type=%d size=%d", |
279 | 0 | obj->via.ext.type, obj->via.ext.size); |
280 | 0 | return -1; |
281 | 0 | } |
282 | 0 | memcpy(&tmp, &obj->via.ext.ptr[0], 4); |
283 | 0 | time->tm.tv_sec = (uint32_t) ntohl(tmp); |
284 | 0 | memcpy(&tmp, &obj->via.ext.ptr[4], 4); |
285 | 0 | time->tm.tv_nsec = (uint32_t) ntohl(tmp); |
286 | 0 | break; |
287 | 0 | default: |
288 | 0 | flb_warn("unknown time format %x", obj->type); |
289 | 0 | return -1; |
290 | 0 | } |
291 | | |
292 | 0 | return 0; |
293 | 0 | } |
294 | | |
295 | | int flb_time_pop_from_mpack(struct flb_time *time, mpack_reader_t *reader) |
296 | 0 | { |
297 | 0 | mpack_tag_t tag; |
298 | 0 | double d; |
299 | 0 | float f; |
300 | 0 | int64_t i; |
301 | 0 | uint32_t tmp; |
302 | 0 | char extbuf[8]; |
303 | 0 | size_t ext_len; |
304 | |
|
305 | 0 | if (time == NULL) { |
306 | 0 | return -1; |
307 | 0 | } |
308 | | |
309 | 0 | tag = mpack_read_tag(reader); |
310 | |
|
311 | 0 | if (mpack_reader_error(reader) != mpack_ok || |
312 | 0 | mpack_tag_type(&tag) != mpack_type_array || |
313 | 0 | mpack_tag_array_count(&tag) == 0) { |
314 | 0 | return -1; |
315 | 0 | } |
316 | | |
317 | 0 | tag = mpack_read_tag(reader); |
318 | 0 | switch (mpack_tag_type(&tag)) { |
319 | 0 | case mpack_type_int: |
320 | 0 | i = mpack_tag_int_value(&tag); |
321 | 0 | if (i < 0) { |
322 | 0 | flb_warn("expecting positive integer, got %" PRId64, i); |
323 | 0 | return -1; |
324 | 0 | } |
325 | 0 | time->tm.tv_sec = i; |
326 | 0 | time->tm.tv_nsec = 0; |
327 | 0 | break; |
328 | 0 | case mpack_type_uint: |
329 | 0 | time->tm.tv_sec = mpack_tag_uint_value(&tag); |
330 | 0 | time->tm.tv_nsec = 0; |
331 | 0 | break; |
332 | 0 | case mpack_type_float: |
333 | 0 | f = mpack_tag_float_value(&tag); |
334 | 0 | time->tm.tv_sec = f; |
335 | 0 | time->tm.tv_nsec = ((f - time->tm.tv_sec) * ONESEC_IN_NSEC); |
336 | 0 | case mpack_type_double: |
337 | 0 | d = mpack_tag_double_value(&tag); |
338 | 0 | time->tm.tv_sec = d; |
339 | 0 | time->tm.tv_nsec = ((d - time->tm.tv_sec) * ONESEC_IN_NSEC); |
340 | 0 | break; |
341 | 0 | case mpack_type_ext: |
342 | 0 | ext_len = mpack_tag_ext_length(&tag); |
343 | 0 | if (ext_len != 8) { |
344 | 0 | flb_warn("expecting ext_len is 8, got %" PRId64, ext_len); |
345 | 0 | return -1; |
346 | 0 | } |
347 | 0 | mpack_read_bytes(reader, extbuf, ext_len); |
348 | 0 | memcpy(&tmp, extbuf, 4); |
349 | 0 | time->tm.tv_sec = (uint32_t) ntohl(tmp); |
350 | 0 | memcpy(&tmp, extbuf + 4, 4); |
351 | 0 | time->tm.tv_nsec = (uint32_t) ntohl(tmp); |
352 | 0 | break; |
353 | 0 | default: |
354 | 0 | flb_warn("unknown time format %d", tag.type); |
355 | 0 | return -1; |
356 | 0 | } |
357 | | |
358 | 0 | return 0; |
359 | 0 | } |
360 | | |
361 | | int flb_time_pop_from_msgpack(struct flb_time *time, msgpack_unpacked *upk, |
362 | | msgpack_object **map) |
363 | 0 | { |
364 | 0 | int ret; |
365 | 0 | msgpack_object obj; |
366 | |
|
367 | 0 | if (time == NULL || upk == NULL) { |
368 | 0 | return -1; |
369 | 0 | } |
370 | | |
371 | 0 | if (upk->data.type != MSGPACK_OBJECT_ARRAY) { |
372 | 0 | return -1; |
373 | 0 | } |
374 | | |
375 | 0 | obj = upk->data.via.array.ptr[0]; |
376 | 0 | *map = &upk->data.via.array.ptr[1]; |
377 | |
|
378 | 0 | ret = flb_time_msgpack_to_time(time, &obj); |
379 | 0 | return ret; |
380 | 0 | } |
381 | | |
382 | | long flb_time_tz_offset_to_second() |
383 | 0 | { |
384 | 0 | time_t t = time(NULL); |
385 | 0 | struct tm local = *localtime(&t); |
386 | 0 | struct tm utc = *gmtime(&t); |
387 | |
|
388 | 0 | long diff = ((local.tm_hour - utc.tm_hour) \ |
389 | 0 | * 60 + (local.tm_min - utc.tm_min)) \ |
390 | 0 | * 60L + (local.tm_sec - utc.tm_sec); |
391 | |
|
392 | 0 | int delta_day = local.tm_mday - utc.tm_mday; |
393 | |
|
394 | 0 | if ((delta_day == 1) || (delta_day < -1)) { |
395 | 0 | diff += 24L * 60 * 60; |
396 | 0 | } |
397 | 0 | else if ((delta_day == -1) || (delta_day > 1)) { |
398 | 0 | diff -= 24L * 60 * 60; |
399 | 0 | } |
400 | |
|
401 | 0 | return diff; |
402 | 0 | } |