freebsd-dev/contrib/ntp/ntpd/refclock_shm.c
2004-07-20 15:01:56 +00:00

306 lines
7.1 KiB
C

/*
* refclock_shm - clock driver for utc via shared memory
* - under construction -
* To add new modes: Extend or union the shmTime-struct. Do not
* extend/shrink size, because otherwise existing implementations
* will specify wrong size of shared memory-segment
* PB 18.3.97
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined(REFCLOCK) && defined(CLOCK_SHM)
#include "ntpd.h"
#undef fileno
#include "ntp_io.h"
#undef fileno
#include "ntp_refclock.h"
#undef fileno
#include "ntp_unixtime.h"
#undef fileno
#include "ntp_stdlib.h"
#undef fileno
#include <ctype.h>
#undef fileno
#ifndef SYS_WINNT
# include <sys/ipc.h>
# include <sys/shm.h>
# include <assert.h>
# include <unistd.h>
# include <stdio.h>
#endif
/*
* This driver supports a reference clock attached thru shared memory
*/
/*
* SHM interface definitions
*/
#define PRECISION (-1) /* precision assumed (0.5 s) */
#define REFID "SHM" /* reference ID */
#define DESCRIPTION "SHM/Shared memory interface"
#define NSAMPLES 3 /* stages of median filter */
/*
* Function prototypes
*/
static int shm_start (int, struct peer *);
static void shm_shutdown (int, struct peer *);
static void shm_poll (int unit, struct peer *);
/*
* Transfer vector
*/
struct refclock refclock_shm = {
shm_start, /* start up driver */
shm_shutdown, /* shut down driver */
shm_poll, /* transmit poll message */
noentry, /* not used */
noentry, /* initialize driver (not used) */
noentry, /* not used */
NOFLAGS /* not used */
};
struct shmTime {
int mode; /* 0 - if valid set
* use values,
* clear valid
* 1 - if valid set
* if count before and after read of values is equal,
* use values
* clear valid
*/
int count;
time_t clockTimeStampSec;
int clockTimeStampUSec;
time_t receiveTimeStampSec;
int receiveTimeStampUSec;
int leap;
int precision;
int nsamples;
int valid;
int dummy[10];
};
struct shmTime *getShmTime(int);
struct shmTime *getShmTime (int unit) {
#ifndef SYS_WINNT
int shmid=0;
assert (unit<10); /* MAXUNIT is 4, so should never happen */
shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
IPC_CREAT|(unit<2?0700:0777));
if (shmid==-1) { /*error */
msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
return 0;
}
else { /* no error */
struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
if ((int)(long)p==-1) { /* error */
msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno));
return 0;
}
return p;
}
#else
char buf[10];
LPSECURITY_ATTRIBUTES psec=0;
HANDLE shmid=0;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
sprintf (buf,"NTP%d",unit);
if (unit>=2) { /* world access */
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit);
return 0;
}
if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
return 0;
}
sa.nLength=sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=&sd;
sa.bInheritHandle=0;
psec=&sa;
}
shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
0, sizeof (struct shmTime),buf);
if (!shmid) { /*error*/
char buf[1000];
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
0, GetLastError (), 0, buf, sizeof (buf), 0);
msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf);
return 0;
}
else {
struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
if (p==0) { /*error*/
char buf[1000];
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
0, GetLastError (), 0, buf, sizeof (buf), 0);
msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf);
return 0;
}
return p;
}
#endif
}
/*
* shm_start - attach to shared memory
*/
static int
shm_start(
int unit,
struct peer *peer
)
{
struct refclockproc *pp;
pp = peer->procptr;
pp->io.clock_recv = noentry;
pp->io.srcclock = (caddr_t)peer;
pp->io.datalen = 0;
pp->io.fd = -1;
pp->unitptr = (caddr_t)getShmTime(unit);
/*
* Initialize miscellaneous peer variables
*/
memcpy((char *)&pp->refid, REFID, 4);
if (pp->unitptr!=0) {
((struct shmTime*)pp->unitptr)->precision=PRECISION;
peer->precision = ((struct shmTime*)pp->unitptr)->precision;
((struct shmTime*)pp->unitptr)->valid=0;
((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES;
pp->clockdesc = DESCRIPTION;
return (1);
}
else {
return 0;
}
}
/*
* shm_shutdown - shut down the clock
*/
static void
shm_shutdown(
int unit,
struct peer *peer
)
{
register struct shmTime *up;
struct refclockproc *pp;
pp = peer->procptr;
up = (struct shmTime *)pp->unitptr;
#ifndef SYS_WINNT
/* HMS: shmdt()wants char* or const void * */
(void) shmdt (up);
#else
UnmapViewOfFile (up);
#endif
}
/*
* shm_poll - called by the transmit procedure
*/
static void
shm_poll(
int unit,
struct peer *peer
)
{
register struct shmTime *up;
struct refclockproc *pp;
/*
* This is the main routine. It snatches the time from the shm
* board and tacks on a local timestamp.
*/
pp = peer->procptr;
up = (struct shmTime*)pp->unitptr;
if (up==0) { /* try to map again - this may succeed if meanwhile some-
body has ipcrm'ed the old (unaccessible) shared mem
segment */
pp->unitptr = (caddr_t)getShmTime(unit);
up = (struct shmTime*)pp->unitptr;
}
if (up==0) {
refclock_report(peer, CEVNT_FAULT);
return;
}
if (up->valid) {
struct timeval tvr;
struct timeval tvt;
struct tm *t;
int ok=1;
switch (up->mode) {
case 0: {
tvr.tv_sec=up->receiveTimeStampSec;
tvr.tv_usec=up->receiveTimeStampUSec;
tvt.tv_sec=up->clockTimeStampSec;
tvt.tv_usec=up->clockTimeStampUSec;
}
break;
case 1: {
int cnt=up->count;
tvr.tv_sec=up->receiveTimeStampSec;
tvr.tv_usec=up->receiveTimeStampUSec;
tvt.tv_sec=up->clockTimeStampSec;
tvt.tv_usec=up->clockTimeStampUSec;
ok=(cnt==up->count);
}
break;
default:
msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode);
}
up->valid=0;
if (ok) {
TVTOTS(&tvr,&pp->lastrec);
pp->lastrec.l_ui += JAN_1970;
/* pp->lasttime = current_time; */
pp->polls++;
t=gmtime (&tvt.tv_sec);
pp->day=t->tm_yday+1;
pp->hour=t->tm_hour;
pp->minute=t->tm_min;
pp->second=t->tm_sec;
pp->nsec=tvt.tv_usec * 1000;
peer->precision=up->precision;
pp->leap=up->leap;
}
else {
refclock_report(peer, CEVNT_FAULT);
msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
return;
}
}
else {
refclock_report(peer, CEVNT_TIMEOUT);
/*
msyslog (LOG_NOTICE, "SHM: no new value found in shared memory");
*/
return;
}
if (!refclock_process(pp)) {
refclock_report(peer, CEVNT_BADTIME);
return;
}
pp->lastref = pp->lastrec;
refclock_receive(peer);
}
#else
int refclock_shm_bs;
#endif /* REFCLOCK */