/*- * Copyright (c) 2014 Poul-Henning Kamp * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include "ntimed.h" #include "mem.h" #include "udp.h" #include "ntp.h" #include "net_getaddrinfo.h" struct ntp_peer * NTP_Peer_New(const char *hostname, const void *sa, unsigned salen) { struct ntp_peer *np; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; AZ(getnameinfo(sa, salen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)); ALLOC_OBJ(np, NTP_PEER_MAGIC); AN(np); np->sa_len = salen; np->sa = allocmem(np->sa_len); AN(np->sa); memcpy(np->sa, sa, np->sa_len); np->hostname = strdup(hostname); AN(np->hostname); np->ip = strdup(hbuf); AN(np->ip); ALLOC_OBJ(np->tx_pkt, NTP_PACKET_MAGIC); AN(np->tx_pkt); ALLOC_OBJ(np->rx_pkt, NTP_PACKET_MAGIC); AN(np->rx_pkt); NTP_Tool_Client_Req(np->tx_pkt); return (np); } struct ntp_peer * NTP_Peer_NewLookup(struct ocx *ocx, const char *hostname) { struct addrinfo hints, *res0; int error; struct ntp_peer *np; memset(&hints, 0, sizeof hints); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; error = getaddrinfo(hostname, "123", &hints, &res0); if (error) Fail(ocx, 0, "hostname '%s', port '123': %s\n", hostname, gai_strerror(error)); np = NTP_Peer_New(hostname, res0->ai_addr, res0->ai_addrlen); freeaddrinfo(res0); return (np); } void NTP_Peer_Destroy(struct ntp_peer *np) { CHECK_OBJ_NOTNULL(np, NTP_PEER_MAGIC); freemem(np->sa); freemem(np->hostname); freemem(np->ip); freemem(np->tx_pkt); freemem(np->rx_pkt); FREE_OBJ(np); } int NTP_Peer_Poll(struct ocx *ocx, const struct udp_socket *usc, const struct ntp_peer *np, double tmo) { char buf[100]; size_t len; struct sockaddr_storage rss; socklen_t rssl; ssize_t l; int i; struct timestamp t0, t1, t2; double d; AN(usc); CHECK_OBJ_NOTNULL(np, NTP_PEER_MAGIC); assert(tmo > 0.0 && tmo <= 1.0); len = NTP_Packet_Pack(buf, sizeof buf, np->tx_pkt); l = Udp_Send(ocx, usc, np->sa, np->sa_len, buf, len); if (l != (ssize_t)len) { Debug(ocx, "Tx peer %s %s got %zd (%s)\n", np->hostname, np->ip, l, strerror(errno)); return (0); } (void)TB_Now(&t0); while (1) { (void)TB_Now(&t1); d = TS_Diff(&t1, &t0); i = UdpTimedRx(ocx, usc, np->sa->sa_family, &rss, &rssl, &t2, buf, sizeof buf, tmo - d); if (i == 0) return (0); if (i < 0) Fail(ocx, 1, "Rx failed\n"); if (i != 48) { Debug(ocx, "Rx peer %s %s got len=%d\n", np->hostname, np->ip, i); continue; } /* Ignore packets from other hosts */ if (!SA_Equal(np->sa, np->sa_len, &rss, rssl)) continue; AN(NTP_Packet_Unpack(np->rx_pkt, buf, i)); np->rx_pkt->ts_rx = t2; /* Ignore packets which are not replies to our packet */ if (TS_Diff(&np->tx_pkt->ntp_transmit, &np->rx_pkt->ntp_origin) != 0.0) { continue; } return (1); } }