xref: /freebsd/contrib/ntp/util/sht.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
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 *
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
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