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 */ 313