1 #include <time.h>
2 #include <sys/ipc.h>
3 #include <sys/time.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 
10 #include "tvhtime.h"
11 #include "tvheadend.h"
12 #include "config.h"
13 
14 #if !ENABLE_ANDROID
15 #include <sys/shm.h>
16 #endif
17 
18 /*
19  * NTP processing
20  */
21 #define NTPD_BASE	0x4e545030	/* "NTP0" */
22 #define NTPD_UNIT	2
23 
24 #if !ENABLE_ANDROID
25 typedef struct
26 {
27   int    mode; /* 0 - if valid set
28 				        *       use values,
29 				        *       clear valid
30 				        * 1 - if valid set
31 				        *       if count before and after read of values is equal,
32 				        *         use values
33 				        *       clear valid
34 				        */
35   int    count;
36   time_t clockTimeStampSec;
37   int    clockTimeStampUSec;
38   time_t receiveTimeStampSec;
39   int    receiveTimeStampUSec;
40   int    leap;
41   int    precision;
42   int    nsamples;
43   int    valid;
44   int    pad[10];
45 } ntp_shm_t;
46 
47 static ntp_shm_t *
ntp_shm_init(void)48 ntp_shm_init ( void )
49 {
50   int shmid, unit, mode;
51   static ntp_shm_t *shmptr = NULL;
52 
53   if (shmptr != NULL)
54     return shmptr;
55 
56   unit = getuid() ? 2 : 0;
57   mode = getuid() ? 0666 : 0600;
58 
59   shmid = shmget((key_t)NTPD_BASE + unit, sizeof(ntp_shm_t), IPC_CREAT | mode);
60   if (shmid == -1)
61     return NULL;
62 
63   shmptr = shmat(shmid, 0, 0);
64 
65   if (shmptr) {
66     memset(shmptr, 0, sizeof(ntp_shm_t));
67     shmptr->mode      = 1;
68     shmptr->precision = -1;
69     shmptr->nsamples  = 1;
70   }
71 
72   return shmptr;
73 }
74 #endif
75 
76 /*
77  * Update time
78  */
79 void
tvhtime_update(time_t utc,const char * srcname)80 tvhtime_update ( time_t utc, const char *srcname )
81 {
82 #if !ENABLE_ANDROID
83   struct tm tm;
84   struct timeval tv;
85   ntp_shm_t *ntp_shm;
86   int64_t t1, t2, diff;
87 
88   localtime_r(&utc, &tm);
89 
90   tvhtrace(LS_TIME, "%s - current time is %04d/%02d/%02d %02d:%02d:%02d",
91            srcname,
92            tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
93            tm.tm_hour, tm.tm_min, tm.tm_sec);
94 
95   gettimeofday(&tv, NULL);
96 
97   /* Delta */
98   t1 = utc * 1000000;
99   t2 = tv.tv_sec * 1000000 + tv.tv_usec;
100 
101   /* Update local clock */
102   if (config.tvhtime_update_enabled) {
103     if ((diff = llabs(t2 - t1)) > config.tvhtime_tolerance) {
104 #if ENABLE_STIME
105       if (stime(&utc) < 0)
106         tvherror(LS_TIME, "%s - unable to update system time: %s", srcname, strerror(errno));
107       else
108         tvhdebug(LS_TIME, "%s - updated system clock", srcname);
109 #else
110       tvhnotice(LS_TIME, "%s - stime(2) not implemented", srcname);
111 #endif
112     } else {
113       tvhwarn(LS_TIME, "%s - time not updated (diff %"PRId64")", srcname, diff);
114     }
115   }
116 
117   /* NTP */
118   if (config.tvhtime_ntp_enabled) {
119     if (!(ntp_shm = ntp_shm_init()))
120       return;
121 
122     tvhtrace(LS_TIME, "ntp delta = %"PRId64" us\n", t2 - t1);
123     ntp_shm->valid = 0;
124     ntp_shm->count++;
125     ntp_shm->clockTimeStampSec    = utc;
126     ntp_shm->clockTimeStampUSec   = 0;
127     ntp_shm->receiveTimeStampSec  = tv.tv_sec;
128     ntp_shm->receiveTimeStampUSec = (int)tv.tv_usec;
129     ntp_shm->count++;
130     ntp_shm->valid = 1;
131   }
132 #endif
133 }
134 
135 /* Initialise */
tvhtime_init(void)136 void tvhtime_init ( void )
137 {
138   if (config.tvhtime_tolerance == 0)
139     config.tvhtime_tolerance = 5000;
140 }
141