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