xref: /netbsd-src/external/bsd/ntp/dist/util/sht.c (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
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