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

Generated by: LCOV version 2.0-1