xref: /freebsd/contrib/ntp/ntpd/refclock_shm.c (revision c0b746e5e8d9479f05b3749cbf1f73b8928719bd)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * refclock_shm - clock driver for utc via shared memory
3c0b746e5SOllivier Robert  * - under construction -
4c0b746e5SOllivier Robert  * To add new modes: Extend or union the shmTime-struct. Do not
5c0b746e5SOllivier Robert  * extend/shrink size, because otherwise existing implementations
6c0b746e5SOllivier Robert  * will specify wrong size of shared memory-segment
7c0b746e5SOllivier Robert  * PB 18.3.97
8c0b746e5SOllivier Robert  */
9c0b746e5SOllivier Robert 
10c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
11c0b746e5SOllivier Robert # include <config.h>
12c0b746e5SOllivier Robert #endif
13c0b746e5SOllivier Robert 
14c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_SHM)
15c0b746e5SOllivier Robert 
16c0b746e5SOllivier Robert #undef fileno
17c0b746e5SOllivier Robert #include <ctype.h>
18c0b746e5SOllivier Robert #undef fileno
19c0b746e5SOllivier Robert #include <sys/time.h>
20c0b746e5SOllivier Robert #undef fileno
21c0b746e5SOllivier Robert 
22c0b746e5SOllivier Robert #include "ntpd.h"
23c0b746e5SOllivier Robert #undef fileno
24c0b746e5SOllivier Robert #include "ntp_io.h"
25c0b746e5SOllivier Robert #undef fileno
26c0b746e5SOllivier Robert #include "ntp_refclock.h"
27c0b746e5SOllivier Robert #undef fileno
28c0b746e5SOllivier Robert #include "ntp_unixtime.h"
29c0b746e5SOllivier Robert #undef fileno
30c0b746e5SOllivier Robert #include "ntp_stdlib.h"
31c0b746e5SOllivier Robert 
32c0b746e5SOllivier Robert #ifndef SYS_WINNT
33c0b746e5SOllivier Robert #include <sys/types.h>
34c0b746e5SOllivier Robert #include <sys/ipc.h>
35c0b746e5SOllivier Robert #include <sys/shm.h>
36c0b746e5SOllivier Robert #include <assert.h>
37c0b746e5SOllivier Robert #include <time.h>
38c0b746e5SOllivier Robert #include <unistd.h>
39c0b746e5SOllivier Robert #include <stdlib.h>
40c0b746e5SOllivier Robert #include <stdio.h>
41c0b746e5SOllivier Robert #endif
42c0b746e5SOllivier Robert 
43c0b746e5SOllivier Robert /*
44c0b746e5SOllivier Robert  * This driver supports a reference clock attached thru shared memory
45c0b746e5SOllivier Robert  */
46c0b746e5SOllivier Robert 
47c0b746e5SOllivier Robert /*
48c0b746e5SOllivier Robert  * SHM interface definitions
49c0b746e5SOllivier Robert  */
50c0b746e5SOllivier Robert #define PRECISION       (-1)    /* precision assumed (0.5 s) */
51c0b746e5SOllivier Robert #define REFID           "SHM"   /* reference ID */
52c0b746e5SOllivier Robert #define DESCRIPTION     "SHM/Shared memory interface"
53c0b746e5SOllivier Robert 
54c0b746e5SOllivier Robert #define NSAMPLES        3       /* stages of median filter */
55c0b746e5SOllivier Robert 
56c0b746e5SOllivier Robert /*
57c0b746e5SOllivier Robert  * Function prototypes
58c0b746e5SOllivier Robert  */
59c0b746e5SOllivier Robert static  int     shm_start       (int, struct peer *);
60c0b746e5SOllivier Robert static  void    shm_shutdown    (int, struct peer *);
61c0b746e5SOllivier Robert static  void    shm_poll        (int unit, struct peer *);
62c0b746e5SOllivier Robert 
63c0b746e5SOllivier Robert /*
64c0b746e5SOllivier Robert  * Transfer vector
65c0b746e5SOllivier Robert  */
66c0b746e5SOllivier Robert struct  refclock refclock_shm = {
67c0b746e5SOllivier Robert 	shm_start,              /* start up driver */
68c0b746e5SOllivier Robert 	shm_shutdown,           /* shut down driver */
69c0b746e5SOllivier Robert 	shm_poll,               /* transmit poll message */
70c0b746e5SOllivier Robert 	noentry,                /* not used */
71c0b746e5SOllivier Robert 	noentry,                /* initialize driver (not used) */
72c0b746e5SOllivier Robert 	noentry,                /* not used */
73c0b746e5SOllivier Robert 	NOFLAGS                 /* not used */
74c0b746e5SOllivier Robert };
75c0b746e5SOllivier Robert struct shmTime {
76c0b746e5SOllivier Robert 	int    mode; /* 0 - if valid set
77c0b746e5SOllivier Robert 		      *       use values,
78c0b746e5SOllivier Robert 		      *       clear valid
79c0b746e5SOllivier Robert 		      * 1 - if valid set
80c0b746e5SOllivier Robert 		      *       if count before and after read of values is equal,
81c0b746e5SOllivier Robert 		      *         use values
82c0b746e5SOllivier Robert 		      *       clear valid
83c0b746e5SOllivier Robert 		      */
84c0b746e5SOllivier Robert 	int    count;
85c0b746e5SOllivier Robert 	time_t clockTimeStampSec;
86c0b746e5SOllivier Robert 	int    clockTimeStampUSec;
87c0b746e5SOllivier Robert 	time_t receiveTimeStampSec;
88c0b746e5SOllivier Robert 	int    receiveTimeStampUSec;
89c0b746e5SOllivier Robert 	int    leap;
90c0b746e5SOllivier Robert 	int    precision;
91c0b746e5SOllivier Robert 	int    nsamples;
92c0b746e5SOllivier Robert 	int    valid;
93c0b746e5SOllivier Robert 	int    dummy[10];
94c0b746e5SOllivier Robert };
95c0b746e5SOllivier Robert struct shmTime *getShmTime (int unit) {
96c0b746e5SOllivier Robert #ifndef SYS_WINNT
97c0b746e5SOllivier Robert 	extern char *sys_errlist[ ];
98c0b746e5SOllivier Robert 	extern int sys_nerr;
99c0b746e5SOllivier Robert 	int shmid=0;
100c0b746e5SOllivier Robert 
101c0b746e5SOllivier Robert 	assert (unit<10); /* MAXUNIT is 4, so should never happen */
102c0b746e5SOllivier Robert 	shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
103c0b746e5SOllivier Robert 		      IPC_CREAT|(unit<2?0700:0777));
104c0b746e5SOllivier Robert 	if (shmid==-1) { /*error */
105c0b746e5SOllivier Robert 		char buf[20];
106c0b746e5SOllivier Robert 		char *pe=buf;
107c0b746e5SOllivier Robert 		if (errno<sys_nerr)
108c0b746e5SOllivier Robert 		    pe=sys_errlist[errno];
109c0b746e5SOllivier Robert 		else {
110c0b746e5SOllivier Robert 			sprintf (buf,"errno=%d",errno);
111c0b746e5SOllivier Robert 		}
112c0b746e5SOllivier Robert 		msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,pe);
113c0b746e5SOllivier Robert 		return 0;
114c0b746e5SOllivier Robert 	}
115c0b746e5SOllivier Robert 	else { /* no error  */
116c0b746e5SOllivier Robert 		struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
117c0b746e5SOllivier Robert 		if ((int)(long)p==-1) { /* error */
118c0b746e5SOllivier Robert 			char buf[20];
119c0b746e5SOllivier Robert 			char *pe=buf;
120c0b746e5SOllivier Robert 			if (errno<sys_nerr)
121c0b746e5SOllivier Robert 			    pe=sys_errlist[errno];
122c0b746e5SOllivier Robert 			else {
123c0b746e5SOllivier Robert 				sprintf (buf,"errno=%d",errno);
124c0b746e5SOllivier Robert 			}
125c0b746e5SOllivier Robert 			msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,pe);
126c0b746e5SOllivier Robert 			return 0;
127c0b746e5SOllivier Robert 		}
128c0b746e5SOllivier Robert 		return p;
129c0b746e5SOllivier Robert 	}
130c0b746e5SOllivier Robert #else
131c0b746e5SOllivier Robert 	char buf[10];
132c0b746e5SOllivier Robert 	LPSECURITY_ATTRIBUTES psec=0;
133c0b746e5SOllivier Robert 	HANDLE shmid=0;
134c0b746e5SOllivier Robert 	SECURITY_DESCRIPTOR sd;
135c0b746e5SOllivier Robert 	SECURITY_ATTRIBUTES sa;
136c0b746e5SOllivier Robert 	sprintf (buf,"NTP%d",unit);
137c0b746e5SOllivier Robert 	if (unit>=2) { /* world access */
138c0b746e5SOllivier Robert 		if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
139c0b746e5SOllivier Robert 			msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit);
140c0b746e5SOllivier Robert 			return 0;
141c0b746e5SOllivier Robert 		}
142c0b746e5SOllivier Robert 		if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
143c0b746e5SOllivier Robert 			msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
144c0b746e5SOllivier Robert 			return 0;
145c0b746e5SOllivier Robert 		}
146c0b746e5SOllivier Robert 		sa.nLength=sizeof (SECURITY_ATTRIBUTES);
147c0b746e5SOllivier Robert 		sa.lpSecurityDescriptor=&sd;
148c0b746e5SOllivier Robert 		sa.bInheritHandle=0;
149c0b746e5SOllivier Robert 		psec=&sa;
150c0b746e5SOllivier Robert 	}
151c0b746e5SOllivier Robert 	shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
152c0b746e5SOllivier Robert 				 0, sizeof (struct shmTime),buf);
153c0b746e5SOllivier Robert 	if (!shmid) { /*error*/
154c0b746e5SOllivier Robert 		char buf[1000];
155c0b746e5SOllivier Robert 		FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
156c0b746e5SOllivier Robert 			       0, GetLastError (), 0, buf, sizeof (buf), 0);
157c0b746e5SOllivier Robert 		msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf);
158c0b746e5SOllivier Robert 		return 0;
159c0b746e5SOllivier Robert 	}
160c0b746e5SOllivier Robert 	else {
161c0b746e5SOllivier Robert 		struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
162c0b746e5SOllivier Robert 								    FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
163c0b746e5SOllivier Robert 		if (p==0) { /*error*/
164c0b746e5SOllivier Robert 			char buf[1000];
165c0b746e5SOllivier Robert 			FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
166c0b746e5SOllivier Robert 				       0, GetLastError (), 0, buf, sizeof (buf), 0);
167c0b746e5SOllivier Robert 			msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf);
168c0b746e5SOllivier Robert 			return 0;
169c0b746e5SOllivier Robert 		}
170c0b746e5SOllivier Robert 		return p;
171c0b746e5SOllivier Robert 	}
172c0b746e5SOllivier Robert #endif
173c0b746e5SOllivier Robert 	return 0;
174c0b746e5SOllivier Robert }
175c0b746e5SOllivier Robert /*
176c0b746e5SOllivier Robert  * shm_start - attach to shared memory
177c0b746e5SOllivier Robert  */
178c0b746e5SOllivier Robert static int
179c0b746e5SOllivier Robert shm_start(
180c0b746e5SOllivier Robert 	int unit,
181c0b746e5SOllivier Robert 	struct peer *peer
182c0b746e5SOllivier Robert 	)
183c0b746e5SOllivier Robert {
184c0b746e5SOllivier Robert 	struct refclockproc *pp;
185c0b746e5SOllivier Robert 	pp = peer->procptr;
186c0b746e5SOllivier Robert 	pp->io.clock_recv = noentry;
187c0b746e5SOllivier Robert 	pp->io.srcclock = (caddr_t)peer;
188c0b746e5SOllivier Robert 	pp->io.datalen = 0;
189c0b746e5SOllivier Robert 	pp->io.fd = -1;
190c0b746e5SOllivier Robert 	pp->unitptr = (caddr_t)getShmTime(unit);
191c0b746e5SOllivier Robert 
192c0b746e5SOllivier Robert 	/*
193c0b746e5SOllivier Robert 	 * Initialize miscellaneous peer variables
194c0b746e5SOllivier Robert 	 */
195c0b746e5SOllivier Robert 	memcpy((char *)&pp->refid, REFID, 4);
196c0b746e5SOllivier Robert 	if (pp->unitptr!=0) {
197c0b746e5SOllivier Robert 		((struct shmTime*)pp->unitptr)->precision=PRECISION;
198c0b746e5SOllivier Robert 		peer->precision = ((struct shmTime*)pp->unitptr)->precision;
199c0b746e5SOllivier Robert 		((struct shmTime*)pp->unitptr)->valid=0;
200c0b746e5SOllivier Robert 		((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES;
201c0b746e5SOllivier Robert 		pp->clockdesc = DESCRIPTION;
202c0b746e5SOllivier Robert 		return (1);
203c0b746e5SOllivier Robert 	}
204c0b746e5SOllivier Robert 	else {
205c0b746e5SOllivier Robert 		return 0;
206c0b746e5SOllivier Robert 	}
207c0b746e5SOllivier Robert }
208c0b746e5SOllivier Robert 
209c0b746e5SOllivier Robert 
210c0b746e5SOllivier Robert /*
211c0b746e5SOllivier Robert  * shm_shutdown - shut down the clock
212c0b746e5SOllivier Robert  */
213c0b746e5SOllivier Robert static void
214c0b746e5SOllivier Robert shm_shutdown(
215c0b746e5SOllivier Robert 	int unit,
216c0b746e5SOllivier Robert 	struct peer *peer
217c0b746e5SOllivier Robert 	)
218c0b746e5SOllivier Robert {
219c0b746e5SOllivier Robert 	register struct shmTime *up;
220c0b746e5SOllivier Robert 	struct refclockproc *pp;
221c0b746e5SOllivier Robert 
222c0b746e5SOllivier Robert 	pp = peer->procptr;
223c0b746e5SOllivier Robert 	up = (struct shmTime *)pp->unitptr;
224c0b746e5SOllivier Robert #ifndef SYS_WINNT
225c0b746e5SOllivier Robert 	shmdt (up);
226c0b746e5SOllivier Robert #else
227c0b746e5SOllivier Robert 	UnmapViewOfFile (up);
228c0b746e5SOllivier Robert #endif
229c0b746e5SOllivier Robert }
230c0b746e5SOllivier Robert 
231c0b746e5SOllivier Robert 
232c0b746e5SOllivier Robert /*
233c0b746e5SOllivier Robert  * shm_poll - called by the transmit procedure
234c0b746e5SOllivier Robert  */
235c0b746e5SOllivier Robert static void
236c0b746e5SOllivier Robert shm_poll(
237c0b746e5SOllivier Robert 	int unit,
238c0b746e5SOllivier Robert 	struct peer *peer
239c0b746e5SOllivier Robert 	)
240c0b746e5SOllivier Robert {
241c0b746e5SOllivier Robert 	register struct shmTime *up;
242c0b746e5SOllivier Robert 	struct refclockproc *pp;
243c0b746e5SOllivier Robert 
244c0b746e5SOllivier Robert 	/*
245c0b746e5SOllivier Robert 	 * This is the main routine. It snatches the time from the shm
246c0b746e5SOllivier Robert 	 * board and tacks on a local timestamp.
247c0b746e5SOllivier Robert 	 */
248c0b746e5SOllivier Robert 	pp = peer->procptr;
249c0b746e5SOllivier Robert 	up = (struct shmTime*)pp->unitptr;
250c0b746e5SOllivier Robert 	if (up==0) { /* try to map again - this may succeed if meanwhile some-
251c0b746e5SOllivier Robert 			body has ipcrm'ed the old (unaccessible) shared mem
252c0b746e5SOllivier Robert 			segment  */
253c0b746e5SOllivier Robert 		pp->unitptr = (caddr_t)getShmTime(unit);
254c0b746e5SOllivier Robert 		up = (struct shmTime*)pp->unitptr;
255c0b746e5SOllivier Robert 	}
256c0b746e5SOllivier Robert 	if (up==0) {
257c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_FAULT);
258c0b746e5SOllivier Robert 		return;
259c0b746e5SOllivier Robert 	}
260c0b746e5SOllivier Robert 	if (up->valid) {
261c0b746e5SOllivier Robert 		struct timeval tvr;
262c0b746e5SOllivier Robert 		struct timeval tvt;
263c0b746e5SOllivier Robert 		struct tm *t;
264c0b746e5SOllivier Robert 		int ok=1;
265c0b746e5SOllivier Robert 		switch (up->mode) {
266c0b746e5SOllivier Robert 		    case 0: {
267c0b746e5SOllivier Robert 			    tvr.tv_sec=up->receiveTimeStampSec-172800;
268c0b746e5SOllivier Robert 			    tvr.tv_usec=up->receiveTimeStampUSec;
269c0b746e5SOllivier Robert 			    tvt.tv_sec=up->clockTimeStampSec;
270c0b746e5SOllivier Robert 			    tvt.tv_usec=up->clockTimeStampUSec;
271c0b746e5SOllivier Robert 		    }
272c0b746e5SOllivier Robert 		    break;
273c0b746e5SOllivier Robert 		    case 1: {
274c0b746e5SOllivier Robert 			    int cnt=up->count;
275c0b746e5SOllivier Robert 			    tvr.tv_sec=up->receiveTimeStampSec-172800;
276c0b746e5SOllivier Robert 			    tvr.tv_usec=up->receiveTimeStampUSec;
277c0b746e5SOllivier Robert 			    tvt.tv_sec=up->clockTimeStampSec;
278c0b746e5SOllivier Robert 			    tvt.tv_usec=up->clockTimeStampUSec;
279c0b746e5SOllivier Robert 			    ok=(cnt==up->count);
280c0b746e5SOllivier Robert 		    }
281c0b746e5SOllivier Robert 		    break;
282c0b746e5SOllivier Robert 		    default:
283c0b746e5SOllivier Robert 			msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode);
284c0b746e5SOllivier Robert 		}
285c0b746e5SOllivier Robert 		/*msyslog(LOG_NOTICE,"poll2a tvr.s %d tvr.u %d tvt.s %d tvt.u %d",tvr.tv_sec,tvr.tv_usec,tvt.tv_sec,tvt.tv_usec);*/
286c0b746e5SOllivier Robert 		up->valid=0;
287c0b746e5SOllivier Robert 		if (ok) {
288c0b746e5SOllivier Robert 			TVTOTS(&tvr,&pp->lastrec);
289c0b746e5SOllivier Robert 			/* pp->lasttime = current_time; */
290c0b746e5SOllivier Robert 			pp->polls++;
291c0b746e5SOllivier Robert 			t=gmtime (&tvt.tv_sec);
292c0b746e5SOllivier Robert 			pp->day=t->tm_yday;/*+2; */
293c0b746e5SOllivier Robert 			pp->hour=t->tm_hour;
294c0b746e5SOllivier Robert 			pp->minute=t->tm_min;
295c0b746e5SOllivier Robert 			pp->second=t->tm_sec;
296c0b746e5SOllivier Robert 			pp->usec=tvt.tv_usec;
297c0b746e5SOllivier Robert 			peer->precision=up->precision;
298c0b746e5SOllivier Robert 			pp->leap=up->leap;
299c0b746e5SOllivier Robert 		}
300c0b746e5SOllivier Robert 		else {
301c0b746e5SOllivier Robert 			refclock_report(peer, CEVNT_FAULT);
302c0b746e5SOllivier Robert 			msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
303c0b746e5SOllivier Robert 			return;
304c0b746e5SOllivier Robert 		}
305c0b746e5SOllivier Robert 	}
306c0b746e5SOllivier Robert 	else {
307c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_TIMEOUT);
308c0b746e5SOllivier Robert 		msyslog (LOG_NOTICE, "SHM: no new value found in shared memory");
309c0b746e5SOllivier Robert 		return;
310c0b746e5SOllivier Robert 	}
311c0b746e5SOllivier Robert 	if (!refclock_process(pp)) {
312c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADTIME);
313c0b746e5SOllivier Robert 		return;
314c0b746e5SOllivier Robert 	}
315c0b746e5SOllivier Robert 	refclock_receive(peer);
316c0b746e5SOllivier Robert }
317c0b746e5SOllivier Robert 
318c0b746e5SOllivier Robert #else
319c0b746e5SOllivier Robert int refclock_shm_bs;
320c0b746e5SOllivier Robert #endif /* REFCLOCK */
321