]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/ntpd/refclock_shm.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / ntpd / refclock_shm.c
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                 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 */