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 struct shmTime *getShmTime (int unit) { 91 #ifndef SYS_WINNT 92 int shmid=0; 93 94 assert (unit<10); /* MAXUNIT is 4, so should never happen */ 95 shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), 96 IPC_CREAT|(unit<2?0700:0777)); 97 if (shmid==-1) { /*error */ 98 msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno)); 99 return 0; 100 } 101 else { /* no error */ 102 struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); 103 if ((int)(long)p==-1) { /* error */ 104 msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno)); 105 return 0; 106 } 107 return p; 108 } 109 #else 110 char buf[10]; 111 LPSECURITY_ATTRIBUTES psec=0; 112 HANDLE shmid=0; 113 SECURITY_DESCRIPTOR sd; 114 SECURITY_ATTRIBUTES sa; 115 sprintf (buf,"NTP%d",unit); 116 if (unit>=2) { /* world access */ 117 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { 118 msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit); 119 return 0; 120 } 121 if (!SetSecurityDescriptorDacl(&sd,1,0,0)) { 122 msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit); 123 return 0; 124 } 125 sa.nLength=sizeof (SECURITY_ATTRIBUTES); 126 sa.lpSecurityDescriptor=&sd; 127 sa.bInheritHandle=0; 128 psec=&sa; 129 } 130 shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, 131 0, sizeof (struct shmTime),buf); 132 if (!shmid) { /*error*/ 133 char buf[1000]; 134 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 135 0, GetLastError (), 0, buf, sizeof (buf), 0); 136 msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf); 137 return 0; 138 } 139 else { 140 struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, 141 FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); 142 if (p==0) { /*error*/ 143 char buf[1000]; 144 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 145 0, GetLastError (), 0, buf, sizeof (buf), 0); 146 msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf); 147 return 0; 148 } 149 return p; 150 } 151 #endif 152 return 0; 153 } 154 /* 155 * shm_start - attach to shared memory 156 */ 157 static int 158 shm_start( 159 int unit, 160 struct peer *peer 161 ) 162 { 163 struct refclockproc *pp; 164 pp = peer->procptr; 165 pp->io.clock_recv = noentry; 166 pp->io.srcclock = (caddr_t)peer; 167 pp->io.datalen = 0; 168 pp->io.fd = -1; 169 pp->unitptr = (caddr_t)getShmTime(unit); 170 171 /* 172 * Initialize miscellaneous peer variables 173 */ 174 memcpy((char *)&pp->refid, REFID, 4); 175 if (pp->unitptr!=0) { 176 ((struct shmTime*)pp->unitptr)->precision=PRECISION; 177 peer->precision = ((struct shmTime*)pp->unitptr)->precision; 178 ((struct shmTime*)pp->unitptr)->valid=0; 179 ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES; 180 pp->clockdesc = DESCRIPTION; 181 return (1); 182 } 183 else { 184 return 0; 185 } 186 } 187 188 189 /* 190 * shm_shutdown - shut down the clock 191 */ 192 static void 193 shm_shutdown( 194 int unit, 195 struct peer *peer 196 ) 197 { 198 register struct shmTime *up; 199 struct refclockproc *pp; 200 201 pp = peer->procptr; 202 up = (struct shmTime *)pp->unitptr; 203 #ifndef SYS_WINNT 204 shmdt (up); 205 #else 206 UnmapViewOfFile (up); 207 #endif 208 } 209 210 211 /* 212 * shm_poll - called by the transmit procedure 213 */ 214 static void 215 shm_poll( 216 int unit, 217 struct peer *peer 218 ) 219 { 220 register struct shmTime *up; 221 struct refclockproc *pp; 222 223 /* 224 * This is the main routine. It snatches the time from the shm 225 * board and tacks on a local timestamp. 226 */ 227 pp = peer->procptr; 228 up = (struct shmTime*)pp->unitptr; 229 if (up==0) { /* try to map again - this may succeed if meanwhile some- 230 body has ipcrm'ed the old (unaccessible) shared mem 231 segment */ 232 pp->unitptr = (caddr_t)getShmTime(unit); 233 up = (struct shmTime*)pp->unitptr; 234 } 235 if (up==0) { 236 refclock_report(peer, CEVNT_FAULT); 237 return; 238 } 239 if (up->valid) { 240 struct timeval tvr; 241 struct timeval tvt; 242 struct tm *t; 243 int ok=1; 244 switch (up->mode) { 245 case 0: { 246 tvr.tv_sec=up->receiveTimeStampSec; 247 tvr.tv_usec=up->receiveTimeStampUSec; 248 tvt.tv_sec=up->clockTimeStampSec; 249 tvt.tv_usec=up->clockTimeStampUSec; 250 } 251 break; 252 case 1: { 253 int cnt=up->count; 254 tvr.tv_sec=up->receiveTimeStampSec; 255 tvr.tv_usec=up->receiveTimeStampUSec; 256 tvt.tv_sec=up->clockTimeStampSec; 257 tvt.tv_usec=up->clockTimeStampUSec; 258 ok=(cnt==up->count); 259 } 260 break; 261 default: 262 msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode); 263 } 264 up->valid=0; 265 if (ok) { 266 TVTOTS(&tvr,&pp->lastrec); 267 pp->lastrec.l_ui += JAN_1970; 268 /* pp->lasttime = current_time; */ 269 pp->polls++; 270 t=gmtime (&tvt.tv_sec); 271 pp->day=t->tm_yday+1; 272 pp->hour=t->tm_hour; 273 pp->minute=t->tm_min; 274 pp->second=t->tm_sec; 275 pp->msec=0; 276 pp->usec=tvt.tv_usec; 277 peer->precision=up->precision; 278 pp->leap=up->leap; 279 } 280 else { 281 refclock_report(peer, CEVNT_FAULT); 282 msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); 283 return; 284 } 285 } 286 else { 287 refclock_report(peer, CEVNT_TIMEOUT); 288 msyslog (LOG_NOTICE, "SHM: no new value found in shared memory"); 289 return; 290 } 291 if (!refclock_process(pp)) { 292 refclock_report(peer, CEVNT_BADTIME); 293 return; 294 } 295 refclock_receive(peer); 296 } 297 298 #else 299 int refclock_shm_bs; 300 #endif /* REFCLOCK */ 301