1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * refclock_shm - clock driver for utc via shared memory 3c0b746e5SOllivier Robert * - under construction - 4c0b746e5SOllivier Robert * To add new modes: Extend or union the shmTime-struct. Do not 5c0b746e5SOllivier Robert * extend/shrink size, because otherwise existing implementations 6c0b746e5SOllivier Robert * will specify wrong size of shared memory-segment 7c0b746e5SOllivier Robert * PB 18.3.97 8c0b746e5SOllivier Robert */ 9c0b746e5SOllivier Robert 10c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 11c0b746e5SOllivier Robert # include <config.h> 12c0b746e5SOllivier Robert #endif 13c0b746e5SOllivier Robert 14c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_SHM) 15c0b746e5SOllivier Robert 16c0b746e5SOllivier Robert #undef fileno 17c0b746e5SOllivier Robert #include <ctype.h> 18c0b746e5SOllivier Robert #undef fileno 19c0b746e5SOllivier Robert #include <sys/time.h> 20c0b746e5SOllivier Robert #undef fileno 21c0b746e5SOllivier Robert 22c0b746e5SOllivier Robert #include "ntpd.h" 23c0b746e5SOllivier Robert #undef fileno 24c0b746e5SOllivier Robert #include "ntp_io.h" 25c0b746e5SOllivier Robert #undef fileno 26c0b746e5SOllivier Robert #include "ntp_refclock.h" 27c0b746e5SOllivier Robert #undef fileno 28c0b746e5SOllivier Robert #include "ntp_unixtime.h" 29c0b746e5SOllivier Robert #undef fileno 30c0b746e5SOllivier Robert #include "ntp_stdlib.h" 31c0b746e5SOllivier Robert 32c0b746e5SOllivier Robert #ifndef SYS_WINNT 33c0b746e5SOllivier Robert #include <sys/types.h> 34c0b746e5SOllivier Robert #include <sys/ipc.h> 35c0b746e5SOllivier Robert #include <sys/shm.h> 36c0b746e5SOllivier Robert #include <assert.h> 37c0b746e5SOllivier Robert #include <time.h> 38c0b746e5SOllivier Robert #include <unistd.h> 39c0b746e5SOllivier Robert #include <stdlib.h> 40c0b746e5SOllivier Robert #include <stdio.h> 41c0b746e5SOllivier Robert #endif 42c0b746e5SOllivier Robert 43c0b746e5SOllivier Robert /* 44c0b746e5SOllivier Robert * This driver supports a reference clock attached thru shared memory 45c0b746e5SOllivier Robert */ 46c0b746e5SOllivier Robert 47c0b746e5SOllivier Robert /* 48c0b746e5SOllivier Robert * SHM interface definitions 49c0b746e5SOllivier Robert */ 50c0b746e5SOllivier Robert #define PRECISION (-1) /* precision assumed (0.5 s) */ 51c0b746e5SOllivier Robert #define REFID "SHM" /* reference ID */ 52c0b746e5SOllivier Robert #define DESCRIPTION "SHM/Shared memory interface" 53c0b746e5SOllivier Robert 54c0b746e5SOllivier Robert #define NSAMPLES 3 /* stages of median filter */ 55c0b746e5SOllivier Robert 56c0b746e5SOllivier Robert /* 57c0b746e5SOllivier Robert * Function prototypes 58c0b746e5SOllivier Robert */ 59c0b746e5SOllivier Robert static int shm_start (int, struct peer *); 60c0b746e5SOllivier Robert static void shm_shutdown (int, struct peer *); 61c0b746e5SOllivier Robert static void shm_poll (int unit, struct peer *); 62c0b746e5SOllivier Robert 63c0b746e5SOllivier Robert /* 64c0b746e5SOllivier Robert * Transfer vector 65c0b746e5SOllivier Robert */ 66c0b746e5SOllivier Robert struct refclock refclock_shm = { 67c0b746e5SOllivier Robert shm_start, /* start up driver */ 68c0b746e5SOllivier Robert shm_shutdown, /* shut down driver */ 69c0b746e5SOllivier Robert shm_poll, /* transmit poll message */ 70c0b746e5SOllivier Robert noentry, /* not used */ 71c0b746e5SOllivier Robert noentry, /* initialize driver (not used) */ 72c0b746e5SOllivier Robert noentry, /* not used */ 73c0b746e5SOllivier Robert NOFLAGS /* not used */ 74c0b746e5SOllivier Robert }; 75c0b746e5SOllivier Robert struct shmTime { 76c0b746e5SOllivier Robert int mode; /* 0 - if valid set 77c0b746e5SOllivier Robert * use values, 78c0b746e5SOllivier Robert * clear valid 79c0b746e5SOllivier Robert * 1 - if valid set 80c0b746e5SOllivier Robert * if count before and after read of values is equal, 81c0b746e5SOllivier Robert * use values 82c0b746e5SOllivier Robert * clear valid 83c0b746e5SOllivier Robert */ 84c0b746e5SOllivier Robert int count; 85c0b746e5SOllivier Robert time_t clockTimeStampSec; 86c0b746e5SOllivier Robert int clockTimeStampUSec; 87c0b746e5SOllivier Robert time_t receiveTimeStampSec; 88c0b746e5SOllivier Robert int receiveTimeStampUSec; 89c0b746e5SOllivier Robert int leap; 90c0b746e5SOllivier Robert int precision; 91c0b746e5SOllivier Robert int nsamples; 92c0b746e5SOllivier Robert int valid; 93c0b746e5SOllivier Robert int dummy[10]; 94c0b746e5SOllivier Robert }; 95c0b746e5SOllivier Robert struct shmTime *getShmTime (int unit) { 96c0b746e5SOllivier Robert #ifndef SYS_WINNT 97c0b746e5SOllivier Robert extern char *sys_errlist[ ]; 98c0b746e5SOllivier Robert extern int sys_nerr; 99c0b746e5SOllivier Robert int shmid=0; 100c0b746e5SOllivier Robert 101c0b746e5SOllivier Robert assert (unit<10); /* MAXUNIT is 4, so should never happen */ 102c0b746e5SOllivier Robert shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), 103c0b746e5SOllivier Robert IPC_CREAT|(unit<2?0700:0777)); 104c0b746e5SOllivier Robert if (shmid==-1) { /*error */ 105c0b746e5SOllivier Robert char buf[20]; 106c0b746e5SOllivier Robert char *pe=buf; 107c0b746e5SOllivier Robert if (errno<sys_nerr) 108c0b746e5SOllivier Robert pe=sys_errlist[errno]; 109c0b746e5SOllivier Robert else { 110c0b746e5SOllivier Robert sprintf (buf,"errno=%d",errno); 111c0b746e5SOllivier Robert } 112c0b746e5SOllivier Robert msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,pe); 113c0b746e5SOllivier Robert return 0; 114c0b746e5SOllivier Robert } 115c0b746e5SOllivier Robert else { /* no error */ 116c0b746e5SOllivier Robert struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); 117c0b746e5SOllivier Robert if ((int)(long)p==-1) { /* error */ 118c0b746e5SOllivier Robert char buf[20]; 119c0b746e5SOllivier Robert char *pe=buf; 120c0b746e5SOllivier Robert if (errno<sys_nerr) 121c0b746e5SOllivier Robert pe=sys_errlist[errno]; 122c0b746e5SOllivier Robert else { 123c0b746e5SOllivier Robert sprintf (buf,"errno=%d",errno); 124c0b746e5SOllivier Robert } 125c0b746e5SOllivier Robert msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,pe); 126c0b746e5SOllivier Robert return 0; 127c0b746e5SOllivier Robert } 128c0b746e5SOllivier Robert return p; 129c0b746e5SOllivier Robert } 130c0b746e5SOllivier Robert #else 131c0b746e5SOllivier Robert char buf[10]; 132c0b746e5SOllivier Robert LPSECURITY_ATTRIBUTES psec=0; 133c0b746e5SOllivier Robert HANDLE shmid=0; 134c0b746e5SOllivier Robert SECURITY_DESCRIPTOR sd; 135c0b746e5SOllivier Robert SECURITY_ATTRIBUTES sa; 136c0b746e5SOllivier Robert sprintf (buf,"NTP%d",unit); 137c0b746e5SOllivier Robert if (unit>=2) { /* world access */ 138c0b746e5SOllivier Robert if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { 139c0b746e5SOllivier Robert msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit); 140c0b746e5SOllivier Robert return 0; 141c0b746e5SOllivier Robert } 142c0b746e5SOllivier Robert if (!SetSecurityDescriptorDacl(&sd,1,0,0)) { 143c0b746e5SOllivier Robert msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit); 144c0b746e5SOllivier Robert return 0; 145c0b746e5SOllivier Robert } 146c0b746e5SOllivier Robert sa.nLength=sizeof (SECURITY_ATTRIBUTES); 147c0b746e5SOllivier Robert sa.lpSecurityDescriptor=&sd; 148c0b746e5SOllivier Robert sa.bInheritHandle=0; 149c0b746e5SOllivier Robert psec=&sa; 150c0b746e5SOllivier Robert } 151c0b746e5SOllivier Robert shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, 152c0b746e5SOllivier Robert 0, sizeof (struct shmTime),buf); 153c0b746e5SOllivier Robert if (!shmid) { /*error*/ 154c0b746e5SOllivier Robert char buf[1000]; 155c0b746e5SOllivier Robert FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 156c0b746e5SOllivier Robert 0, GetLastError (), 0, buf, sizeof (buf), 0); 157c0b746e5SOllivier Robert msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf); 158c0b746e5SOllivier Robert return 0; 159c0b746e5SOllivier Robert } 160c0b746e5SOllivier Robert else { 161c0b746e5SOllivier Robert struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, 162c0b746e5SOllivier Robert FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); 163c0b746e5SOllivier Robert if (p==0) { /*error*/ 164c0b746e5SOllivier Robert char buf[1000]; 165c0b746e5SOllivier Robert FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 166c0b746e5SOllivier Robert 0, GetLastError (), 0, buf, sizeof (buf), 0); 167c0b746e5SOllivier Robert msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf); 168c0b746e5SOllivier Robert return 0; 169c0b746e5SOllivier Robert } 170c0b746e5SOllivier Robert return p; 171c0b746e5SOllivier Robert } 172c0b746e5SOllivier Robert #endif 173c0b746e5SOllivier Robert return 0; 174c0b746e5SOllivier Robert } 175c0b746e5SOllivier Robert /* 176c0b746e5SOllivier Robert * shm_start - attach to shared memory 177c0b746e5SOllivier Robert */ 178c0b746e5SOllivier Robert static int 179c0b746e5SOllivier Robert shm_start( 180c0b746e5SOllivier Robert int unit, 181c0b746e5SOllivier Robert struct peer *peer 182c0b746e5SOllivier Robert ) 183c0b746e5SOllivier Robert { 184c0b746e5SOllivier Robert struct refclockproc *pp; 185c0b746e5SOllivier Robert pp = peer->procptr; 186c0b746e5SOllivier Robert pp->io.clock_recv = noentry; 187c0b746e5SOllivier Robert pp->io.srcclock = (caddr_t)peer; 188c0b746e5SOllivier Robert pp->io.datalen = 0; 189c0b746e5SOllivier Robert pp->io.fd = -1; 190c0b746e5SOllivier Robert pp->unitptr = (caddr_t)getShmTime(unit); 191c0b746e5SOllivier Robert 192c0b746e5SOllivier Robert /* 193c0b746e5SOllivier Robert * Initialize miscellaneous peer variables 194c0b746e5SOllivier Robert */ 195c0b746e5SOllivier Robert memcpy((char *)&pp->refid, REFID, 4); 196c0b746e5SOllivier Robert if (pp->unitptr!=0) { 197c0b746e5SOllivier Robert ((struct shmTime*)pp->unitptr)->precision=PRECISION; 198c0b746e5SOllivier Robert peer->precision = ((struct shmTime*)pp->unitptr)->precision; 199c0b746e5SOllivier Robert ((struct shmTime*)pp->unitptr)->valid=0; 200c0b746e5SOllivier Robert ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES; 201c0b746e5SOllivier Robert pp->clockdesc = DESCRIPTION; 202c0b746e5SOllivier Robert return (1); 203c0b746e5SOllivier Robert } 204c0b746e5SOllivier Robert else { 205c0b746e5SOllivier Robert return 0; 206c0b746e5SOllivier Robert } 207c0b746e5SOllivier Robert } 208c0b746e5SOllivier Robert 209c0b746e5SOllivier Robert 210c0b746e5SOllivier Robert /* 211c0b746e5SOllivier Robert * shm_shutdown - shut down the clock 212c0b746e5SOllivier Robert */ 213c0b746e5SOllivier Robert static void 214c0b746e5SOllivier Robert shm_shutdown( 215c0b746e5SOllivier Robert int unit, 216c0b746e5SOllivier Robert struct peer *peer 217c0b746e5SOllivier Robert ) 218c0b746e5SOllivier Robert { 219c0b746e5SOllivier Robert register struct shmTime *up; 220c0b746e5SOllivier Robert struct refclockproc *pp; 221c0b746e5SOllivier Robert 222c0b746e5SOllivier Robert pp = peer->procptr; 223c0b746e5SOllivier Robert up = (struct shmTime *)pp->unitptr; 224c0b746e5SOllivier Robert #ifndef SYS_WINNT 225c0b746e5SOllivier Robert shmdt (up); 226c0b746e5SOllivier Robert #else 227c0b746e5SOllivier Robert UnmapViewOfFile (up); 228c0b746e5SOllivier Robert #endif 229c0b746e5SOllivier Robert } 230c0b746e5SOllivier Robert 231c0b746e5SOllivier Robert 232c0b746e5SOllivier Robert /* 233c0b746e5SOllivier Robert * shm_poll - called by the transmit procedure 234c0b746e5SOllivier Robert */ 235c0b746e5SOllivier Robert static void 236c0b746e5SOllivier Robert shm_poll( 237c0b746e5SOllivier Robert int unit, 238c0b746e5SOllivier Robert struct peer *peer 239c0b746e5SOllivier Robert ) 240c0b746e5SOllivier Robert { 241c0b746e5SOllivier Robert register struct shmTime *up; 242c0b746e5SOllivier Robert struct refclockproc *pp; 243c0b746e5SOllivier Robert 244c0b746e5SOllivier Robert /* 245c0b746e5SOllivier Robert * This is the main routine. It snatches the time from the shm 246c0b746e5SOllivier Robert * board and tacks on a local timestamp. 247c0b746e5SOllivier Robert */ 248c0b746e5SOllivier Robert pp = peer->procptr; 249c0b746e5SOllivier Robert up = (struct shmTime*)pp->unitptr; 250c0b746e5SOllivier Robert if (up==0) { /* try to map again - this may succeed if meanwhile some- 251c0b746e5SOllivier Robert body has ipcrm'ed the old (unaccessible) shared mem 252c0b746e5SOllivier Robert segment */ 253c0b746e5SOllivier Robert pp->unitptr = (caddr_t)getShmTime(unit); 254c0b746e5SOllivier Robert up = (struct shmTime*)pp->unitptr; 255c0b746e5SOllivier Robert } 256c0b746e5SOllivier Robert if (up==0) { 257c0b746e5SOllivier Robert refclock_report(peer, CEVNT_FAULT); 258c0b746e5SOllivier Robert return; 259c0b746e5SOllivier Robert } 260c0b746e5SOllivier Robert if (up->valid) { 261c0b746e5SOllivier Robert struct timeval tvr; 262c0b746e5SOllivier Robert struct timeval tvt; 263c0b746e5SOllivier Robert struct tm *t; 264c0b746e5SOllivier Robert int ok=1; 265c0b746e5SOllivier Robert switch (up->mode) { 266c0b746e5SOllivier Robert case 0: { 267c0b746e5SOllivier Robert tvr.tv_sec=up->receiveTimeStampSec-172800; 268c0b746e5SOllivier Robert tvr.tv_usec=up->receiveTimeStampUSec; 269c0b746e5SOllivier Robert tvt.tv_sec=up->clockTimeStampSec; 270c0b746e5SOllivier Robert tvt.tv_usec=up->clockTimeStampUSec; 271c0b746e5SOllivier Robert } 272c0b746e5SOllivier Robert break; 273c0b746e5SOllivier Robert case 1: { 274c0b746e5SOllivier Robert int cnt=up->count; 275c0b746e5SOllivier Robert tvr.tv_sec=up->receiveTimeStampSec-172800; 276c0b746e5SOllivier Robert tvr.tv_usec=up->receiveTimeStampUSec; 277c0b746e5SOllivier Robert tvt.tv_sec=up->clockTimeStampSec; 278c0b746e5SOllivier Robert tvt.tv_usec=up->clockTimeStampUSec; 279c0b746e5SOllivier Robert ok=(cnt==up->count); 280c0b746e5SOllivier Robert } 281c0b746e5SOllivier Robert break; 282c0b746e5SOllivier Robert default: 283c0b746e5SOllivier Robert msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode); 284c0b746e5SOllivier Robert } 285c0b746e5SOllivier Robert /*msyslog(LOG_NOTICE,"poll2a tvr.s %d tvr.u %d tvt.s %d tvt.u %d",tvr.tv_sec,tvr.tv_usec,tvt.tv_sec,tvt.tv_usec);*/ 286c0b746e5SOllivier Robert up->valid=0; 287c0b746e5SOllivier Robert if (ok) { 288c0b746e5SOllivier Robert TVTOTS(&tvr,&pp->lastrec); 289c0b746e5SOllivier Robert /* pp->lasttime = current_time; */ 290c0b746e5SOllivier Robert pp->polls++; 291c0b746e5SOllivier Robert t=gmtime (&tvt.tv_sec); 292c0b746e5SOllivier Robert pp->day=t->tm_yday;/*+2; */ 293c0b746e5SOllivier Robert pp->hour=t->tm_hour; 294c0b746e5SOllivier Robert pp->minute=t->tm_min; 295c0b746e5SOllivier Robert pp->second=t->tm_sec; 296c0b746e5SOllivier Robert pp->usec=tvt.tv_usec; 297c0b746e5SOllivier Robert peer->precision=up->precision; 298c0b746e5SOllivier Robert pp->leap=up->leap; 299c0b746e5SOllivier Robert } 300c0b746e5SOllivier Robert else { 301c0b746e5SOllivier Robert refclock_report(peer, CEVNT_FAULT); 302c0b746e5SOllivier Robert msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); 303c0b746e5SOllivier Robert return; 304c0b746e5SOllivier Robert } 305c0b746e5SOllivier Robert } 306c0b746e5SOllivier Robert else { 307c0b746e5SOllivier Robert refclock_report(peer, CEVNT_TIMEOUT); 308c0b746e5SOllivier Robert msyslog (LOG_NOTICE, "SHM: no new value found in shared memory"); 309c0b746e5SOllivier Robert return; 310c0b746e5SOllivier Robert } 311c0b746e5SOllivier Robert if (!refclock_process(pp)) { 312c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADTIME); 313c0b746e5SOllivier Robert return; 314c0b746e5SOllivier Robert } 315c0b746e5SOllivier Robert refclock_receive(peer); 316c0b746e5SOllivier Robert } 317c0b746e5SOllivier Robert 318c0b746e5SOllivier Robert #else 319c0b746e5SOllivier Robert int refclock_shm_bs; 320c0b746e5SOllivier Robert #endif /* REFCLOCK */ 321