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