Home | History | Annotate | Line # | Download | only in ntpd
refclock_shm.c revision 1.1
      1 /*	$NetBSD: refclock_shm.c,v 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