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 */
54 static int shm_start (int, struct peer *);
55 static void shm_shutdown (int, struct peer *);
56 static void shm_poll (int unit, struct peer *);
57
58 /*
59 * Transfer vector
60 */
61 struct 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 };
70 struct 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 };
90
91 struct shmTime *getShmTime(int);
92
getShmTime(int unit)93 struct shmTime *getShmTime (int unit) {
94 #ifndef SYS_WINNT
95 int shmid=0;
96
97 assert (unit<10); /* MAXUNIT is 4, so should never happen */
98 shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
99 IPC_CREAT|(unit<2?0700:0777));
100 if (shmid==-1) { /*error */
101 msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
102 return 0;
103 }
104 else { /* no error */
105 struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
106 if ((int)(long)p==-1) { /* error */
107 msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno));
108 return 0;
109 }
110 return p;
111 }
112 #else
113 char buf[10];
114 LPSECURITY_ATTRIBUTES psec=0;
115 HANDLE shmid=0;
116 SECURITY_DESCRIPTOR sd;
117 SECURITY_ATTRIBUTES sa;
118 sprintf (buf,"NTP%d",unit);
119 if (unit>=2) { /* world access */
120 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
121 msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit);
122 return 0;
123 }
124 if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
125 msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
126 return 0;
127 }
128 sa.nLength=sizeof (SECURITY_ATTRIBUTES);
129 sa.lpSecurityDescriptor=&sd;
130 sa.bInheritHandle=0;
131 psec=&sa;
132 }
133 shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
134 0, sizeof (struct shmTime),buf);
135 if (!shmid) { /*error*/
136 char buf[1000];
137 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
138 0, GetLastError (), 0, buf, sizeof (buf), 0);
139 msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf);
140 return 0;
141 }
142 else {
143 struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
144 FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
145 if (p==0) { /*error*/
146 char buf[1000];
147 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
148 0, GetLastError (), 0, buf, sizeof (buf), 0);
149 msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf);
150 return 0;
151 }
152 return p;
153 }
154 #endif
155 }
156 /*
157 * shm_start - attach to shared memory
158 */
159 static int
shm_start(int unit,struct peer * peer)160 shm_start(
161 int unit,
162 struct peer *peer
163 )
164 {
165 struct refclockproc *pp;
166 pp = peer->procptr;
167 pp->io.clock_recv = noentry;
168 pp->io.srcclock = (caddr_t)peer;
169 pp->io.datalen = 0;
170 pp->io.fd = -1;
171 pp->unitptr = (caddr_t)getShmTime(unit);
172
173 /*
174 * Initialize miscellaneous peer variables
175 */
176 memcpy((char *)&pp->refid, REFID, 4);
177 if (pp->unitptr!=0) {
178 ((struct shmTime*)pp->unitptr)->precision=PRECISION;
179 peer->precision = ((struct shmTime*)pp->unitptr)->precision;
180 ((struct shmTime*)pp->unitptr)->valid=0;
181 ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES;
182 pp->clockdesc = DESCRIPTION;
183 return (1);
184 }
185 else {
186 return 0;
187 }
188 }
189
190
191 /*
192 * shm_shutdown - shut down the clock
193 */
194 static void
shm_shutdown(int unit,struct peer * peer)195 shm_shutdown(
196 int unit,
197 struct peer *peer
198 )
199 {
200 register struct shmTime *up;
201 struct refclockproc *pp;
202
203 pp = peer->procptr;
204 up = (struct shmTime *)pp->unitptr;
205 #ifndef SYS_WINNT
206 /* HMS: shmdt()wants char* or const void * */
207 (void) shmdt (up);
208 #else
209 UnmapViewOfFile (up);
210 #endif
211 }
212
213
214 /*
215 * shm_poll - called by the transmit procedure
216 */
217 static void
shm_poll(int unit,struct peer * peer)218 shm_poll(
219 int unit,
220 struct peer *peer
221 )
222 {
223 register struct shmTime *up;
224 struct refclockproc *pp;
225
226 /*
227 * This is the main routine. It snatches the time from the shm
228 * board and tacks on a local timestamp.
229 */
230 pp = peer->procptr;
231 up = (struct shmTime*)pp->unitptr;
232 if (up==0) { /* try to map again - this may succeed if meanwhile some-
233 body has ipcrm'ed the old (unaccessible) shared mem
234 segment */
235 pp->unitptr = (caddr_t)getShmTime(unit);
236 up = (struct shmTime*)pp->unitptr;
237 }
238 if (up==0) {
239 refclock_report(peer, CEVNT_FAULT);
240 return;
241 }
242 if (up->valid) {
243 struct timeval tvr;
244 struct timeval tvt;
245 struct tm *t;
246 int ok=1;
247 tvr.tv_sec = 0;
248 tvr.tv_usec = 0;
249 tvt.tv_sec = 0;
250 tvt.tv_usec = 0;
251 switch (up->mode) {
252 case 0: {
253 tvr.tv_sec=up->receiveTimeStampSec;
254 tvr.tv_usec=up->receiveTimeStampUSec;
255 tvt.tv_sec=up->clockTimeStampSec;
256 tvt.tv_usec=up->clockTimeStampUSec;
257 }
258 break;
259 case 1: {
260 int cnt=up->count;
261 tvr.tv_sec=up->receiveTimeStampSec;
262 tvr.tv_usec=up->receiveTimeStampUSec;
263 tvt.tv_sec=up->clockTimeStampSec;
264 tvt.tv_usec=up->clockTimeStampUSec;
265 ok=(cnt==up->count);
266 }
267 break;
268 default:
269 msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode);
270 }
271 up->valid=0;
272 if (ok) {
273 time_t help; /* XXX NetBSD has incompatible tv_sec */
274
275 TVTOTS(&tvr,&pp->lastrec);
276 pp->lastrec.l_ui += JAN_1970;
277 /* pp->lasttime = current_time; */
278 pp->polls++;
279 help = tvt.tv_sec;
280 t = gmtime (&help);
281 pp->day=t->tm_yday+1;
282 pp->hour=t->tm_hour;
283 pp->minute=t->tm_min;
284 pp->second=t->tm_sec;
285 pp->nsec=tvt.tv_usec * 1000;
286 peer->precision=up->precision;
287 pp->leap=up->leap;
288 }
289 else {
290 refclock_report(peer, CEVNT_FAULT);
291 msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
292 return;
293 }
294 }
295 else {
296 refclock_report(peer, CEVNT_TIMEOUT);
297 /*
298 msyslog (LOG_NOTICE, "SHM: no new value found in shared memory");
299 */
300 return;
301 }
302 if (!refclock_process(pp)) {
303 refclock_report(peer, CEVNT_BADTIME);
304 return;
305 }
306 pp->lastref = pp->lastrec;
307 refclock_receive(peer);
308 }
309
310 #else
311 int refclock_shm_bs;
312 #endif /* REFCLOCK */
313