LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/mqtt - ntputil.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 92.9 % 56 52
Test Date: 2025-03-13 05:38:21 Functions: 50.0 % 2 1

            Line data    Source code
       1              : /* SPDX-License-Identifier: LGPL-2.1-only */
       2              : /**
       3              :  * Copyright (C) 2021 Wook Song <wook16.song@samsung.com>
       4              :  */
       5              : /**
       6              :  * @file    ntputil.c
       7              :  * @date    16 Jul 2021
       8              :  * @brief   NTP utility functions
       9              :  * @see     https://github.com/nnstreamer/nnstreamer
      10              :  * @author  Wook Song <wook16.song@samsung.com>
      11              :  * @bug     No known bugs except for NYI items
      12              :  * @todo    Need to support caching and polling timer mechanism
      13              :  */
      14              : 
      15              : #include <errno.h>
      16              : #include <arpa/inet.h>
      17              : #include <netdb.h>
      18              : #include <stdint.h>
      19              : #include <stdio.h>
      20              : #include <string.h>
      21              : #include <time.h>
      22              : #include <unistd.h>
      23              : 
      24              : #include "ntputil.h"
      25              : 
      26              : /**
      27              :  *******************************************************************
      28              :  * NTP Timestamp Format (https://www.ietf.org/rfc/rfc5905.txt p.12)
      29              :  *  0                   1                   2                   3
      30              :  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      31              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      32              :  * |                            Seconds                            |
      33              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      34              :  * |                            Fraction                           |
      35              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      36              :  *******************************************************************
      37              :  */
      38              : /**
      39              :  * @brief A custom data type to represent NTP timestamp format
      40              :  */
      41              : typedef struct _ntp_timestamp_t
      42              : {
      43              :   uint32_t sec;
      44              :   uint32_t frac;
      45              : } ntp_timestamp_t;
      46              : 
      47              : /**
      48              :  *******************************************************************
      49              :  * NTP Packet Header Format (https://www.ietf.org/rfc/rfc5905.txt p.18)
      50              :  *  0                   1                   2                   3
      51              :  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      52              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      53              :  * |LI | VN  |Mode |    Stratum     |     Poll      |  Precision   |
      54              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      55              :  * |                         Root Delay                            |
      56              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      57              :  * |                         Root Dispersion                       |
      58              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      59              :  * |                          Reference ID                         |
      60              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      61              :  * |                                                               |
      62              :  * +                     Reference Timestamp (64)                  +
      63              :  * |                                                               |
      64              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      65              :  * |                                                               |
      66              :  * +                      Origin Timestamp (64)                    +
      67              :  * |                                                               |
      68              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      69              :  * |                                                               |
      70              :  * +                      Receive Timestamp (64)                   +
      71              :  * |                                                               |
      72              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      73              :  * |                                                               |
      74              :  * +                      Transmit Timestamp (64)                  +
      75              :  * |                                                               |
      76              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      77              :  * |                                                               |
      78              :  * .                                                               .
      79              :  * .                    Extension Field 1 (variable)               .
      80              :  * .                                                               .
      81              :  * |                                                               |
      82              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      83              :  * |                                                               |
      84              :  * .                                                               .
      85              :  * .                    Extension Field 2 (variable)               .
      86              :  * .                                                               .
      87              :  * |                                                               |
      88              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      89              :  * |                          Key Identifier                       |
      90              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      91              :  * |                                                               |
      92              :  * |                            dgst (128)                         |
      93              :  * |                                                               |
      94              :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      95              :  *******************************************************************
      96              :  */
      97              : 
      98              : /**
      99              :  * @brief A custom data type to represent NTP packet header format
     100              :  */
     101              : typedef struct _ntp_packet_t
     102              : {
     103              :   uint8_t li_vn_mode;
     104              :   uint8_t stratum;
     105              :   uint8_t poll;
     106              :   uint8_t precision;
     107              :   uint32_t root_delay;
     108              :   uint32_t root_dispersion;
     109              :   uint32_t ref_id;
     110              :   ntp_timestamp_t ref_ts;
     111              :   ntp_timestamp_t org_ts;
     112              :   ntp_timestamp_t recv_ts;
     113              :   ntp_timestamp_t xmit_ts;
     114              : } ntp_packet_t;
     115              : 
     116              : const uint64_t NTPUTIL_TIMESTAMP_DELTA = 2208988800ULL;
     117              : const double NTPUTIL_MAX_FRAC_DOUBLE = 4294967295.0L;
     118              : const int64_t NTPUTIL_SEC_TO_USEC_MULTIPLIER = 1000000;
     119              : const char NTPUTIL_DEFAULT_HNAME[] = "pool.ntp.org";
     120              : const uint16_t NTPUTIL_DEFAULT_PORT = 123;
     121              : 
     122              : /**
     123              :  * @brief Wrapper function of ntohl.
     124              :  */
     125              : uint32_t
     126            0 : _convert_to_host_byte_order (uint32_t in)
     127              : {
     128            0 :   return ntohl (in);
     129              : }
     130              : 
     131              : /**
     132              :  * @brief Get NTP timestamps from the given or public NTP servers
     133              :  * @param[in] hnums A number of hostname and port pairs. If 0 is given,
     134              :  *                  the NTP server pool will be used.
     135              :  * @param[in] hnames A list of hostname
     136              :  * @param[in] ports A list of port
     137              :  * @return an Unix epoch time as microseconds on success,
     138              :  *         negative values on error
     139              :  */
     140              : int64_t
     141            6 : ntputil_get_epoch (uint32_t hnums, char **hnames, uint16_t * ports)
     142              : {
     143              :   struct sockaddr_in serv_addr;
     144            6 :   struct hostent *srv = NULL;
     145            6 :   struct hostent *default_srv = NULL;
     146            6 :   uint16_t port = -1;
     147            6 :   int32_t sockfd = -1;
     148              :   uint32_t i;
     149              :   int64_t ret;
     150              : 
     151            6 :   sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     152            6 :   if (sockfd < 0) {
     153            0 :     ret = -1;
     154            0 :     goto ret_normal;
     155              :   }
     156              : 
     157            6 :   for (i = 0; i < hnums; ++i) {
     158            1 :     srv = gethostbyname (hnames[i]);
     159            1 :     if (srv != NULL) {
     160            1 :       port = ports[i];
     161            1 :       break;
     162              :     }
     163              :   }
     164              : 
     165            6 :   if (srv == NULL) {
     166            5 :     default_srv = gethostbyname (NTPUTIL_DEFAULT_HNAME);
     167            5 :     if (default_srv == NULL) {
     168            1 :       ret = -h_errno;
     169            1 :       goto ret_close_sockfd;
     170              :     }
     171            4 :     srv = default_srv;
     172            4 :     port = NTPUTIL_DEFAULT_PORT;
     173              :   }
     174              : 
     175            5 :   memset (&serv_addr, 0, sizeof (serv_addr));
     176            5 :   serv_addr.sin_family = AF_INET;
     177            5 :   memcpy ((uint8_t *) & serv_addr.sin_addr.s_addr,
     178            5 :       (uint8_t *) srv->h_addr_list[0], (size_t) srv->h_length);
     179            5 :   serv_addr.sin_port = htons (port);
     180              : 
     181            5 :   ret = connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr));
     182            5 :   if (ret < 0) {
     183            1 :     ret = -errno;
     184            1 :     goto ret_close_sockfd;
     185              :   }
     186              : 
     187              :   {
     188              :     ntp_packet_t packet;
     189              :     uint32_t recv_sec;
     190              :     uint32_t recv_frac;
     191              :     double frac;
     192              :     ssize_t n;
     193              : 
     194            4 :     memset (&packet, 0, sizeof (packet));
     195              : 
     196              :     /* li = 0, vn = 3, mode = 3 */
     197            4 :     packet.li_vn_mode = 0x1B;
     198              : 
     199              :     /* Request */
     200            4 :     n = write (sockfd, &packet, sizeof (packet));
     201            4 :     if (n < 0) {
     202            1 :       ret = -errno;
     203            3 :       goto ret_close_sockfd;
     204              :     }
     205              : 
     206              :     /* Receive */
     207            3 :     n = read (sockfd, &packet, sizeof (packet));
     208            3 :     if (n < 0) {
     209            1 :       ret = -errno;
     210            1 :       goto ret_close_sockfd;
     211              :     }
     212              : 
     213              :     /**
     214              :      * @note ntp_timestamp_t recv_ts in ntp_packet_t means the timestamp as the packet
     215              :      * left the NTP server. 'sec' corresponds to the seconds passed since 1900
     216              :      * and 'frac' is needed to convert seconds to smaller units of a second
     217              :      * such as microsceonds. Note that the bit/byte order of those data should
     218              :      * be converted to the host's endianness.
     219              :      */
     220            2 :     recv_sec = _convert_to_host_byte_order (packet.xmit_ts.sec);
     221            2 :     recv_frac = _convert_to_host_byte_order (packet.xmit_ts.frac);
     222              : 
     223              :     /**
     224              :      * @note NTP uses an epoch of January 1, 1900 while the Unix epoch is
     225              :      * the number of seconds that have elapsed since January 1, 1970. For this
     226              :      * reason, we subtract 70 years worth of seconds from the seconds since 1900
     227              :      */
     228            2 :     if (recv_sec <= NTPUTIL_TIMESTAMP_DELTA) {
     229            1 :       ret = -1;
     230            1 :       goto ret_close_sockfd;
     231              :     }
     232              : 
     233            1 :     ret = (int64_t) (recv_sec - NTPUTIL_TIMESTAMP_DELTA);
     234            1 :     ret *= NTPUTIL_SEC_TO_USEC_MULTIPLIER;
     235            1 :     frac = ((double) recv_frac) / NTPUTIL_MAX_FRAC_DOUBLE;
     236            1 :     frac *= NTPUTIL_SEC_TO_USEC_MULTIPLIER;
     237              : 
     238            1 :     ret += (int64_t) frac;
     239              :   }
     240              : 
     241            6 : ret_close_sockfd:
     242            6 :   close (sockfd);
     243              : 
     244            6 : ret_normal:
     245            6 :   return ret;
     246              : }
        

Generated by: LCOV version 2.0-1