1 /* $NetBSD: refclock_shm.c,v 1.1.1.1 2009/12/13 16:56:03 kardel Exp $ */ 2 3 /* 4 * refclock_shm - clock driver for utc via shared memory 5 * - under construction - 6 * To add new modes: Extend or union the shmTime-struct. Do not 7 * extend/shrink size, because otherwise existing implementations 8 * will specify wrong size of shared memory-segment 9 * PB 18.3.97 10 */ 11 12 #ifdef HAVE_CONFIG_H 13 # include <config.h> 14 #endif 15 16 #if defined(REFCLOCK) && defined(CLOCK_SHM) 17 18 #include "ntpd.h" 19 #undef fileno 20 #include "ntp_io.h" 21 #undef fileno 22 #include "ntp_refclock.h" 23 #undef fileno 24 #include "ntp_unixtime.h" 25 #undef fileno 26 #include "ntp_stdlib.h" 27 28 #undef fileno 29 #include <ctype.h> 30 #undef fileno 31 32 #ifndef SYS_WINNT 33 # include <sys/ipc.h> 34 # include <sys/shm.h> 35 # include <assert.h> 36 # include <unistd.h> 37 # include <stdio.h> 38 #endif 39 40 /* 41 * This driver supports a reference clock attached thru shared memory 42 */ 43 44 /* Temp hack to simplify testing of the old mode. */ 45 #define OLDWAY 0 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 unit, struct peer *peer); 60 static void shm_shutdown (int unit, struct peer *peer); 61 static void shm_poll (int unit, struct peer *peer); 62 static void shm_timer (int unit, struct peer *peer); 63 int shm_peek (int unit, struct peer *peer); 64 void shm_clockstats (int unit, struct peer *peer); 65 66 /* 67 * Transfer vector 68 */ 69 struct refclock refclock_shm = { 70 shm_start, /* start up driver */ 71 shm_shutdown, /* shut down driver */ 72 shm_poll, /* transmit poll message */ 73 noentry, /* not used: control */ 74 noentry, /* not used: init */ 75 noentry, /* not used: buginfo */ 76 shm_timer, /* once per second */ 77 }; 78 79 struct shmTime { 80 int mode; /* 0 - if valid set 81 * use values, 82 * clear valid 83 * 1 - if valid set 84 * if count before and after read of values is equal, 85 * use values 86 * clear valid 87 */ 88 int count; 89 time_t clockTimeStampSec; 90 int clockTimeStampUSec; 91 time_t receiveTimeStampSec; 92 int receiveTimeStampUSec; 93 int leap; 94 int precision; 95 int nsamples; 96 int valid; 97 int dummy[10]; 98 }; 99 100 struct shmunit { 101 struct shmTime *shm; /* pointer to shared memory segment */ 102 103 /* debugging/monitoring counters - reset when printed */ 104 int ticks; /* number of attempts to read data*/ 105 int good; /* number of valid samples */ 106 int notready; /* number of peeks without data ready */ 107 int bad; /* number of invalid samples */ 108 int clash; /* number of access clashes while reading */ 109 }; 110 111 112 struct shmTime *getShmTime(int); 113 114 struct shmTime *getShmTime (int unit) { 115 #ifndef SYS_WINNT 116 int shmid=0; 117 118 /* 0x4e545030 is NTP0. 119 * Big units will give non-ascii but that's OK 120 * as long as everybody does it the same way. 121 */ 122 shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), 123 IPC_CREAT|(unit<2?0600:0666)); 124 if (shmid==-1) { /*error */ 125 msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno)); 126 return 0; 127 } 128 else { /* no error */ 129 struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); 130 if ((int)(long)p==-1) { /* error */ 131 msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno)); 132 return 0; 133 } 134 return p; 135 } 136 #else 137 char buf[10]; 138 LPSECURITY_ATTRIBUTES psec=0; 139 HANDLE shmid=0; 140 SECURITY_DESCRIPTOR sd; 141 SECURITY_ATTRIBUTES sa; 142 sprintf (buf,"NTP%d",unit); 143 if (unit>=2) { /* world access */ 144 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { 145 msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit); 146 return 0; 147 } 148 if (!SetSecurityDescriptorDacl(&sd,1,0,0)) { 149 msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit); 150 return 0; 151 } 152 sa.nLength=sizeof (SECURITY_ATTRIBUTES); 153 sa.lpSecurityDescriptor=&sd; 154 sa.bInheritHandle=0; 155 psec=&sa; 156 } 157 shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, 158 0, sizeof (struct shmTime),buf); 159 if (!shmid) { /*error*/ 160 char buf[1000]; 161 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 162 0, GetLastError (), 0, buf, sizeof (buf), 0); 163 msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf); 164 return 0; 165 } 166 else { 167 struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, 168 FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); 169 if (p==0) { /*error*/ 170 char buf[1000]; 171 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 172 0, GetLastError (), 0, buf, sizeof (buf), 0); 173 msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf); 174 return 0; 175 } 176 return p; 177 } 178 #endif 179 } 180 /* 181 * shm_start - attach to shared memory 182 */ 183 static int 184 shm_start( 185 int unit, 186 struct peer *peer 187 ) 188 { 189 struct refclockproc *pp; 190 struct shmunit *up; 191 192 pp = peer->procptr; 193 pp->io.clock_recv = noentry; 194 pp->io.srcclock = (caddr_t)peer; 195 pp->io.datalen = 0; 196 pp->io.fd = -1; 197 198 up = (struct shmunit *) emalloc(sizeof(*up)); 199 if (up == NULL) 200 return (FALSE); 201 memset((char *)up, 0, sizeof(*up)); 202 pp->unitptr = (caddr_t)up; 203 204 up->shm = getShmTime(unit); 205 206 /* 207 * Initialize miscellaneous peer variables 208 */ 209 memcpy((char *)&pp->refid, REFID, 4); 210 if (up->shm != 0) { 211 up->shm->precision = PRECISION; 212 peer->precision = up->shm->precision; 213 up->shm->valid=0; 214 up->shm->nsamples=NSAMPLES; 215 pp->clockdesc = DESCRIPTION; 216 return (1); 217 } 218 else { 219 return 0; 220 } 221 } 222 223 224 /* 225 * shm_shutdown - shut down the clock 226 */ 227 static void 228 shm_shutdown( 229 int unit, 230 struct peer *peer 231 ) 232 { 233 struct refclockproc *pp; 234 struct shmunit *up; 235 236 pp = peer->procptr; 237 up = (struct shmunit *)pp->unitptr; 238 #ifndef SYS_WINNT 239 /* HMS: shmdt()wants char* or const void * */ 240 (void) shmdt ((char *)up->shm); 241 #else 242 UnmapViewOfFile (up->shm); 243 #endif 244 } 245 246 247 /* 248 * shm_timer - called every second 249 */ 250 static void 251 shm_timer(int unit, struct peer *peer) 252 { 253 if (OLDWAY) 254 return; 255 256 shm_peek(unit, peer); 257 } 258 259 260 /* 261 * shm_poll - called by the transmit procedure 262 */ 263 static void 264 shm_poll( 265 int unit, 266 struct peer *peer 267 ) 268 { 269 struct refclockproc *pp; 270 int ok; 271 272 pp = peer->procptr; 273 274 if (OLDWAY) { 275 ok = shm_peek(unit, peer); 276 if (!ok) return; 277 } 278 279 /* 280 * Process median filter samples. If none received, declare a 281 * timeout and keep going. 282 */ 283 if (pp->coderecv == pp->codeproc) { 284 refclock_report(peer, CEVNT_TIMEOUT); 285 shm_clockstats(unit, peer); 286 return; 287 } 288 pp->lastref = pp->lastrec; 289 refclock_receive(peer); 290 shm_clockstats(unit, peer); 291 } 292 293 /* 294 * shm_peek - try to grab a sample 295 */ 296 int shm_peek( 297 int unit, 298 struct peer *peer 299 ) 300 { 301 struct refclockproc *pp; 302 struct shmunit *up; 303 struct shmTime *shm; 304 305 /* 306 * This is the main routine. It snatches the time from the shm 307 * board and tacks on a local timestamp. 308 */ 309 pp = peer->procptr; 310 up = (struct shmunit*)pp->unitptr; 311 up->ticks++; 312 if (up->shm == 0) { 313 /* try to map again - this may succeed if meanwhile some- 314 body has ipcrm'ed the old (unaccessible) shared mem segment */ 315 up->shm = getShmTime(unit); 316 } 317 shm = up->shm; 318 if (shm == 0) { 319 refclock_report(peer, CEVNT_FAULT); 320 return(0); 321 } 322 if (shm->valid) { 323 struct timeval tvr; 324 struct timeval tvt; 325 struct tm *t; 326 int ok=1; 327 tvr.tv_sec = 0; 328 tvr.tv_usec = 0; 329 tvt.tv_sec = 0; 330 tvt.tv_usec = 0; 331 switch (shm->mode) { 332 case 0: { 333 tvr.tv_sec=shm->receiveTimeStampSec; 334 tvr.tv_usec=shm->receiveTimeStampUSec; 335 tvt.tv_sec=shm->clockTimeStampSec; 336 tvt.tv_usec=shm->clockTimeStampUSec; 337 } 338 break; 339 case 1: { 340 int cnt=shm->count; 341 tvr.tv_sec=shm->receiveTimeStampSec; 342 tvr.tv_usec=shm->receiveTimeStampUSec; 343 tvt.tv_sec=shm->clockTimeStampSec; 344 tvt.tv_usec=shm->clockTimeStampUSec; 345 ok=(cnt==shm->count); 346 } 347 break; 348 default: 349 msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode); 350 } 351 shm->valid=0; 352 if (ok) { 353 time_t help; /* XXX NetBSD has incompatible tv_sec */ 354 355 TVTOTS(&tvr,&pp->lastrec); 356 pp->lastrec.l_ui += JAN_1970; 357 /* pp->lasttime = current_time; */ 358 pp->polls++; 359 help = tvt.tv_sec; 360 t = gmtime (&help); 361 pp->day=t->tm_yday+1; 362 pp->hour=t->tm_hour; 363 pp->minute=t->tm_min; 364 pp->second=t->tm_sec; 365 pp->nsec=tvt.tv_usec * 1000; 366 peer->precision=shm->precision; 367 pp->leap=shm->leap; 368 } 369 else { 370 refclock_report(peer, CEVNT_FAULT); 371 msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); 372 up->clash++; 373 return(0); 374 } 375 } 376 else { 377 refclock_report(peer, CEVNT_TIMEOUT); 378 up->notready++; 379 return(0); 380 } 381 if (!refclock_process(pp)) { 382 refclock_report(peer, CEVNT_BADTIME); 383 up->bad++; 384 return(0); 385 } 386 up->good++; 387 return(1); 388 } 389 390 /* 391 * shm_clockstats - dump and reset counters 392 */ 393 void shm_clockstats( 394 int unit, 395 struct peer *peer 396 ) 397 { 398 struct refclockproc *pp; 399 struct shmunit *up; 400 char logbuf[256]; 401 402 pp = peer->procptr; 403 up = (struct shmunit*)pp->unitptr; 404 405 if (!(pp->sloppyclockflag & CLK_FLAG4)) return; 406 407 snprintf(logbuf, sizeof(logbuf), "%3d %3d %3d %3d %3d", 408 up->ticks, up->good, up->notready, up->bad, up->clash); 409 record_clock_stats(&peer->srcadr, logbuf); 410 411 up->ticks = up->good = up->notready =up->bad = up->clash = 0; 412 413 } 414 415 #else 416 int refclock_shm_bs; 417 #endif /* REFCLOCK */ 418