/src/open5gs/lib/core/ogs-time.c
Line | Count | Source |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | /* |
18 | | * Copyright 2013 MongoDB, Inc. |
19 | | * |
20 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
21 | | * you may not use this file except in compliance with the License. |
22 | | * You may obtain a copy of the License at |
23 | | * |
24 | | * http://www.apache.org/licenses/LICENSE-2.0 |
25 | | * |
26 | | * Unless required by applicable law or agreed to in writing, software |
27 | | * distributed under the License is distributed on an "AS IS" BASIS, |
28 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
29 | | * See the License for the specific language governing permissions and |
30 | | * limitations under the License. |
31 | | */ |
32 | | |
33 | | /* |
34 | | * Copyright Beman Dawes 2008 |
35 | | * Copyright 2009-2010 Vicente J. Botet Escriba |
36 | | * |
37 | | * Distributed under the Boost Software License, Version 1.0. |
38 | | * See http://www.boost.org/LICENSE_1_0.txt |
39 | | */ |
40 | | |
41 | | /* |
42 | | * Copyright (C) 2019-2020 by Sukchan Lee <acetcom@gmail.com> |
43 | | * |
44 | | * This file is part of Open5GS. |
45 | | * |
46 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
47 | | * you may not use this file except in compliance with the License. |
48 | | * You may obtain a copy of the License at |
49 | | * |
50 | | * http://www.apache.org/licenses/LICENSE-2.0 |
51 | | * |
52 | | * Unless required by applicable law or agreed to in writing, software |
53 | | * distributed under the License is distributed on an "AS IS" BASIS, |
54 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
55 | | * See the License for the specific language governing permissions and |
56 | | * limitations under the License. |
57 | | */ |
58 | | |
59 | | #ifdef __APPLE__ |
60 | | #include <mach/clock.h> |
61 | | #include <mach/mach.h> |
62 | | #include <mach/mach_time.h> |
63 | | #endif |
64 | | |
65 | | #include "core-config-private.h" |
66 | | |
67 | | #include "ogs-core.h" |
68 | | |
69 | | /* |
70 | | * The following code is stolen from mongodb-c-driver |
71 | | * https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-clock.c |
72 | | */ |
73 | | int ogs_gettimeofday(struct timeval *tv) |
74 | 6.83k | { |
75 | | #if defined(_WIN32) |
76 | | #if defined(_MSC_VER) |
77 | | #define DELTA_EPOCH_IN_MICROSEC 11644473600000000Ui64 |
78 | | #else |
79 | | #define DELTA_EPOCH_IN_MICROSEC 11644473600000000ULL |
80 | | #endif |
81 | | FILETIME ft; |
82 | | uint64_t tmp = 0; |
83 | | |
84 | | /* |
85 | | * The const value is shamelessy stolen from |
86 | | * http://www.boost.org/doc/libs/1_55_0/boost/chrono/detail/inlined/win/chrono.hpp |
87 | | * |
88 | | * File times are the number of 100 nanosecond intervals elapsed since |
89 | | * 12:00 am Jan 1, 1601 UTC. I haven't check the math particularly hard |
90 | | * |
91 | | * ... good luck |
92 | | */ |
93 | | |
94 | | if (tv) { |
95 | | GetSystemTimeAsFileTime (&ft); |
96 | | |
97 | | /* pull out of the filetime into a 64 bit uint */ |
98 | | tmp |= ft.dwHighDateTime; |
99 | | tmp <<= 32; |
100 | | tmp |= ft.dwLowDateTime; |
101 | | |
102 | | /* convert from 100's of nanosecs to microsecs */ |
103 | | tmp /= 10; |
104 | | |
105 | | /* adjust to unix epoch */ |
106 | | tmp -= DELTA_EPOCH_IN_MICROSEC; |
107 | | |
108 | | tv->tv_sec = (long) (tmp / 1000000UL); |
109 | | tv->tv_usec = (long) (tmp % 1000000UL); |
110 | | } |
111 | | |
112 | | return 0; |
113 | | #else |
114 | 6.83k | int rc = gettimeofday(tv, NULL); |
115 | 6.83k | ogs_assert(rc == 0); |
116 | 6.83k | return 0; |
117 | 6.83k | #endif |
118 | 6.83k | } |
119 | | |
120 | | ogs_time_t ogs_time_now(void) |
121 | 0 | { |
122 | 0 | int rc; |
123 | 0 | struct timeval tv; |
124 | |
|
125 | 0 | rc = ogs_gettimeofday(&tv); |
126 | 0 | ogs_assert(rc == 0); |
127 | | |
128 | 0 | return ogs_time_from_sec(tv.tv_sec) + tv.tv_usec; |
129 | 0 | } |
130 | | |
131 | | /* The following code is stolen from APR library */ |
132 | | int ogs_time_from_lt(ogs_time_t *t, struct tm *tm, int tm_usec) |
133 | 0 | { |
134 | 0 | ogs_time_t year = tm->tm_year; |
135 | 0 | ogs_time_t days; |
136 | 0 | static const int dayoffset[12] = |
137 | 0 | {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; |
138 | |
|
139 | 0 | if (tm->tm_mon < 0 || tm->tm_mon >= 12) |
140 | 0 | return OGS_ERROR; |
141 | | |
142 | | /* shift new year to 1st March in order to make leap year calc easy */ |
143 | | |
144 | 0 | if (tm->tm_mon < 2) |
145 | 0 | year--; |
146 | | |
147 | | /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ |
148 | |
|
149 | 0 | days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4; |
150 | 0 | days += dayoffset[tm->tm_mon] + tm->tm_mday - 1; |
151 | 0 | days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ |
152 | 0 | days = ((days * 24 + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; |
153 | |
|
154 | 0 | if (days < 0) { |
155 | 0 | return OGS_ERROR; |
156 | 0 | } |
157 | 0 | *t = days * OGS_USEC_PER_SEC + tm_usec; |
158 | |
|
159 | 0 | return OGS_OK; |
160 | 0 | } |
161 | | |
162 | | int ogs_time_from_gmt(ogs_time_t *t, struct tm *tm, int tm_usec) |
163 | 0 | { |
164 | 0 | int status = ogs_time_from_lt(t, tm, tm_usec); |
165 | 0 | if (status == OGS_OK) |
166 | 0 | *t -= (ogs_time_t) tm->tm_gmtoff * OGS_USEC_PER_SEC; |
167 | 0 | return status; |
168 | 0 | } |
169 | | |
170 | | /* RFC 5905 A.1.1, A.4 |
171 | | * PFCP entity uses NTP timestamp(1900), but Open5GS uses UNIX(1970). |
172 | | * |
173 | | * One is the offset between the two epochs. |
174 | | * Unix uses an epoch located at 1/1/1970-00:00h (UTC) and |
175 | | * NTP uses 1/1/1900-00:00h. This leads to an offset equivalent |
176 | | * to 70 years in seconds (there are 17 leap years |
177 | | * between the two dates so the offset is |
178 | | * |
179 | | * (70*365 + 17)*86400 = 2208988800 |
180 | | * |
181 | | * to be substracted from NTP time to get Unix struct timeval. |
182 | | */ |
183 | | uint32_t ogs_time_ntp32_now(void) |
184 | 0 | { |
185 | 0 | int rc; |
186 | 0 | struct timeval tv; |
187 | |
|
188 | 0 | rc = ogs_gettimeofday(&tv); |
189 | 0 | ogs_assert(rc == 0); |
190 | | |
191 | 0 | return ogs_time_to_ntp32(ogs_time_from_sec(tv.tv_sec) + tv.tv_usec); |
192 | 0 | } |
193 | | ogs_time_t ogs_time_from_ntp32(uint32_t ntp_timestamp) |
194 | 0 | { |
195 | 0 | if (ntp_timestamp < OGS_1970_1900_SEC_DIFF) |
196 | 0 | return 0; |
197 | 0 | return ogs_time_from_sec(ntp_timestamp - OGS_1970_1900_SEC_DIFF); |
198 | 0 | } |
199 | | uint32_t ogs_time_to_ntp32(ogs_time_t time) |
200 | 0 | { |
201 | 0 | return (time / OGS_USEC_PER_SEC) + OGS_1970_1900_SEC_DIFF; |
202 | 0 | } |
203 | | |
204 | | int ogs_timezone(void) |
205 | 0 | { |
206 | | #if defined(_WIN32) |
207 | | u_long n; |
208 | | TIME_ZONE_INFORMATION tz; |
209 | | |
210 | | n = GetTimeZoneInformation(&tz); |
211 | | |
212 | | switch (n) { |
213 | | case TIME_ZONE_ID_UNKNOWN: |
214 | | /* Bias = UTC - local time in minutes |
215 | | * tm_gmtoff is seconds east of UTC |
216 | | */ |
217 | | return tz.Bias * -60; |
218 | | case TIME_ZONE_ID_STANDARD: |
219 | | return (tz.Bias + tz.StandardBias) * -60; |
220 | | case TIME_ZONE_ID_DAYLIGHT: |
221 | | return (tz.Bias + tz.DaylightBias) * -60; |
222 | | default: |
223 | | ogs_assert_if_reached(); |
224 | | return 0; |
225 | | } |
226 | | #else |
227 | 0 | struct timeval tv; |
228 | 0 | struct tm tm; |
229 | 0 | int ret; |
230 | |
|
231 | 0 | ret = ogs_gettimeofday(&tv); |
232 | 0 | ogs_assert(ret == 0); |
233 | | |
234 | 0 | ogs_localtime(tv.tv_sec, &tm); |
235 | |
|
236 | 0 | return tm.tm_gmtoff; |
237 | 0 | #endif |
238 | 0 | } |
239 | | |
240 | | ogs_time_t ogs_get_monotonic_time(void) |
241 | 6 | { |
242 | 6 | #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) |
243 | 6 | struct timespec ts; |
244 | 6 | clock_gettime(CLOCK_MONOTONIC, &ts); |
245 | 6 | return ogs_time_from_sec(ts.tv_sec) + ts.tv_nsec / 1000UL; |
246 | | #elif defined(__APPLE__) |
247 | | static mach_timebase_info_data_t info = {0}; |
248 | | static double ratio = 0.0; |
249 | | |
250 | | if (!info.denom) { |
251 | | /* the value from mach_absolute_time () * info.numer / info.denom |
252 | | * is in nano seconds. So we have to divid by 1000.0 to get micro |
253 | | * seconds*/ |
254 | | mach_timebase_info(&info); |
255 | | ratio = (double) info.numer / (double) info.denom / 1000.0; |
256 | | } |
257 | | |
258 | | return mach_absolute_time() * ratio; |
259 | | #elif defined(_WIN32) |
260 | | /* Despite it's name, this is in milliseconds! */ |
261 | | ogs_time_t ticks = GetTickCount64(); |
262 | | return (ticks * 1000L); |
263 | | #elif defined(__hpux__) |
264 | | ogs_time_t nanosec = gethrtime(); |
265 | | return (nanosec / 1000UL); |
266 | | #else |
267 | | #warning "Monotonic clock is not yet supported on your platform." |
268 | | struct timeval tv; |
269 | | |
270 | | ogs_gettimeofday(&tv); |
271 | | return ogs_time_from_sec(tv.tv_sec) + tv.tv_usec; |
272 | | #endif |
273 | 6 | } |
274 | | |
275 | | void ogs_localtime(time_t s, struct tm *tm) |
276 | 6.83k | { |
277 | 6.83k | ogs_assert(tm); |
278 | 6.83k | memset(tm, 0, sizeof(*tm)); |
279 | | |
280 | 6.83k | #if (HAVE_LOCALTIME_R) |
281 | 6.83k | (void)localtime_r(&s, tm); |
282 | | #else |
283 | | struct tm *t; |
284 | | |
285 | | t = localtime(&s); |
286 | | *tm = *t; |
287 | | #endif |
288 | 6.83k | } |
289 | | |
290 | | void ogs_gmtime(time_t s, struct tm *tm) |
291 | 0 | { |
292 | 0 | ogs_assert(tm); |
293 | 0 | memset(tm, 0, sizeof(*tm)); |
294 | |
|
295 | 0 | #if (HAVE_LOCALTIME_R) |
296 | 0 | (void)gmtime_r(&s, tm); |
297 | | #else |
298 | | struct tm *t; |
299 | | |
300 | | t = gmtime(&s); |
301 | | *tm = *t; |
302 | | #endif |
303 | 0 | } |
304 | | |
305 | | void ogs_msleep(time_t msec) |
306 | 0 | { |
307 | | #if defined(_WIN32) |
308 | | Sleep(msec); |
309 | | #else |
310 | 0 | ogs_usleep(msec * 1000); |
311 | 0 | #endif |
312 | 0 | } |
313 | | |
314 | | void ogs_usleep(time_t usec) |
315 | 0 | { |
316 | | #if defined(_WIN32) |
317 | | Sleep(usec ? (1 + (usec - 1) / 1000) : 0); |
318 | | #else |
319 | 0 | struct timespec req, rem; |
320 | 0 | req.tv_sec = usec / OGS_USEC_PER_SEC; |
321 | 0 | req.tv_nsec = (usec % OGS_USEC_PER_SEC) * 1000; |
322 | 0 | while (nanosleep(&req, &rem) == -1 && errno == EINTR) |
323 | 0 | req = rem; |
324 | 0 | #endif |
325 | 0 | } |