xref: /freebsd/contrib/ntp/ntpd/refclock_shm.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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  */
59 static  int     shm_start       (int, struct peer *);
60 static  void    shm_shutdown    (int, struct peer *);
61 static  void    shm_poll        (int unit, struct peer *);
62 
63 /*
64  * Transfer vector
65  */
66 struct  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 };
75 struct 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 };
95 struct 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  */
178 static int
179 shm_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  */
213 static void
214 shm_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  */
235 static void
236 shm_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
319 int refclock_shm_bs;
320 #endif /* REFCLOCK */
321