Coverage Report

Created: 2025-12-31 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}