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