BSD 4_3_Net_2 development
[unix-history] / usr / src / contrib / isode / others / ntp / ntp_sock.c
#ifndef lint
static char *RCSid = "$Header: /f/osi/others/ntp/RCS/ntp_sock.c,v 7.1 91/02/22 09:33:53 mrose Interim $";
#endif
/*
* Ntp UDP specific code (mainly) based on the 3.4 ntp but heavily modified.
* $Log: ntp_sock.c,v $
* Revision 7.1 91/02/22 09:33:53 mrose
* Interim 6.8
*
* Revision 7.0 90/12/10 17:21:33 mrose
* *** empty log message ***
*
* Revision 1.2 90/08/14 10:13:58 jpo
* new protocol version
*
* Revision 1.1 89/06/15 20:36:59 jpo
* Initial revision
*
*
*/
#include "ntp.h"
struct intf *addrs;
int nintf = 0;
#ifdef TEST
extern int errno;
main() {
int i, cc, val;
char foo[10];
advise(LLOG_DEBUG, NULLCP, "ifconfig test");
create_sockets(htons(43242));
for (i = 0; i < nintf; i++) {
printf("%d: %s fd %d addr %s mask %x ",
i, addrs[i].name, addrs[i].fd,
paddr (addrs[i].addr),
ntohl(addrs[i].mask.sin_addr.s_addr));
cc = sizeof(val);
if (getsockopt(addrs[0].fd, SOL_SOCKET, SO_BROADCAST,
(char*)&val, &cc)) {
perror("getsockopt");
exit(1);
}
printf("BCAST opt %d", val);
cc = sizeof(val);
if (getsockopt(addrs[0].fd, SOL_SOCKET, SO_RCVBUF,
(char*)&val, &cc)) {
perror("getsockopt");
exit(1);
}
printf("sockbuf size = %d ", val);
putchar('\n');
}
for (i=0; i < nintf; i++) {
fprintf(stderr, "Read fd %d.. ", addrs[i].fd);
cc = read(addrs[i].fd, foo, 10);
fprintf(stderr, " returns %d ", cc);
perror("read errno");
}
}
#endif
#ifndef SIOCGIFCONF
/*
* If we can't determine the interface configuration, just listen with one
* socket at the INADDR_ANY address.
*/
create_sockets(port)
unsigned int port;
{
struct intf *ap;
int no;
ap = getintf (&no);
ap->addr.ad_inet.sin.sin_family = AF_INET;
ap->addr.ad_inet.sin.sin_port = 0;
ap->addr.ad_inet.sin_addr.s_addr = INADDR_ANY;
ap->addr.ad_inet.sin_mask.s_addr = htonl(~0);
ap->name = "wildcard";
ap->addr.type = AF_INET;
ap->flags = (INTF_VALID|INTF_STATIC);
if ((ap->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
adios ("failed", "socket()");
if (fcntl(ap->fd, F_SETFL, FNDELAY) < 0)
adios ("failed", "fcntl(FNDELAY)");
ap->addr.ad_inet.sin_family = AF_INET;
ap->addr.ad_inet.sin_port = port;
ap->if_flags = 0;
ap->flags = (INTF_VALID|INTF_STATIC);
if (bind(ap->fd, (struct sockaddr *)&addrs[0].addr.ad_inet,
sizeof(ap->addr.ad_inet)) < 0)
adios("failed", "bind");
return nintf;
}
#else
/*
* Grab interface configuration, and create a socket for each interface
* address.
*/
create_sockets(port)
unsigned int port;
{
char buf[1024];
struct intf *ap;
struct ifconf ifc;
struct ifreq ifreq, *ifr;
int on = 1, off = 0;
int n, i, vs;
extern char *malloc();
/*
* create pseudo-interface with wildcard address
*/
ap = getintf (&n);
ap->addr.type =
ap -> addr.inet_ad.sin_family = AF_INET;
ap -> addr.inet_ad.sin_port = 0;
ap -> addr.inet_ad.sin_addr.s_addr = INADDR_ANY;
ap -> name = "wild";
ap -> flags = (INTF_VALID|INTF_STATIC);
ap -> mask.sin_addr.s_addr = htonl(~0);
if ((vs = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
adios("failed", "socket(AF_INET, SOCK_DGRAM)");
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0)
adios ("failed", "get interface configuration");
n = ifc.ifc_len/sizeof(struct ifreq);
for (ifr = ifc.ifc_req; n > 0; n--, ifr++) {
int num;
ap = getintf (&num);
if (ifr->ifr_addr.sa_family != AF_INET)
continue;
ifreq = *ifr;
if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
advise(LLOG_EXCEPTIONS, "failed",
"get interface flags");
continue;
}
if ((ifreq.ifr_flags & IFF_UP) == 0)
continue;
ap -> if_flags = ifreq.ifr_flags;
if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
advise (LLOG_EXCEPTIONS, "failed",
"get interface addr");
continue;
}
ap -> name = strdup (ifreq.ifr_name);
ap -> addr.inet_ad = *(struct sockaddr_in *)&ifreq.ifr_addr;
ap -> addr.type = AF_INET;
#ifdef SIOCGIFBRDADDR
if (ap -> if_flags & IFF_BROADCAST) {
if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0)
adios("failed", "SIOCGIFBRDADDR ");
#ifndef SUN_3_3
ap -> bcast =
*(struct sockaddr_in *)&ifreq.ifr_broadaddr;
#else
ap -> bcast =
*(struct sockaddr_in *)&ifreq.ifr_addr;
#endif
}
#endif /* SIOCGIFBRDADDR */
#ifdef SIOCGIFNETMASK
if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0)
adios ("failed", "SIOCGIFNETMASK ");
ap -> mask = *(struct sockaddr_in *)&ifreq.ifr_addr;
#endif /* SIOCGIFNETMASK */
/*
* look for an already existing source interface address. If
* the machine has multiple point to point interfaces, then
* the local address may appear more than once.
*/
for (i=0; i < nintf; i++) {
if (i != num &&
addr_compare (&addrs[i].addr, &ap -> addr)) {
advise (LLOG_EXCEPTIONS, NULLCP,
"dup interface address %s on %s\n",
paddr (&ap -> addr),
ifreq.ifr_name);
goto next;
}
}
ap -> flags = (INTF_VALID|INTF_STATIC);
next:;
}
(void) close(vs);
for (i = 0; i < nintf; i++) {
if ((addrs[i].flags & INTF_VALID) == 0)
continue;
/* create a datagram (UDP) socket */
if ((addrs[i].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
adios ("failed", "socket()");
/* set SO_REUSEADDR since we will be binding the same port
number on each interface */
if (setsockopt(addrs[i].fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)))
advise(LLOG_EXCEPTIONS, "failed",
"setsockopt SO_REUSEADDR");
/*
* set non-blocking I/O on the descriptor
*/
if (fcntl(addrs[i].fd, F_SETFL, FNDELAY) < 0)
adios ("failed", "fcntl(FNDELAY) fails");
/*
* finally, bind the local address address.
*/
addrs[i].addr.inet_ad.sin_family = AF_INET;
addrs[i].addr.inet_ad.sin_port = port;
if (bind(addrs[i].fd,
(struct sockaddr *)&addrs[i].addr.inet_ad,
sizeof(addrs[i].addr.inet_ad)) < 0)
adios ("failed", "bind on %s", paddr(&addrs[i].addr));
/*
* Turn off the SO_REUSEADDR socket option. It apparently
* causes heartburn on systems with multicast IP installed.
* On normal systems it only gets looked at when the address
* is being bound anyway..
*/
if (setsockopt(addrs[i].fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&off, sizeof(off)))
adios ("failed", "setsockopt SO_REUSEADDR off");
#ifdef SO_BROADCAST
/* if this interface can support broadcast, set SO_BROADCAST */
if (addrs[i].if_flags & IFF_BROADCAST) {
if (setsockopt(addrs[i].fd, SOL_SOCKET, SO_BROADCAST,
(char *)&on, sizeof(on)))
adios ("failed", "setsockopt(SO_BROADCAST)");
}
#endif /* SO_BROADCAST */
}
return nintf;
}
#endif
recv_inet (ap, tvp)
struct intf *ap;
struct timeval *tvp;
{
int dstlen;
int cc;
struct Naddr peers;
struct Naddr *peer = &peers;
extern int debug;
struct ntpdata pkts;
struct ntpdata *pkt = &pkts;
peer -> type = AF_INET;
dstlen = sizeof(struct sockaddr_in);
if ((cc = recvfrom(ap -> fd, (char *) pkt,
sizeof(*pkt), 0,
(struct sockaddr *) &peer->inet_ad, &dstlen)) < 0) {
if (errno != EWOULDBLOCK) {
advise (LLOG_EXCEPTIONS, "failed", "recvfrom");
#ifdef DEBUG
if(debug > 2)
perror("recvfrom");
#endif
}
return -1;
}
if (cc < sizeof(*pkt)) {
#ifdef DEBUG
if (debug)
printf("Runt packet from %s\n",
paddr (peer));
#endif
return -1;
}
if (pkt -> stratum == INFO_QUERY ||
pkt -> stratum == INFO_REPLY) {
query_mode (peer, pkt, ap);
return 0;
}
#ifdef DEBUG
if (debug > 3) {
printf ("\nInput ");
dump_pkt(peer, pkt, (struct ntp_peer *)NULL);
}
#endif
switch (PKT2VERS (pkt -> status)) {
case 1:
case 2:
break;
default:
return -1;
}
receive (peer, pkt, tvp, ap - addrs);
return 0;
}
send_inet (ap, pkt, size, peer)
struct intf *ap;
char *pkt;
int size;
struct Naddr *peer;
{
if (ap -> addr.type != AF_INET) {
advise (LLOG_EXCEPTIONS, NULLCP,
"Bad address type in sent_inet");
return -1;
}
if (sendto(ap -> fd, (char *) pkt, size,
0, (struct sockaddr *)&peer->inet_ad,
sizeof(peer->inet_ad)) < 0) {
advise (LLOG_EXCEPTIONS, "failed", "sendto: %s",
paddr (peer));
return -1;
}
return 0;
}
#define PKTBUF_SIZE 536
/* number of clocks per packet */
#define N_NTP_PKTS \
((PKTBUF_SIZE - sizeof(struct ntpinfo))/(sizeof(struct clockinfo)))
query_mode(dst, ntp, ap)
struct Naddr *dst;
struct ntpdata *ntp;
struct intf *ap;
{
extern struct list peer_list;
extern struct sysdata sys;
char packet[PKTBUF_SIZE];
register struct ntpinfo *nip = (struct ntpinfo *) packet;
register struct ntp_peer *peer;
struct clockinfo *cip;
int seq = 0;
int i;
if (ntp->stratum != INFO_QUERY)
return;
nip->version = NTPDC_VERSION;
nip->type = INFO_REPLY;
nip->seq = 0;
nip->npkts = peer_list.members/N_NTP_PKTS;
if (peer_list.members % N_NTP_PKTS)
nip->npkts++;
nip->peers = peer_list.members;
nip->count = 0;
cip = (struct clockinfo *)&nip[1];
for (peer = peer_list.head; peer != NULL; peer = peer->next) {
if (peer->src.type == AF_INET) {
if (peer->sock < 0)
cip->my_address = htonl(0);
else
cip->my_address =
addrs[peer->sock].addr.inet_ad.sin_addr.s_addr;
cip->port = peer->src.inet_ad.sin_port; /* already in network order */
cip->net_address = peer->src.inet_ad.sin_addr.s_addr;
}
else {
struct in_addr sin;
/* fake some values */
sin = inet_makeaddr (126,1);
cip -> net_address = sin.s_addr;
cip -> port = htons(10123);
sin = inet_makeaddr (126, 1);
cip -> my_address = sin.s_addr;
}
cip->flags = htons(peer->flags);
if (sys.peer == peer)
cip->flags |= htons(PEER_FL_SELECTED);
cip->pkt_sent = htonl(peer->pkt_sent);
cip->pkt_rcvd = htonl(peer->pkt_rcvd);
cip->pkt_dropped = htonl(peer->pkt_dropped);
cip->timer = htonl(peer->timer);
cip->leap = peer->leap;
cip->stratum = peer->stratum;
cip->ppoll = peer->ppoll;
cip->precision = (int) peer->precision;
cip->hpoll = peer->hpoll;
cip->reach = htons(peer->reach & NTP_WINDOW_SHIFT_MASK);
cip->estdisp = htonl((long) (peer->estdisp * 1000.0));
cip->estdelay = htonl((long) (peer->estdelay * 1000.0));
cip->estoffset = htonl((long) (peer->estoffset * 1000.0));
switch (peer->refid.rid_type) {
case RID_STRING:
case RID_INET:
cip->refid = peer->refid.rid_inet; /* XXX */
break;
case RID_PSAP:
cip -> refid = 0;
break;
}
cip->reftime.int_part = htonl(peer->reftime.int_part);
cip->reftime.fraction = htonl(peer->reftime.fraction);
cip->info_filter.index = htons(peer->filter.samples);
for (i = 0; i < PEER_SHIFT; i++) {
cip->info_filter.offset[i] =
htonl((long)(peer->filter.offset[i] * 1000.0));
cip->info_filter.delay[i] =
htonl((long)(peer->filter.delay[i] * 1000.0));
}
cip++;
if (nip->count++ >= N_NTP_PKTS - 1) {
nip->seq =seq++;
(void) send_inet (ap, (char *)packet,
sizeof (packet), dst);
nip->type = INFO_REPLY;
nip->count = 0;
cip = (struct clockinfo *)&nip[1];
}
}
if (nip->count) {
nip->seq = seq;
(void) send_inet (ap, (char *)packet,
sizeof (packet), dst);
}
}