1 /*        $NetBSD: sht.c,v 1.6 2020/05/25 20:47:37 christos Exp $     */
2 
3 /*
4  * sht.c - Testprogram for shared memory refclock
5  * read/write shared memory segment; see usage
6  */
7 #include "config.h"
8 
9 #ifndef SYS_WINNT
10 #include <sys/types.h>
11 #include <sys/ipc.h>
12 #include <sys/shm.h>
13 #include <stdio.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #else
18 #include <windows.h>
19 #include <time.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <iostream.h>
23 #define sleep(x) Sleep(x*1000)
24 #endif
25 #include <assert.h>
26 
27 struct shmTime {
28           int    mode; /* 0 - if valid set
29                           *       use values,
30                           *       clear valid
31                           * 1 - if valid set
32                           *       if count before and after read of values is equal,
33                           *         use values
34                           *       clear valid
35                           */
36           volatile int        count;
37           time_t              clockTimeStampSec;
38           int                 clockTimeStampUSec;
39           time_t              receiveTimeStampSec;
40           int                 receiveTimeStampUSec;
41           int                 leap;
42           int                 precision;
43           int                 nsamples;
44           volatile int        valid;
45           unsigned  clockTimeStampNSec; /* Unsigned ns timestamps */
46           unsigned  receiveTimeStampNSec;         /* Unsigned ns timestamps */
47 };
48 
49 static struct shmTime *
getShmTime(int unit)50 getShmTime (
51           int unit
52           )
53 {
54 #ifndef SYS_WINNT
55           int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777);
56           if (shmid==-1) {
57                     perror ("shmget");
58                     exit (1);
59           }
60           else {
61                     struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
62                     if ((int)(long)p==-1) {
63                               perror ("shmat");
64                               p=0;
65                     }
66                     assert (p!=0);
67                     return p;
68           }
69 #else
70           char buf[10];
71           LPSECURITY_ATTRIBUTES psec=0;
72           snprintf (buf, sizeof(buf), "NTP%d", unit);
73           SECURITY_DESCRIPTOR sd;
74           SECURITY_ATTRIBUTES sa;
75           HANDLE shmid;
76 
77           assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
78           assert (SetSecurityDescriptorDacl(&sd,1,0,0));
79           sa.nLength=sizeof (SECURITY_ATTRIBUTES);
80           sa.lpSecurityDescriptor=&sd;
81           sa.bInheritHandle=0;
82           shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
83                                          psec, sizeof (struct shmTime),buf);
84           if (!shmid) {
85                     shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
86                                                    0, sizeof (struct shmTime),buf);
87                     cout <<"CreateFileMapping with psec!=0 failed"<<endl;
88           }
89 
90           if (!shmid) {
91                     char mbuf[1000];
92                     FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
93                                      0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
94                     int x=GetLastError ();
95                     cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl;
96                     exit (1);
97           }
98           else {
99                     struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
100                                                                                     FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
101                     if (p==0) {
102                               char mbuf[1000];
103                               FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
104                                                0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
105                               cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl;
106                               exit (1);
107                     }
108                     return p;
109           }
110           return 0;
111 #endif
112 }
113 
114 
115 int
main(int argc,char * argv[])116 main (
117           int argc,
118           char *argv[]
119           )
120 {
121           volatile struct shmTime *p;
122           int unit;
123           char *argp;
124 
125           if (argc<=1) {
126             usage:
127                     printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]);
128                     printf ("       uu use clock unit uu (default: 2)\n");
129                     printf ("       r read shared memory\n");
130                     printf ("       c clear valid-flag\n");
131                     printf ("       l loop (so, rcl will read and clear in a loop\n");
132                     printf ("       w write shared memory with current time\n");
133                     printf ("       snnnn set nsamples to nnn\n");
134                     printf ("       lnnnn set leap to nnn\n");
135                     printf ("       pnnnn set precision to -nnn\n");
136                     exit (0);
137           }
138 
139           srand(time(NULL));
140 
141           unit = strtoul(argv[1], &argp, 10);
142           if (argp == argv[1])
143                     unit = 2;
144           else if (*argp == ':')
145                     argp++;
146           else
147                     goto usage;
148 
149           p=getShmTime(unit);
150           switch (*argp) {
151           case 's':
152                     p->nsamples=atoi(argp+1);
153                     break;
154 
155           case 'l':
156                     p->leap=atoi(argp+1);
157                     break;
158 
159           case 'p':
160                     p->precision=-atoi(argp+1);
161                     break;
162 
163           case 'r': {
164                     int clear=0;
165                     int loop=0;
166                     printf ("reader\n");
167                     while (*++argp) {
168                               switch (*argp) {
169                               case 'l': loop=1; break;
170                               case 'c': clear=1; break;
171                               default : goto usage;
172                               }
173                     }
174 again:
175                     printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n",
176                               p->mode,p->count,
177                               (long)p->clockTimeStampSec,p->clockTimeStampNSec,
178                               (long)p->receiveTimeStampSec,p->receiveTimeStampNSec);
179                     printf ("  leap=%d, precision=%d, nsamples=%d, valid=%d\n",
180                               p->leap, p->precision, p->nsamples, p->valid);
181                     if (!p->valid)
182                               printf ("***\n");
183                     if (clear) {
184                               p->valid=0;
185                               printf ("cleared\n");
186                     }
187                     if (loop) {
188                               sleep (1);
189                               goto again;
190                     }
191                     break;
192           }
193 
194           case 'w': {
195                     /* To show some life action, we read the system
196                      * clock and use a bit of fuzz from 'random()' to get a
197                      * bit of wobbling into the values (so we can observe a
198                      * certain jitter!)
199                      */
200                     time_t clk_sec, rcv_sec;
201                     u_int  clk_frc, rcv_frc;
202 
203 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
204 
205                     /* Here we have a high-resolution system clock, and
206                      * we're not afraid to use it!
207                      */
208                     struct timespec tmptime;
209                     if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) {
210                               rcv_sec = tmptime.tv_sec;
211                               rcv_frc = (u_int)tmptime.tv_nsec;
212                     }
213                     else
214 #endif
215                     {
216                               time(&rcv_sec);
217                               rcv_frc = (u_int)random() % 1000000000u;
218                     }
219                     /* add a wobble of ~3.5msec to the clock time */
220                     clk_sec = rcv_sec;
221                     clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356);
222                     /* normalise result -- the SHM driver is picky! */
223                     while ((int)clk_frc < 0) {
224                               clk_frc += 1000000000;
225                               clk_sec -= 1;
226                     }
227                     while ((int)clk_frc >= 1000000000) {
228                               clk_frc -= 1000000000;
229                               clk_sec += 1;
230                     }
231 
232                     /* Most 'real' time sources would create a clock
233                      * (reference) time stamp where the fraction is zero,
234                      * but that's not an actual requirement. So we show how
235                      * to deal with the time stamps in general; changing the
236                      * behaviour for cases where the fraction of the
237                      * clock time is zero should be trivial.
238                      */
239                     printf ("writer\n");
240                     p->mode=0;
241                     if (!p->valid) {
242                               p->clockTimeStampSec    = clk_sec;
243                               p->clockTimeStampUSec   = clk_frc / 1000; /* truncate! */
244                               p->clockTimeStampNSec   = clk_frc;
245                               p->receiveTimeStampSec  = rcv_sec;
246                               p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */
247                               p->receiveTimeStampNSec = rcv_frc;
248                               printf ("%ld.%09u %ld.%09u\n",
249                                         (long)p->clockTimeStampSec  , p->clockTimeStampNSec  ,
250                                         (long)p->receiveTimeStampSec, p->receiveTimeStampNSec);
251                               p->valid=1;
252                     }
253                     else {
254                               printf ("p->valid still set\n"); /* not an error! */
255                     }
256                     break;
257           }
258           default:
259                     break;
260           }
261           return 0;
262 }
263