xref: /freebsd-src/contrib/ntp/util/sht.c (revision 7847e04111f2c2b06b36f6d19a46d78814d7836d)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * sht.c - Testprogram for shared memory refclock
3c0b746e5SOllivier Robert  * read/write shared memory segment; see usage
4c0b746e5SOllivier Robert  */
52b15cb3dSCy Schubert #include "config.h"
62b15cb3dSCy Schubert 
7c0b746e5SOllivier Robert #ifndef SYS_WINNT
8c0b746e5SOllivier Robert #include <sys/types.h>
9c0b746e5SOllivier Robert #include <sys/ipc.h>
10c0b746e5SOllivier Robert #include <sys/shm.h>
11c0b746e5SOllivier Robert #include <stdio.h>
12c0b746e5SOllivier Robert #include <time.h>
13c0b746e5SOllivier Robert #include <unistd.h>
14c0b746e5SOllivier Robert #include <stdlib.h>
15c0b746e5SOllivier Robert #else
16c0b746e5SOllivier Robert #include <windows.h>
17c0b746e5SOllivier Robert #include <time.h>
18c0b746e5SOllivier Robert #include <stdlib.h>
19c0b746e5SOllivier Robert #include <stdio.h>
20c0b746e5SOllivier Robert #include <iostream.h>
21c0b746e5SOllivier Robert #define sleep(x) Sleep(x*1000)
22c0b746e5SOllivier Robert #endif
23c0b746e5SOllivier Robert #include <assert.h>
242b15cb3dSCy Schubert 
25c0b746e5SOllivier Robert struct shmTime {
26c0b746e5SOllivier Robert 	int    mode; /* 0 - if valid set
27c0b746e5SOllivier Robert 		      *       use values,
28c0b746e5SOllivier Robert 		      *       clear valid
29c0b746e5SOllivier Robert 		      * 1 - if valid set
30c0b746e5SOllivier Robert 		      *       if count before and after read of values is equal,
31c0b746e5SOllivier Robert 		      *         use values
32c0b746e5SOllivier Robert 		      *       clear valid
33c0b746e5SOllivier Robert 		      */
342b15cb3dSCy Schubert 	volatile int	count;
35c0b746e5SOllivier Robert 	time_t		clockTimeStampSec;
36c0b746e5SOllivier Robert 	int		clockTimeStampUSec;
37c0b746e5SOllivier Robert 	time_t		receiveTimeStampSec;
38c0b746e5SOllivier Robert 	int		receiveTimeStampUSec;
39c0b746e5SOllivier Robert 	int		leap;
40c0b746e5SOllivier Robert 	int		precision;
41c0b746e5SOllivier Robert 	int		nsamples;
422b15cb3dSCy Schubert 	volatile int	valid;
432b15cb3dSCy Schubert 	unsigned	clockTimeStampNSec;	/* Unsigned ns timestamps */
442b15cb3dSCy Schubert 	unsigned	receiveTimeStampNSec;	/* Unsigned ns timestamps */
45c0b746e5SOllivier Robert };
46c0b746e5SOllivier Robert 
472b15cb3dSCy Schubert static struct shmTime *
getShmTime(int unit)48c0b746e5SOllivier Robert getShmTime (
49c0b746e5SOllivier Robert 	int unit
50c0b746e5SOllivier Robert 	)
51c0b746e5SOllivier Robert {
52c0b746e5SOllivier Robert #ifndef SYS_WINNT
53c0b746e5SOllivier Robert 	int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777);
54c0b746e5SOllivier Robert 	if (shmid==-1) {
55c0b746e5SOllivier Robert 		perror ("shmget");
56c0b746e5SOllivier Robert 		exit (1);
57c0b746e5SOllivier Robert 	}
58c0b746e5SOllivier Robert 	else {
59c0b746e5SOllivier Robert 		struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
60c0b746e5SOllivier Robert 		if ((int)(long)p==-1) {
61c0b746e5SOllivier Robert 			perror ("shmat");
62c0b746e5SOllivier Robert 			p=0;
63c0b746e5SOllivier Robert 		}
64c0b746e5SOllivier Robert 		assert (p!=0);
65c0b746e5SOllivier Robert 		return p;
66c0b746e5SOllivier Robert 	}
67c0b746e5SOllivier Robert #else
68c0b746e5SOllivier Robert 	char buf[10];
69c0b746e5SOllivier Robert 	LPSECURITY_ATTRIBUTES psec=0;
702b15cb3dSCy Schubert 	snprintf (buf, sizeof(buf), "NTP%d", unit);
71c0b746e5SOllivier Robert 	SECURITY_DESCRIPTOR sd;
72c0b746e5SOllivier Robert 	SECURITY_ATTRIBUTES sa;
73c0b746e5SOllivier Robert 	HANDLE shmid;
74c0b746e5SOllivier Robert 
75c0b746e5SOllivier Robert 	assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
76c0b746e5SOllivier Robert 	assert (SetSecurityDescriptorDacl(&sd,1,0,0));
77c0b746e5SOllivier Robert 	sa.nLength=sizeof (SECURITY_ATTRIBUTES);
78c0b746e5SOllivier Robert 	sa.lpSecurityDescriptor=&sd;
79c0b746e5SOllivier Robert 	sa.bInheritHandle=0;
80c0b746e5SOllivier Robert 	shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
81c0b746e5SOllivier Robert 				 psec, sizeof (struct shmTime),buf);
82c0b746e5SOllivier Robert 	if (!shmid) {
83c0b746e5SOllivier Robert 		shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
84c0b746e5SOllivier Robert 					 0, sizeof (struct shmTime),buf);
85c0b746e5SOllivier Robert 		cout <<"CreateFileMapping with psec!=0 failed"<<endl;
86c0b746e5SOllivier Robert 	}
87c0b746e5SOllivier Robert 
88c0b746e5SOllivier Robert 	if (!shmid) {
89c0b746e5SOllivier Robert 		char mbuf[1000];
90c0b746e5SOllivier Robert 		FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
91c0b746e5SOllivier Robert 			       0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
92c0b746e5SOllivier Robert 		int x=GetLastError ();
93c0b746e5SOllivier Robert 		cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl;
94c0b746e5SOllivier Robert 		exit (1);
95c0b746e5SOllivier Robert 	}
96c0b746e5SOllivier Robert 	else {
97c0b746e5SOllivier Robert 		struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
98c0b746e5SOllivier Robert 								    FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
99c0b746e5SOllivier Robert 		if (p==0) {
100c0b746e5SOllivier Robert 			char mbuf[1000];
101c0b746e5SOllivier Robert 			FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
102c0b746e5SOllivier Robert 				       0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
103c0b746e5SOllivier Robert 			cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl;
104c0b746e5SOllivier Robert 			exit (1);
105c0b746e5SOllivier Robert 		}
106c0b746e5SOllivier Robert 		return p;
107c0b746e5SOllivier Robert 	}
108c0b746e5SOllivier Robert 	return 0;
109c0b746e5SOllivier Robert #endif
110c0b746e5SOllivier Robert }
111c0b746e5SOllivier Robert 
112c0b746e5SOllivier Robert 
113c0b746e5SOllivier Robert int
main(int argc,char * argv[])114c0b746e5SOllivier Robert main (
115c0b746e5SOllivier Robert 	int argc,
116c0b746e5SOllivier Robert 	char *argv[]
117c0b746e5SOllivier Robert 	)
118c0b746e5SOllivier Robert {
1192b15cb3dSCy Schubert 	volatile struct shmTime *p;
1202b15cb3dSCy Schubert 	int unit;
1212b15cb3dSCy Schubert 	char *argp;
1222b15cb3dSCy Schubert 
123c0b746e5SOllivier Robert 	if (argc<=1) {
1242b15cb3dSCy Schubert 	  usage:
1252b15cb3dSCy Schubert 		printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]);
1262b15cb3dSCy Schubert 		printf ("       uu use clock unit uu (default: 2)\n");
127c0b746e5SOllivier Robert 		printf ("       r read shared memory\n");
128c0b746e5SOllivier Robert 		printf ("       c clear valid-flag\n");
129c0b746e5SOllivier Robert 		printf ("       l loop (so, rcl will read and clear in a loop\n");
130c0b746e5SOllivier Robert 		printf ("       w write shared memory with current time\n");
131c0b746e5SOllivier Robert 		printf ("       snnnn set nsamples to nnn\n");
132c0b746e5SOllivier Robert 		printf ("       lnnnn set leap to nnn\n");
133c0b746e5SOllivier Robert 		printf ("       pnnnn set precision to -nnn\n");
134c0b746e5SOllivier Robert 		exit (0);
135c0b746e5SOllivier Robert 	}
1362b15cb3dSCy Schubert 
1372b15cb3dSCy Schubert 	srand(time(NULL));
1382b15cb3dSCy Schubert 
1392b15cb3dSCy Schubert 	unit = strtoul(argv[1], &argp, 10);
1402b15cb3dSCy Schubert 	if (argp == argv[1])
1412b15cb3dSCy Schubert 		unit = 2;
1422b15cb3dSCy Schubert 	else if (*argp == ':')
1432b15cb3dSCy Schubert 		argp++;
1442b15cb3dSCy Schubert 	else
1452b15cb3dSCy Schubert 		goto usage;
1462b15cb3dSCy Schubert 
1472b15cb3dSCy Schubert 	p=getShmTime(unit);
1482b15cb3dSCy Schubert 	switch (*argp) {
1492b15cb3dSCy Schubert 	case 's':
1502b15cb3dSCy Schubert 		p->nsamples=atoi(argp+1);
151c0b746e5SOllivier Robert 		break;
1522b15cb3dSCy Schubert 
1532b15cb3dSCy Schubert 	case 'l':
1542b15cb3dSCy Schubert 		p->leap=atoi(argp+1);
155c0b746e5SOllivier Robert 		break;
1562b15cb3dSCy Schubert 
1572b15cb3dSCy Schubert 	case 'p':
1582b15cb3dSCy Schubert 		p->precision=-atoi(argp+1);
159c0b746e5SOllivier Robert 		break;
1602b15cb3dSCy Schubert 
161c0b746e5SOllivier Robert 	case 'r': {
162c0b746e5SOllivier Robert 		int clear=0;
163c0b746e5SOllivier Robert 		int loop=0;
164c0b746e5SOllivier Robert 		printf ("reader\n");
1652b15cb3dSCy Schubert 		while (*++argp) {
1662b15cb3dSCy Schubert 			switch (*argp) {
167c0b746e5SOllivier Robert 			case 'l': loop=1; break;
168c0b746e5SOllivier Robert 			case 'c': clear=1; break;
1692b15cb3dSCy Schubert 			default : goto usage;
170c0b746e5SOllivier Robert 			}
171c0b746e5SOllivier Robert 		}
1722b15cb3dSCy Schubert again:
1732b15cb3dSCy Schubert 		printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n",
1742b15cb3dSCy Schubert 			p->mode,p->count,
1752b15cb3dSCy Schubert 			(long)p->clockTimeStampSec,p->clockTimeStampNSec,
1762b15cb3dSCy Schubert 			(long)p->receiveTimeStampSec,p->receiveTimeStampNSec);
177c0b746e5SOllivier Robert 		printf ("  leap=%d, precision=%d, nsamples=%d, valid=%d\n",
178c0b746e5SOllivier Robert 			p->leap, p->precision, p->nsamples, p->valid);
179c0b746e5SOllivier Robert 		if (!p->valid)
180c0b746e5SOllivier Robert 			printf ("***\n");
181c0b746e5SOllivier Robert 		if (clear) {
182c0b746e5SOllivier Robert 			p->valid=0;
183c0b746e5SOllivier Robert 			printf ("cleared\n");
184c0b746e5SOllivier Robert 		}
1852b15cb3dSCy Schubert 		if (loop) {
186c0b746e5SOllivier Robert 			sleep (1);
1872b15cb3dSCy Schubert 			goto again;
188c0b746e5SOllivier Robert 		}
189c0b746e5SOllivier Robert 		break;
1902b15cb3dSCy Schubert 	}
1912b15cb3dSCy Schubert 
192c0b746e5SOllivier Robert 	case 'w': {
1932b15cb3dSCy Schubert 		/* To show some life action, we read the system
1942b15cb3dSCy Schubert 		 * clock and use a bit of fuzz from 'random()' to get a
1952b15cb3dSCy Schubert 		 * bit of wobbling into the values (so we can observe a
1962b15cb3dSCy Schubert 		 * certain jitter!)
1972b15cb3dSCy Schubert 		 */
1982b15cb3dSCy Schubert 		time_t clk_sec, rcv_sec;
199*4e1ef62aSXin LI 		u_int  clk_frc, rcv_frc;
2002b15cb3dSCy Schubert 
2012b15cb3dSCy Schubert #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
2022b15cb3dSCy Schubert 
2032b15cb3dSCy Schubert 		/* Here we have a high-resolution system clock, and
2042b15cb3dSCy Schubert 		 * we're not afraid to use it!
2052b15cb3dSCy Schubert 		 */
2062b15cb3dSCy Schubert 		struct timespec tmptime;
2072b15cb3dSCy Schubert 		if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) {
2082b15cb3dSCy Schubert 			rcv_sec = tmptime.tv_sec;
209*4e1ef62aSXin LI 			rcv_frc = (u_int)tmptime.tv_nsec;
2102b15cb3dSCy Schubert 		}
2112b15cb3dSCy Schubert 		else
2122b15cb3dSCy Schubert #endif
2132b15cb3dSCy Schubert 		{
2142b15cb3dSCy Schubert 			time(&rcv_sec);
215*4e1ef62aSXin LI 			rcv_frc = (u_int)random() % 1000000000u;
2162b15cb3dSCy Schubert 		}
2172b15cb3dSCy Schubert 		/* add a wobble of ~3.5msec to the clock time */
2182b15cb3dSCy Schubert 		clk_sec = rcv_sec;
219*4e1ef62aSXin LI 		clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356);
2202b15cb3dSCy Schubert 		/* normalise result -- the SHM driver is picky! */
2212b15cb3dSCy Schubert 		while ((int)clk_frc < 0) {
2222b15cb3dSCy Schubert 			clk_frc += 1000000000;
2232b15cb3dSCy Schubert 			clk_sec -= 1;
2242b15cb3dSCy Schubert 		}
2252b15cb3dSCy Schubert 		while ((int)clk_frc >= 1000000000) {
2262b15cb3dSCy Schubert 			clk_frc -= 1000000000;
2272b15cb3dSCy Schubert 			clk_sec += 1;
2282b15cb3dSCy Schubert 		}
2292b15cb3dSCy Schubert 
2302b15cb3dSCy Schubert 		/* Most 'real' time sources would create a clock
2312b15cb3dSCy Schubert 		 * (reference) time stamp where the fraction is zero,
2322b15cb3dSCy Schubert 		 * but that's not an actual requirement. So we show how
2332b15cb3dSCy Schubert 		 * to deal with the time stamps in general; changing the
2342b15cb3dSCy Schubert 		 * behaviour for cases where the fraction of the
2352b15cb3dSCy Schubert 		 * clock time is zero should be trivial.
2362b15cb3dSCy Schubert 		 */
237c0b746e5SOllivier Robert 		printf ("writer\n");
238c0b746e5SOllivier Robert 		p->mode=0;
239c0b746e5SOllivier Robert 		if (!p->valid) {
2402b15cb3dSCy Schubert 			p->clockTimeStampSec    = clk_sec;
2412b15cb3dSCy Schubert 			p->clockTimeStampUSec   = clk_frc / 1000; /* truncate! */
2422b15cb3dSCy Schubert 			p->clockTimeStampNSec   = clk_frc;
2432b15cb3dSCy Schubert 			p->receiveTimeStampSec  = rcv_sec;
2442b15cb3dSCy Schubert 			p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */
2452b15cb3dSCy Schubert 			p->receiveTimeStampNSec = rcv_frc;
2462b15cb3dSCy Schubert 			printf ("%ld.%09u %ld.%09u\n",
2472b15cb3dSCy Schubert 				(long)p->clockTimeStampSec  , p->clockTimeStampNSec  ,
2482b15cb3dSCy Schubert 				(long)p->receiveTimeStampSec, p->receiveTimeStampNSec);
249c0b746e5SOllivier Robert 			p->valid=1;
250c0b746e5SOllivier Robert 		}
251c0b746e5SOllivier Robert 		else {
2529c2daa00SOllivier Robert 			printf ("p->valid still set\n"); /* not an error! */
253c0b746e5SOllivier Robert 		}
254c0b746e5SOllivier Robert 		break;
255c0b746e5SOllivier Robert 	}
2562b15cb3dSCy Schubert 	default:
2572b15cb3dSCy Schubert 		break;
2582b15cb3dSCy Schubert 	}
2592b15cb3dSCy Schubert 	return 0;
260c0b746e5SOllivier Robert }
261