refclock_shm.c revision 1.1.1.1.6.1 1 /* $NetBSD: refclock_shm.c,v 1.1.1.1.6.1 2012/04/17 00:03:48 yamt Exp $ */
2
3 /*
4 * refclock_shm - clock driver for utc via shared memory
5 * - under construction -
6 * To add new modes: Extend or union the shmTime-struct. Do not
7 * extend/shrink size, because otherwise existing implementations
8 * will specify wrong size of shared memory-segment
9 * PB 18.3.97
10 */
11
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #if defined(REFCLOCK) && defined(CLOCK_SHM)
17
18 #include "ntpd.h"
19 #undef fileno
20 #include "ntp_io.h"
21 #undef fileno
22 #include "ntp_refclock.h"
23 #undef fileno
24 #include "ntp_unixtime.h"
25 #undef fileno
26 #include "ntp_stdlib.h"
27
28 #undef fileno
29 #include <ctype.h>
30 #undef fileno
31
32 #ifndef SYS_WINNT
33 # include <sys/ipc.h>
34 # include <sys/shm.h>
35 # include <assert.h>
36 # include <unistd.h>
37 # include <stdio.h>
38 #endif
39
40 /*
41 * This driver supports a reference clock attached thru shared memory
42 */
43
44 /* Temp hack to simplify testing of the old mode. */
45 #define OLDWAY 0
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 */
59 static int shm_start (int unit, struct peer *peer);
60 static void shm_shutdown (int unit, struct peer *peer);
61 static void shm_poll (int unit, struct peer *peer);
62 static void shm_timer (int unit, struct peer *peer);
63 int shm_peek (int unit, struct peer *peer);
64 void shm_clockstats (int unit, struct peer *peer);
65
66 /*
67 * Transfer vector
68 */
69 struct refclock refclock_shm = {
70 shm_start, /* start up driver */
71 shm_shutdown, /* shut down driver */
72 shm_poll, /* transmit poll message */
73 noentry, /* not used: control */
74 noentry, /* not used: init */
75 noentry, /* not used: buginfo */
76 shm_timer, /* once per second */
77 };
78
79 struct shmTime {
80 int mode; /* 0 - if valid set
81 * use values,
82 * clear valid
83 * 1 - if valid set
84 * if count before and after read of values is equal,
85 * use values
86 * clear valid
87 */
88 int count;
89 time_t clockTimeStampSec;
90 int clockTimeStampUSec;
91 time_t receiveTimeStampSec;
92 int receiveTimeStampUSec;
93 int leap;
94 int precision;
95 int nsamples;
96 int valid;
97 int dummy[10];
98 };
99
100 struct shmunit {
101 struct shmTime *shm; /* pointer to shared memory segment */
102
103 /* debugging/monitoring counters - reset when printed */
104 int ticks; /* number of attempts to read data*/
105 int good; /* number of valid samples */
106 int notready; /* number of peeks without data ready */
107 int bad; /* number of invalid samples */
108 int clash; /* number of access clashes while reading */
109 };
110
111
112 struct shmTime *getShmTime(int);
113
114 struct shmTime *getShmTime (int unit) {
115 #ifndef SYS_WINNT
116 int shmid=0;
117
118 /* 0x4e545030 is NTP0.
119 * Big units will give non-ascii but that's OK
120 * as long as everybody does it the same way.
121 */
122 shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
123 IPC_CREAT|(unit<2?0600:0666));
124 if (shmid==-1) { /*error */
125 msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
126 return 0;
127 }
128 else { /* no error */
129 struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
130 if ((int)(long)p==-1) { /* error */
131 msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno));
132 return 0;
133 }
134 return p;
135 }
136 #else
137 char buf[10];
138 LPSECURITY_ATTRIBUTES psec=0;
139 HANDLE shmid=0;
140 SECURITY_DESCRIPTOR sd;
141 SECURITY_ATTRIBUTES sa;
142 snprintf(buf, sizeof(buf), "NTP%d", unit);
143 if (unit >= 2) { /* world access */
144 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
145 msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit);
146 return 0;
147 }
148 if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
149 msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
150 return 0;
151 }
152 sa.nLength=sizeof (SECURITY_ATTRIBUTES);
153 sa.lpSecurityDescriptor=&sd;
154 sa.bInheritHandle=0;
155 psec=&sa;
156 }
157 shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
158 0, sizeof (struct shmTime),buf);
159 if (!shmid) { /*error*/
160 char buf[1000];
161 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
162 0, GetLastError (), 0, buf, sizeof (buf), 0);
163 msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf);
164 return 0;
165 }
166 else {
167 struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
168 FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
169 if (p==0) { /*error*/
170 char buf[1000];
171 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
172 0, GetLastError (), 0, buf, sizeof (buf), 0);
173 msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf);
174 return 0;
175 }
176 return p;
177 }
178 #endif
179 }
180 /*
181 * shm_start - attach to shared memory
182 */
183 static int
184 shm_start(
185 int unit,
186 struct peer *peer
187 )
188 {
189 struct refclockproc *pp;
190 struct shmunit *up;
191
192 pp = peer->procptr;
193 pp->io.clock_recv = noentry;
194 pp->io.srcclock = (caddr_t)peer;
195 pp->io.datalen = 0;
196 pp->io.fd = -1;
197
198 up = emalloc(sizeof(*up));
199 memset(up, 0, sizeof(*up));
200 pp->unitptr = (caddr_t)up;
201
202 up->shm = getShmTime(unit);
203
204 /*
205 * Initialize miscellaneous peer variables
206 */
207 memcpy((char *)&pp->refid, REFID, 4);
208 if (up->shm != 0) {
209 up->shm->precision = PRECISION;
210 peer->precision = up->shm->precision;
211 up->shm->valid=0;
212 up->shm->nsamples=NSAMPLES;
213 pp->clockdesc = DESCRIPTION;
214 return (1);
215 }
216 else {
217 return 0;
218 }
219 }
220
221
222 /*
223 * shm_shutdown - shut down the clock
224 */
225 static void
226 shm_shutdown(
227 int unit,
228 struct peer *peer
229 )
230 {
231 struct refclockproc *pp;
232 struct shmunit *up;
233
234 pp = peer->procptr;
235 up = (struct shmunit *)pp->unitptr;
236
237 if (NULL == up)
238 return;
239 #ifndef SYS_WINNT
240 /* HMS: shmdt()wants char* or const void * */
241 (void) shmdt ((char *)up->shm);
242 #else
243 UnmapViewOfFile (up->shm);
244 #endif
245 free(up);
246 }
247
248
249 /*
250 * shm_timer - called every second
251 */
252 static void
253 shm_timer(int unit, struct peer *peer)
254 {
255 if (OLDWAY)
256 return;
257
258 shm_peek(unit, peer);
259 }
260
261
262 /*
263 * shm_poll - called by the transmit procedure
264 */
265 static void
266 shm_poll(
267 int unit,
268 struct peer *peer
269 )
270 {
271 struct refclockproc *pp;
272 int ok;
273
274 pp = peer->procptr;
275
276 if (OLDWAY) {
277 ok = shm_peek(unit, peer);
278 if (!ok) return;
279 }
280
281 /*
282 * Process median filter samples. If none received, declare a
283 * timeout and keep going.
284 */
285 if (pp->coderecv == pp->codeproc) {
286 refclock_report(peer, CEVNT_TIMEOUT);
287 shm_clockstats(unit, peer);
288 return;
289 }
290 pp->lastref = pp->lastrec;
291 refclock_receive(peer);
292 shm_clockstats(unit, peer);
293 }
294
295 /*
296 * shm_peek - try to grab a sample
297 */
298 int shm_peek(
299 int unit,
300 struct peer *peer
301 )
302 {
303 struct refclockproc *pp;
304 struct shmunit *up;
305 struct shmTime *shm;
306
307 /*
308 * This is the main routine. It snatches the time from the shm
309 * board and tacks on a local timestamp.
310 */
311 pp = peer->procptr;
312 up = (struct shmunit*)pp->unitptr;
313 up->ticks++;
314 if (up->shm == 0) {
315 /* try to map again - this may succeed if meanwhile some-
316 body has ipcrm'ed the old (unaccessible) shared mem segment */
317 up->shm = getShmTime(unit);
318 }
319 shm = up->shm;
320 if (shm == 0) {
321 refclock_report(peer, CEVNT_FAULT);
322 return(0);
323 }
324 if (shm->valid) {
325 struct timeval tvr;
326 struct timeval tvt;
327 struct tm *t;
328 int ok=1;
329 tvr.tv_sec = 0;
330 tvr.tv_usec = 0;
331 tvt.tv_sec = 0;
332 tvt.tv_usec = 0;
333 switch (shm->mode) {
334 case 0: {
335 tvr.tv_sec=shm->receiveTimeStampSec;
336 tvr.tv_usec=shm->receiveTimeStampUSec;
337 tvt.tv_sec=shm->clockTimeStampSec;
338 tvt.tv_usec=shm->clockTimeStampUSec;
339 }
340 break;
341 case 1: {
342 int cnt=shm->count;
343 tvr.tv_sec=shm->receiveTimeStampSec;
344 tvr.tv_usec=shm->receiveTimeStampUSec;
345 tvt.tv_sec=shm->clockTimeStampSec;
346 tvt.tv_usec=shm->clockTimeStampUSec;
347 ok=(cnt==shm->count);
348 }
349 break;
350 default:
351 msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode);
352 }
353 shm->valid=0;
354 if (ok) {
355 time_t help; /* XXX NetBSD has incompatible tv_sec */
356
357 TVTOTS(&tvr,&pp->lastrec);
358 pp->lastrec.l_ui += JAN_1970;
359 /* pp->lasttime = current_time; */
360 pp->polls++;
361 help = tvt.tv_sec;
362 t = gmtime (&help);
363 pp->day=t->tm_yday+1;
364 pp->hour=t->tm_hour;
365 pp->minute=t->tm_min;
366 pp->second=t->tm_sec;
367 pp->nsec=tvt.tv_usec * 1000;
368 peer->precision=shm->precision;
369 pp->leap=shm->leap;
370 }
371 else {
372 refclock_report(peer, CEVNT_FAULT);
373 msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
374 up->clash++;
375 return(0);
376 }
377 }
378 else {
379 refclock_report(peer, CEVNT_TIMEOUT);
380 up->notready++;
381 return(0);
382 }
383 if (!refclock_process(pp)) {
384 refclock_report(peer, CEVNT_BADTIME);
385 up->bad++;
386 return(0);
387 }
388 up->good++;
389 return(1);
390 }
391
392 /*
393 * shm_clockstats - dump and reset counters
394 */
395 void shm_clockstats(
396 int unit,
397 struct peer *peer
398 )
399 {
400 struct refclockproc *pp;
401 struct shmunit *up;
402 char logbuf[256];
403
404 pp = peer->procptr;
405 up = (struct shmunit*)pp->unitptr;
406
407 if (!(pp->sloppyclockflag & CLK_FLAG4)) return;
408
409 snprintf(logbuf, sizeof(logbuf), "%3d %3d %3d %3d %3d",
410 up->ticks, up->good, up->notready, up->bad, up->clash);
411 record_clock_stats(&peer->srcadr, logbuf);
412
413 up->ticks = up->good = up->notready =up->bad = up->clash = 0;
414
415 }
416
417 #else
418 int refclock_shm_bs;
419 #endif /* REFCLOCK */
420