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