#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
#define OLDWAY 0
#define PRECISION (-1)
#define REFID "SHM"
#define DESCRIPTION "SHM/Shared memory interface"
#define NSAMPLES 3
static int shm_start (int unit, struct peer *peer);
static void shm_shutdown (int unit, struct peer *peer);
static void shm_poll (int unit, struct peer *peer);
static void shm_timer (int unit, struct peer *peer);
int shm_peek (int unit, struct peer *peer);
void shm_clockstats (int unit, struct peer *peer);
struct refclock refclock_shm = {
shm_start,
shm_shutdown,
shm_poll,
noentry,
noentry,
noentry,
shm_timer,
};
struct shmTime {
int mode;
int count;
time_t clockTimeStampSec;
int clockTimeStampUSec;
time_t receiveTimeStampSec;
int receiveTimeStampUSec;
int leap;
int precision;
int nsamples;
int valid;
int dummy[10];
};
struct shmunit {
struct shmTime *shm;
int ticks;
int good;
int notready;
int bad;
int clash;
};
struct shmTime *getShmTime(int);
struct shmTime *getShmTime (int unit) {
#ifndef SYS_WINNT
int shmid=0;
shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
IPC_CREAT|(unit<2?0600:0666));
if (shmid==-1) {
msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
return 0;
}
else {
struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
if ((int)(long)p==-1) {
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) {
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) {
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) {
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
}
static int
shm_start(
int unit,
struct peer *peer
)
{
struct refclockproc *pp;
struct shmunit *up;
pp = peer->procptr;
pp->io.clock_recv = noentry;
pp->io.srcclock = (caddr_t)peer;
pp->io.datalen = 0;
pp->io.fd = -1;
up = (struct shmunit *) emalloc(sizeof(*up));
if (up == NULL)
return (FALSE);
memset((char *)up, 0, sizeof(*up));
pp->unitptr = (caddr_t)up;
up->shm = getShmTime(unit);
memcpy((char *)&pp->refid, REFID, 4);
if (up->shm != 0) {
up->shm->precision = PRECISION;
peer->precision = up->shm->precision;
up->shm->valid=0;
up->shm->nsamples=NSAMPLES;
pp->clockdesc = DESCRIPTION;
return (1);
}
else {
return 0;
}
}
static void
shm_shutdown(
int unit,
struct peer *peer
)
{
struct refclockproc *pp;
struct shmunit *up;
pp = peer->procptr;
up = (struct shmunit *)pp->unitptr;
#ifndef SYS_WINNT
(void) shmdt ((char *)up->shm);
#else
UnmapViewOfFile (up->shm);
#endif
}
static void
shm_timer(int unit, struct peer *peer)
{
if (OLDWAY)
return;
shm_peek(unit, peer);
}
static void
shm_poll(
int unit,
struct peer *peer
)
{
struct refclockproc *pp;
int ok;
pp = peer->procptr;
if (OLDWAY) {
ok = shm_peek(unit, peer);
if (!ok) return;
}
if (pp->coderecv == pp->codeproc) {
refclock_report(peer, CEVNT_TIMEOUT);
shm_clockstats(unit, peer);
return;
}
pp->lastref = pp->lastrec;
refclock_receive(peer);
shm_clockstats(unit, peer);
}
int shm_peek(
int unit,
struct peer *peer
)
{
struct refclockproc *pp;
struct shmunit *up;
struct shmTime *shm;
pp = peer->procptr;
up = (struct shmunit*)pp->unitptr;
up->ticks++;
if (up->shm == 0) {
up->shm = getShmTime(unit);
}
shm = up->shm;
if (shm == 0) {
refclock_report(peer, CEVNT_FAULT);
return(0);
}
if (shm->valid) {
struct timeval tvr;
struct timeval tvt;
struct tm *t;
int ok=1;
tvr.tv_sec = 0;
tvr.tv_usec = 0;
tvt.tv_sec = 0;
tvt.tv_usec = 0;
switch (shm->mode) {
case 0: {
tvr.tv_sec=shm->receiveTimeStampSec;
tvr.tv_usec=shm->receiveTimeStampUSec;
tvt.tv_sec=shm->clockTimeStampSec;
tvt.tv_usec=shm->clockTimeStampUSec;
}
break;
case 1: {
int cnt=shm->count;
tvr.tv_sec=shm->receiveTimeStampSec;
tvr.tv_usec=shm->receiveTimeStampUSec;
tvt.tv_sec=shm->clockTimeStampSec;
tvt.tv_usec=shm->clockTimeStampUSec;
ok=(cnt==shm->count);
}
break;
default:
msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode);
}
shm->valid=0;
if (ok) {
time_t help;
TVTOTS(&tvr,&pp->lastrec);
pp->lastrec.l_ui += JAN_1970;
pp->polls++;
help = tvt.tv_sec;
t = gmtime (&help);
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=shm->precision;
pp->leap=shm->leap;
}
else {
refclock_report(peer, CEVNT_FAULT);
msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
up->clash++;
return(0);
}
}
else {
refclock_report(peer, CEVNT_TIMEOUT);
up->notready++;
return(0);
}
if (!refclock_process(pp)) {
refclock_report(peer, CEVNT_BADTIME);
up->bad++;
return(0);
}
up->good++;
return(1);
}
void shm_clockstats(
int unit,
struct peer *peer
)
{
struct refclockproc *pp;
struct shmunit *up;
char logbuf[256];
pp = peer->procptr;
up = (struct shmunit*)pp->unitptr;
if (!(pp->sloppyclockflag & CLK_FLAG4)) return;
snprintf(logbuf, sizeof(logbuf), "%3d %3d %3d %3d %3d",
up->ticks, up->good, up->notready, up->bad, up->clash);
record_clock_stats(&peer->srcadr, logbuf);
up->ticks = up->good = up->notready =up->bad = up->clash = 0;
}
#else
int refclock_shm_bs;
#endif