154359Sroberto/*
254359Sroberto * sht.c - Testprogram for shared memory refclock
354359Sroberto * read/write shared memory segment; see usage
454359Sroberto */
5285612Sdelphij#include "config.h"
6285612Sdelphij
754359Sroberto#ifndef SYS_WINNT
854359Sroberto#include <sys/types.h>
954359Sroberto#include <sys/ipc.h>
1054359Sroberto#include <sys/shm.h>
1154359Sroberto#include <stdio.h>
1254359Sroberto#include <time.h>
1354359Sroberto#include <unistd.h>
1454359Sroberto#include <stdlib.h>
1554359Sroberto#else
1654359Sroberto#include <windows.h>
1754359Sroberto#include <time.h>
1854359Sroberto#include <stdlib.h>
1954359Sroberto#include <stdio.h>
2054359Sroberto#include <iostream.h>
2154359Sroberto#define sleep(x) Sleep(x*1000)
2254359Sroberto#endif
2354359Sroberto#include <assert.h>
24285612Sdelphij
2554359Srobertostruct shmTime {
2654359Sroberto	int    mode; /* 0 - if valid set
2754359Sroberto		      *       use values,
2854359Sroberto		      *       clear valid
2954359Sroberto		      * 1 - if valid set
3054359Sroberto		      *       if count before and after read of values is equal,
3154359Sroberto		      *         use values
3254359Sroberto		      *       clear valid
3354359Sroberto		      */
34285612Sdelphij	volatile int	count;
35285612Sdelphij	time_t		clockTimeStampSec;
36285612Sdelphij	int		clockTimeStampUSec;
37285612Sdelphij	time_t		receiveTimeStampSec;
38285612Sdelphij	int		receiveTimeStampUSec;
39285612Sdelphij	int		leap;
40285612Sdelphij	int		precision;
41285612Sdelphij	int		nsamples;
42285612Sdelphij	volatile int	valid;
43285612Sdelphij	unsigned	clockTimeStampNSec;	/* Unsigned ns timestamps */
44285612Sdelphij	unsigned	receiveTimeStampNSec;	/* Unsigned ns timestamps */
4554359Sroberto};
4654359Sroberto
47285612Sdelphijstatic struct shmTime *
4854359SrobertogetShmTime (
4954359Sroberto	int unit
5054359Sroberto	)
5154359Sroberto{
5254359Sroberto#ifndef SYS_WINNT
5354359Sroberto	int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777);
5454359Sroberto	if (shmid==-1) {
5554359Sroberto		perror ("shmget");
5654359Sroberto		exit (1);
5754359Sroberto	}
5854359Sroberto	else {
5954359Sroberto		struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
6054359Sroberto		if ((int)(long)p==-1) {
6154359Sroberto			perror ("shmat");
6254359Sroberto			p=0;
6354359Sroberto		}
6454359Sroberto		assert (p!=0);
6554359Sroberto		return p;
6654359Sroberto	}
6754359Sroberto#else
6854359Sroberto	char buf[10];
6954359Sroberto	LPSECURITY_ATTRIBUTES psec=0;
70285612Sdelphij	snprintf (buf, sizeof(buf), "NTP%d", unit);
7154359Sroberto	SECURITY_DESCRIPTOR sd;
7254359Sroberto	SECURITY_ATTRIBUTES sa;
7354359Sroberto	HANDLE shmid;
7454359Sroberto
7554359Sroberto	assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
7654359Sroberto	assert (SetSecurityDescriptorDacl(&sd,1,0,0));
7754359Sroberto	sa.nLength=sizeof (SECURITY_ATTRIBUTES);
7854359Sroberto	sa.lpSecurityDescriptor=&sd;
7954359Sroberto	sa.bInheritHandle=0;
8054359Sroberto	shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
8154359Sroberto				 psec, sizeof (struct shmTime),buf);
8254359Sroberto	if (!shmid) {
8354359Sroberto		shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
8454359Sroberto					 0, sizeof (struct shmTime),buf);
8554359Sroberto		cout <<"CreateFileMapping with psec!=0 failed"<<endl;
8654359Sroberto	}
8754359Sroberto
8854359Sroberto	if (!shmid) {
8954359Sroberto		char mbuf[1000];
9054359Sroberto		FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
9154359Sroberto			       0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
9254359Sroberto		int x=GetLastError ();
9354359Sroberto		cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl;
9454359Sroberto		exit (1);
9554359Sroberto	}
9654359Sroberto	else {
9754359Sroberto		struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
9854359Sroberto								    FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
9954359Sroberto		if (p==0) {
10054359Sroberto			char mbuf[1000];
10154359Sroberto			FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
10254359Sroberto				       0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
10354359Sroberto			cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl;
10454359Sroberto			exit (1);
10554359Sroberto		}
10654359Sroberto		return p;
10754359Sroberto	}
10854359Sroberto	return 0;
10954359Sroberto#endif
11054359Sroberto}
11154359Sroberto
11254359Sroberto
11354359Srobertoint
11454359Srobertomain (
11554359Sroberto	int argc,
11654359Sroberto	char *argv[]
11754359Sroberto	)
11854359Sroberto{
119285612Sdelphij	volatile struct shmTime *p;
120285612Sdelphij	int unit;
121285612Sdelphij	char *argp;
122285612Sdelphij
12354359Sroberto	if (argc<=1) {
124285612Sdelphij	  usage:
125285612Sdelphij		printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]);
126285612Sdelphij		printf ("       uu use clock unit uu (default: 2)\n");
12754359Sroberto		printf ("       r read shared memory\n");
128285612Sdelphij		printf ("       c clear valid-flag\n");
129285612Sdelphij		printf ("       l loop (so, rcl will read and clear in a loop\n");
13054359Sroberto		printf ("       w write shared memory with current time\n");
13154359Sroberto		printf ("       snnnn set nsamples to nnn\n");
13254359Sroberto		printf ("       lnnnn set leap to nnn\n");
13354359Sroberto		printf ("       pnnnn set precision to -nnn\n");
13454359Sroberto		exit (0);
13554359Sroberto	}
136285612Sdelphij
137285612Sdelphij	srand(time(NULL));
138285612Sdelphij
139285612Sdelphij	unit = strtoul(argv[1], &argp, 10);
140285612Sdelphij	if (argp == argv[1])
141285612Sdelphij		unit = 2;
142285612Sdelphij	else if (*argp == ':')
143285612Sdelphij		argp++;
144285612Sdelphij	else
145285612Sdelphij		goto usage;
146285612Sdelphij
147285612Sdelphij	p=getShmTime(unit);
148285612Sdelphij	switch (*argp) {
149285612Sdelphij	case 's':
150285612Sdelphij		p->nsamples=atoi(argp+1);
151285612Sdelphij		break;
152285612Sdelphij
153285612Sdelphij	case 'l':
154285612Sdelphij		p->leap=atoi(argp+1);
155285612Sdelphij		break;
156285612Sdelphij
157285612Sdelphij	case 'p':
158285612Sdelphij		p->precision=-atoi(argp+1);
159285612Sdelphij		break;
160285612Sdelphij
161285612Sdelphij	case 'r': {
162285612Sdelphij		int clear=0;
163285612Sdelphij		int loop=0;
164285612Sdelphij		printf ("reader\n");
165285612Sdelphij		while (*++argp) {
166285612Sdelphij			switch (*argp) {
167285612Sdelphij			case 'l': loop=1; break;
168285612Sdelphij			case 'c': clear=1; break;
169285612Sdelphij			default : goto usage;
170285612Sdelphij			}
171285612Sdelphij		}
172285612Sdelphijagain:
173285612Sdelphij		printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n",
174285612Sdelphij			p->mode,p->count,
175285612Sdelphij			(long)p->clockTimeStampSec,p->clockTimeStampNSec,
176285612Sdelphij			(long)p->receiveTimeStampSec,p->receiveTimeStampNSec);
177285612Sdelphij		printf ("  leap=%d, precision=%d, nsamples=%d, valid=%d\n",
178285612Sdelphij			p->leap, p->precision, p->nsamples, p->valid);
179285612Sdelphij		if (!p->valid)
180285612Sdelphij			printf ("***\n");
181285612Sdelphij		if (clear) {
182285612Sdelphij			p->valid=0;
183285612Sdelphij			printf ("cleared\n");
184285612Sdelphij		}
185285612Sdelphij		if (loop) {
186285612Sdelphij			sleep (1);
187285612Sdelphij			goto again;
188285612Sdelphij		}
189285612Sdelphij		break;
19054359Sroberto	}
191285612Sdelphij
192285612Sdelphij	case 'w': {
193285612Sdelphij		/* To show some life action, we read the system
194285612Sdelphij		 * clock and use a bit of fuzz from 'random()' to get a
195285612Sdelphij		 * bit of wobbling into the values (so we can observe a
196285612Sdelphij		 * certain jitter!)
197285612Sdelphij		 */
198285612Sdelphij		time_t clk_sec, rcv_sec;
199338531Sdelphij		u_int  clk_frc, rcv_frc;
200285612Sdelphij
201285612Sdelphij#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
202285612Sdelphij
203285612Sdelphij		/* Here we have a high-resolution system clock, and
204285612Sdelphij		 * we're not afraid to use it!
205285612Sdelphij		 */
206285612Sdelphij		struct timespec tmptime;
207285612Sdelphij		if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) {
208285612Sdelphij			rcv_sec = tmptime.tv_sec;
209338531Sdelphij			rcv_frc = (u_int)tmptime.tv_nsec;
210285612Sdelphij		}
211285612Sdelphij		else
212285612Sdelphij#endif
213285612Sdelphij		{
214285612Sdelphij			time(&rcv_sec);
215338531Sdelphij			rcv_frc = (u_int)random() % 1000000000u;
216285612Sdelphij		}
217285612Sdelphij		/* add a wobble of ~3.5msec to the clock time */
218285612Sdelphij		clk_sec = rcv_sec;
219338531Sdelphij		clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356);
220285612Sdelphij		/* normalise result -- the SHM driver is picky! */
221285612Sdelphij		while ((int)clk_frc < 0) {
222285612Sdelphij			clk_frc += 1000000000;
223285612Sdelphij			clk_sec -= 1;
224285612Sdelphij		}
225285612Sdelphij		while ((int)clk_frc >= 1000000000) {
226285612Sdelphij			clk_frc -= 1000000000;
227285612Sdelphij			clk_sec += 1;
228285612Sdelphij		}
229285612Sdelphij
230285612Sdelphij		/* Most 'real' time sources would create a clock
231285612Sdelphij		 * (reference) time stamp where the fraction is zero,
232285612Sdelphij		 * but that's not an actual requirement. So we show how
233285612Sdelphij		 * to deal with the time stamps in general; changing the
234285612Sdelphij		 * behaviour for cases where the fraction of the
235285612Sdelphij		 * clock time is zero should be trivial.
236285612Sdelphij		 */
237285612Sdelphij		printf ("writer\n");
238285612Sdelphij		p->mode=0;
239285612Sdelphij		if (!p->valid) {
240285612Sdelphij			p->clockTimeStampSec    = clk_sec;
241285612Sdelphij			p->clockTimeStampUSec   = clk_frc / 1000; /* truncate! */
242285612Sdelphij			p->clockTimeStampNSec   = clk_frc;
243285612Sdelphij			p->receiveTimeStampSec  = rcv_sec;
244285612Sdelphij			p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */
245285612Sdelphij			p->receiveTimeStampNSec = rcv_frc;
246285612Sdelphij			printf ("%ld.%09u %ld.%09u\n",
247285612Sdelphij				(long)p->clockTimeStampSec  , p->clockTimeStampNSec  ,
248285612Sdelphij				(long)p->receiveTimeStampSec, p->receiveTimeStampNSec);
249285612Sdelphij			p->valid=1;
250285612Sdelphij		}
251285612Sdelphij		else {
252285612Sdelphij			printf ("p->valid still set\n"); /* not an error! */
253285612Sdelphij		}
254285612Sdelphij		break;
255285612Sdelphij	}
256285612Sdelphij	default:
257285612Sdelphij		break;
258285612Sdelphij	}
259285612Sdelphij	return 0;
26054359Sroberto}
261