xref: /freebsd/contrib/ntp/ntpd/refclock_shm.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 
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
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
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
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 		switch (up->mode) {
248 		    case 0: {
249 			    tvr.tv_sec=up->receiveTimeStampSec;
250 			    tvr.tv_usec=up->receiveTimeStampUSec;
251 			    tvt.tv_sec=up->clockTimeStampSec;
252 			    tvt.tv_usec=up->clockTimeStampUSec;
253 		    }
254 		    break;
255 		    case 1: {
256 			    int cnt=up->count;
257 			    tvr.tv_sec=up->receiveTimeStampSec;
258 			    tvr.tv_usec=up->receiveTimeStampUSec;
259 			    tvt.tv_sec=up->clockTimeStampSec;
260 			    tvt.tv_usec=up->clockTimeStampUSec;
261 			    ok=(cnt==up->count);
262 		    }
263 		    break;
264 		    default:
265 			msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode);
266 		}
267 		up->valid=0;
268 		if (ok) {
269 			TVTOTS(&tvr,&pp->lastrec);
270 			pp->lastrec.l_ui += JAN_1970;
271 			/* pp->lasttime = current_time; */
272 			pp->polls++;
273 			t=gmtime (&tvt.tv_sec);
274 			pp->day=t->tm_yday+1;
275 			pp->hour=t->tm_hour;
276 			pp->minute=t->tm_min;
277 			pp->second=t->tm_sec;
278 			pp->nsec=tvt.tv_usec * 1000;
279 			peer->precision=up->precision;
280 			pp->leap=up->leap;
281 		}
282 		else {
283 			refclock_report(peer, CEVNT_FAULT);
284 			msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
285 			return;
286 		}
287 	}
288 	else {
289 		refclock_report(peer, CEVNT_TIMEOUT);
290 		/*
291 		msyslog (LOG_NOTICE, "SHM: no new value found in shared memory");
292 		*/
293 		return;
294 	}
295 	if (!refclock_process(pp)) {
296 		refclock_report(peer, CEVNT_BADTIME);
297 		return;
298 	}
299 	pp->lastref = pp->lastrec;
300 	refclock_receive(peer);
301 }
302 
303 #else
304 int refclock_shm_bs;
305 #endif /* REFCLOCK */
306