ntp: convert to new socket API
Rework the NTP I/O code to use the new socket support. There are differences in debug messages and handling of some errors.
This commit is contained in:
parent
86a3ef9ed1
commit
2de24cfd82
7 changed files with 192 additions and 711 deletions
|
@ -36,8 +36,8 @@ DESTDIR=
|
||||||
HASH_OBJ = @HASH_OBJ@
|
HASH_OBJ = @HASH_OBJ@
|
||||||
|
|
||||||
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
|
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
|
||||||
reference.o regress.o rtc.o samplefilt.o sched.o sources.o sourcestats.o stubs.o \
|
reference.o regress.o rtc.o samplefilt.o sched.o socket.o sources.o sourcestats.o \
|
||||||
smooth.o sys.o sys_null.o tempcomp.o util.o $(HASH_OBJ)
|
stubs.o smooth.o sys.o sys_null.o tempcomp.o util.o $(HASH_OBJ)
|
||||||
|
|
||||||
EXTRA_OBJS=@EXTRA_OBJECTS@
|
EXTRA_OBJS=@EXTRA_OBJECTS@
|
||||||
|
|
||||||
|
|
3
main.c
3
main.c
|
@ -38,6 +38,7 @@
|
||||||
#include "ntp_signd.h"
|
#include "ntp_signd.h"
|
||||||
#include "ntp_sources.h"
|
#include "ntp_sources.h"
|
||||||
#include "ntp_core.h"
|
#include "ntp_core.h"
|
||||||
|
#include "socket.h"
|
||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
#include "sourcestats.h"
|
#include "sourcestats.h"
|
||||||
#include "reference.h"
|
#include "reference.h"
|
||||||
|
@ -118,6 +119,7 @@ MAI_CleanupAndExit(void)
|
||||||
NCR_Finalise();
|
NCR_Finalise();
|
||||||
NIO_Finalise();
|
NIO_Finalise();
|
||||||
CAM_Finalise();
|
CAM_Finalise();
|
||||||
|
SCK_Finalise();
|
||||||
KEY_Finalise();
|
KEY_Finalise();
|
||||||
RCL_Finalise();
|
RCL_Finalise();
|
||||||
SRC_Finalise();
|
SRC_Finalise();
|
||||||
|
@ -554,6 +556,7 @@ int main
|
||||||
SRC_Initialise();
|
SRC_Initialise();
|
||||||
RCL_Initialise();
|
RCL_Initialise();
|
||||||
KEY_Initialise();
|
KEY_Initialise();
|
||||||
|
SCK_Initialise();
|
||||||
|
|
||||||
/* Open privileged ports before dropping root */
|
/* Open privileged ports before dropping root */
|
||||||
CAM_Initialise(address_family);
|
CAM_Initialise(address_family);
|
||||||
|
|
628
ntp_io.c
628
ntp_io.c
|
@ -30,11 +30,11 @@
|
||||||
|
|
||||||
#include "sysincl.h"
|
#include "sysincl.h"
|
||||||
|
|
||||||
#include "array.h"
|
|
||||||
#include "ntp_io.h"
|
#include "ntp_io.h"
|
||||||
#include "ntp_core.h"
|
#include "ntp_core.h"
|
||||||
#include "ntp_sources.h"
|
#include "ntp_sources.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
|
#include "socket.h"
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
@ -46,54 +46,16 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INVALID_SOCK_FD -1
|
#define INVALID_SOCK_FD -1
|
||||||
#define CMSGBUF_SIZE 256
|
|
||||||
|
|
||||||
union sockaddr_in46 {
|
|
||||||
struct sockaddr_in in4;
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
struct sockaddr_in6 in6;
|
|
||||||
#endif
|
|
||||||
struct sockaddr u;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Message {
|
|
||||||
union sockaddr_in46 name;
|
|
||||||
struct iovec iov;
|
|
||||||
NTP_Receive_Buffer buf;
|
|
||||||
/* Aligned buffer for control messages */
|
|
||||||
struct cmsghdr cmsgbuf[CMSGBUF_SIZE / sizeof (struct cmsghdr)];
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef HAVE_RECVMMSG
|
|
||||||
#define MAX_RECV_MESSAGES 4
|
|
||||||
#define MessageHeader mmsghdr
|
|
||||||
#else
|
|
||||||
/* Compatible with mmsghdr */
|
|
||||||
struct MessageHeader {
|
|
||||||
struct msghdr msg_hdr;
|
|
||||||
unsigned int msg_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_RECV_MESSAGES 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Arrays of Message and MessageHeader */
|
|
||||||
static ARR_Instance recv_messages;
|
|
||||||
static ARR_Instance recv_headers;
|
|
||||||
|
|
||||||
/* The server/peer and client sockets for IPv4 and IPv6 */
|
/* The server/peer and client sockets for IPv4 and IPv6 */
|
||||||
static int server_sock_fd4;
|
static int server_sock_fd4;
|
||||||
static int client_sock_fd4;
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
static int server_sock_fd6;
|
static int server_sock_fd6;
|
||||||
|
static int client_sock_fd4;
|
||||||
static int client_sock_fd6;
|
static int client_sock_fd6;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Reference counters for server sockets to keep them open only when needed */
|
/* Reference counters for server sockets to keep them open only when needed */
|
||||||
static int server_sock_ref4;
|
static int server_sock_ref4;
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
static int server_sock_ref6;
|
static int server_sock_ref6;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Flag indicating we create a new connected client socket for each
|
/* Flag indicating we create a new connected client socket for each
|
||||||
server instead of sharing client_sock_fd4 and client_sock_fd6 */
|
server instead of sharing client_sock_fd4 and client_sock_fd6 */
|
||||||
|
@ -119,162 +81,42 @@ static void read_from_socket(int sock_fd, int event, void *anything);
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
prepare_socket(int family, int port_number, int client_only)
|
open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr)
|
||||||
{
|
{
|
||||||
union sockaddr_in46 my_addr;
|
int sock_fd, sock_flags, events = SCH_FILE_INPUT;
|
||||||
socklen_t my_addr_len;
|
IPSockAddr local_addr;
|
||||||
int sock_fd;
|
|
||||||
IPAddr bind_address;
|
|
||||||
int events = SCH_FILE_INPUT, on_off = 1;
|
|
||||||
|
|
||||||
/* Open Internet domain UDP socket for NTP message transmissions */
|
if (!client_only)
|
||||||
|
CNF_GetBindAddress(family, &local_addr.ip_addr);
|
||||||
|
else
|
||||||
|
CNF_GetBindAcquisitionAddress(family, &local_addr.ip_addr);
|
||||||
|
|
||||||
sock_fd = socket(family, SOCK_DGRAM, 0);
|
if (local_addr.ip_addr.family != family)
|
||||||
|
SCK_GetAnyLocalIPAddress(family, &local_addr.ip_addr);
|
||||||
|
|
||||||
|
local_addr.port = local_port;
|
||||||
|
|
||||||
|
sock_flags = SCK_FLAG_RX_DEST_ADDR | SCK_FLAG_PRIV_BIND;
|
||||||
|
if (!client_only)
|
||||||
|
sock_flags |= SCK_FLAG_NONBLOCK | SCK_FLAG_BROADCAST;
|
||||||
|
|
||||||
|
sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, sock_flags);
|
||||||
if (sock_fd < 0) {
|
if (sock_fd < 0) {
|
||||||
if (!client_only) {
|
if (!client_only)
|
||||||
LOG(LOGS_ERR, "Could not open %s NTP socket : %s",
|
LOG(LOGS_ERR, "Could not open NTP socket on %s", UTI_IPSockAddrToString(&local_addr));
|
||||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
|
||||||
} else {
|
|
||||||
DEBUG_LOG("Could not open %s NTP socket : %s",
|
|
||||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
|
||||||
}
|
|
||||||
return INVALID_SOCK_FD;
|
return INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close on exec */
|
if (!client_only && family == IPADDR_INET4 && local_addr.port > 0)
|
||||||
UTI_FdSetCloexec(sock_fd);
|
bound_server_sock_fd4 = local_addr.ip_addr.addr.in4 != INADDR_ANY;
|
||||||
|
|
||||||
/* Enable non-blocking mode on server sockets */
|
|
||||||
if (!client_only && fcntl(sock_fd, F_SETFL, O_NONBLOCK))
|
|
||||||
DEBUG_LOG("Could not set O_NONBLOCK : %s", strerror(errno));
|
|
||||||
|
|
||||||
/* Prepare local address */
|
|
||||||
memset(&my_addr, 0, sizeof (my_addr));
|
|
||||||
my_addr_len = 0;
|
|
||||||
|
|
||||||
switch (family) {
|
|
||||||
case AF_INET:
|
|
||||||
if (!client_only)
|
|
||||||
CNF_GetBindAddress(IPADDR_INET4, &bind_address);
|
|
||||||
else
|
|
||||||
CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
|
|
||||||
|
|
||||||
if (bind_address.family == IPADDR_INET4)
|
|
||||||
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
|
|
||||||
else if (port_number)
|
|
||||||
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
my_addr.in4.sin_family = family;
|
|
||||||
my_addr.in4.sin_port = htons(port_number);
|
|
||||||
my_addr_len = sizeof (my_addr.in4);
|
|
||||||
|
|
||||||
if (!client_only)
|
|
||||||
bound_server_sock_fd4 = my_addr.in4.sin_addr.s_addr != htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
break;
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
case AF_INET6:
|
|
||||||
if (!client_only)
|
|
||||||
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
|
|
||||||
else
|
|
||||||
CNF_GetBindAcquisitionAddress(IPADDR_INET6, &bind_address);
|
|
||||||
|
|
||||||
if (bind_address.family == IPADDR_INET6)
|
|
||||||
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
|
|
||||||
sizeof (my_addr.in6.sin6_addr.s6_addr));
|
|
||||||
else if (port_number)
|
|
||||||
my_addr.in6.sin6_addr = in6addr_any;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
my_addr.in6.sin6_family = family;
|
|
||||||
my_addr.in6.sin6_port = htons(port_number);
|
|
||||||
my_addr_len = sizeof (my_addr.in6);
|
|
||||||
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make the socket capable of re-using an old address if binding to a specific port */
|
|
||||||
if (port_number &&
|
|
||||||
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "SO_REUSEADDR");
|
|
||||||
/* Don't quit - we might survive anyway */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
|
|
||||||
if (!client_only &&
|
|
||||||
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "SO_BROADCAST");
|
|
||||||
/* Don't quit - we might survive anyway */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable kernel/HW timestamping of packets */
|
/* Enable kernel/HW timestamping of packets */
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
|
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
|
||||||
#endif
|
#endif
|
||||||
#ifdef SO_TIMESTAMPNS
|
if (!SCK_EnableKernelRxTimestamping(sock_fd))
|
||||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, (char *)&on_off, sizeof(on_off)) < 0)
|
|
||||||
#endif
|
|
||||||
#ifdef SO_TIMESTAMP
|
|
||||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, (char *)&on_off, sizeof(on_off)) < 0)
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMP");
|
|
||||||
#endif
|
|
||||||
;
|
;
|
||||||
|
|
||||||
#ifdef IP_FREEBIND
|
|
||||||
/* Allow binding to address that doesn't exist yet */
|
|
||||||
if (my_addr_len > 0 &&
|
|
||||||
setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "IP_FREEBIND");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (family == AF_INET) {
|
|
||||||
#ifdef HAVE_IN_PKTINFO
|
|
||||||
if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0)
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "IP_PKTINFO");
|
|
||||||
#elif defined(IP_RECVDSTADDR)
|
|
||||||
if (setsockopt(sock_fd, IPPROTO_IP, IP_RECVDSTADDR, (char *)&on_off, sizeof(on_off)) < 0)
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "IP_RECVDSTADDR");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
else if (family == AF_INET6) {
|
|
||||||
#ifdef IPV6_V6ONLY
|
|
||||||
/* Receive IPv6 packets only */
|
|
||||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_V6ONLY");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_IN6_PKTINFO
|
|
||||||
#ifdef IPV6_RECVPKTINFO
|
|
||||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_RECVPKTINFO");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_PKTINFO");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Bind the socket if a port or address was specified */
|
|
||||||
if (my_addr_len > 0 && PRV_BindSocket(sock_fd, &my_addr.u, my_addr_len) < 0) {
|
|
||||||
LOG(LOGS_ERR, "Could not bind %s NTP socket : %s",
|
|
||||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
|
||||||
close(sock_fd);
|
|
||||||
return INVALID_SOCK_FD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register handler for read and possibly exception events on the socket */
|
/* Register handler for read and possibly exception events on the socket */
|
||||||
SCH_AddFileHandler(sock_fd, events, read_from_socket, NULL);
|
SCH_AddFileHandler(sock_fd, events, read_from_socket, NULL);
|
||||||
|
|
||||||
|
@ -284,40 +126,9 @@ prepare_socket(int family, int port_number, int client_only)
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
prepare_separate_client_socket(int family)
|
open_separate_client_socket(IPSockAddr *remote_addr)
|
||||||
{
|
{
|
||||||
switch (family) {
|
return open_socket(remote_addr->ip_addr.family, 0, 1, remote_addr);
|
||||||
case IPADDR_INET4:
|
|
||||||
return prepare_socket(AF_INET, 0, 1);
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
case IPADDR_INET6:
|
|
||||||
return prepare_socket(AF_INET6, 0, 1);
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return INVALID_SOCK_FD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================================================== */
|
|
||||||
|
|
||||||
static int
|
|
||||||
connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
|
|
||||||
{
|
|
||||||
union sockaddr_in46 addr;
|
|
||||||
socklen_t addr_len;
|
|
||||||
|
|
||||||
addr_len = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port, &addr.u);
|
|
||||||
|
|
||||||
assert(addr_len);
|
|
||||||
|
|
||||||
if (connect(sock_fd, &addr.u, addr_len) < 0) {
|
|
||||||
DEBUG_LOG("Could not connect NTP socket to %s:%d : %s",
|
|
||||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
|
||||||
strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -332,33 +143,7 @@ close_socket(int sock_fd)
|
||||||
NIO_Linux_NotifySocketClosing(sock_fd);
|
NIO_Linux_NotifySocketClosing(sock_fd);
|
||||||
#endif
|
#endif
|
||||||
SCH_RemoveFileHandler(sock_fd);
|
SCH_RemoveFileHandler(sock_fd);
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
}
|
|
||||||
|
|
||||||
/* ================================================== */
|
|
||||||
|
|
||||||
static void
|
|
||||||
prepare_buffers(unsigned int n)
|
|
||||||
{
|
|
||||||
struct MessageHeader *hdr;
|
|
||||||
struct Message *msg;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
msg = ARR_GetElement(recv_messages, i);
|
|
||||||
hdr = ARR_GetElement(recv_headers, i);
|
|
||||||
|
|
||||||
msg->iov.iov_base = &msg->buf;
|
|
||||||
msg->iov.iov_len = sizeof (msg->buf);
|
|
||||||
hdr->msg_hdr.msg_name = &msg->name;
|
|
||||||
hdr->msg_hdr.msg_namelen = sizeof (msg->name);
|
|
||||||
hdr->msg_hdr.msg_iov = &msg->iov;
|
|
||||||
hdr->msg_hdr.msg_iovlen = 1;
|
|
||||||
hdr->msg_hdr.msg_control = &msg->cmsgbuf;
|
|
||||||
hdr->msg_hdr.msg_controllen = sizeof (msg->cmsgbuf);
|
|
||||||
hdr->msg_hdr.msg_flags = 0;
|
|
||||||
hdr->msg_len = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -371,6 +156,10 @@ NIO_Initialise(int family)
|
||||||
assert(!initialised);
|
assert(!initialised);
|
||||||
initialised = 1;
|
initialised = 1;
|
||||||
|
|
||||||
|
#ifdef PRIVOPS_BINDSOCKET
|
||||||
|
SCK_SetPrivBind(PRV_BindSocket);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
NIO_Linux_Initialise();
|
NIO_Linux_Initialise();
|
||||||
#else
|
#else
|
||||||
|
@ -381,12 +170,6 @@ NIO_Initialise(int family)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
recv_messages = ARR_CreateInstance(sizeof (struct Message));
|
|
||||||
ARR_SetSize(recv_messages, MAX_RECV_MESSAGES);
|
|
||||||
recv_headers = ARR_CreateInstance(sizeof (struct MessageHeader));
|
|
||||||
ARR_SetSize(recv_headers, MAX_RECV_MESSAGES);
|
|
||||||
prepare_buffers(MAX_RECV_MESSAGES);
|
|
||||||
|
|
||||||
server_port = CNF_GetNTPPort();
|
server_port = CNF_GetNTPPort();
|
||||||
client_port = CNF_GetAcquisitionPort();
|
client_port = CNF_GetAcquisitionPort();
|
||||||
|
|
||||||
|
@ -399,47 +182,38 @@ NIO_Initialise(int family)
|
||||||
client_port == server_port);
|
client_port == server_port);
|
||||||
|
|
||||||
server_sock_fd4 = INVALID_SOCK_FD;
|
server_sock_fd4 = INVALID_SOCK_FD;
|
||||||
client_sock_fd4 = INVALID_SOCK_FD;
|
|
||||||
server_sock_ref4 = 0;
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
server_sock_fd6 = INVALID_SOCK_FD;
|
server_sock_fd6 = INVALID_SOCK_FD;
|
||||||
|
client_sock_fd4 = INVALID_SOCK_FD;
|
||||||
client_sock_fd6 = INVALID_SOCK_FD;
|
client_sock_fd6 = INVALID_SOCK_FD;
|
||||||
|
server_sock_ref4 = 0;
|
||||||
server_sock_ref6 = 0;
|
server_sock_ref6 = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
|
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
|
||||||
if (permanent_server_sockets && server_port)
|
if (permanent_server_sockets && server_port)
|
||||||
server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
|
server_sock_fd4 = open_socket(IPADDR_INET4, server_port, 0, NULL);
|
||||||
if (!separate_client_sockets) {
|
if (!separate_client_sockets) {
|
||||||
if (client_port != server_port || !server_port)
|
if (client_port != server_port || !server_port)
|
||||||
client_sock_fd4 = prepare_socket(AF_INET, client_port, 1);
|
client_sock_fd4 = open_socket(IPADDR_INET4, client_port, 1, NULL);
|
||||||
else
|
else
|
||||||
client_sock_fd4 = server_sock_fd4;
|
client_sock_fd4 = server_sock_fd4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
|
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
|
||||||
if (permanent_server_sockets && server_port)
|
if (permanent_server_sockets && server_port)
|
||||||
server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
|
server_sock_fd6 = open_socket(IPADDR_INET6, server_port, 0, NULL);
|
||||||
if (!separate_client_sockets) {
|
if (!separate_client_sockets) {
|
||||||
if (client_port != server_port || !server_port)
|
if (client_port != server_port || !server_port)
|
||||||
client_sock_fd6 = prepare_socket(AF_INET6, client_port, 1);
|
client_sock_fd6 = open_socket(IPADDR_INET6, client_port, 1, NULL);
|
||||||
else
|
else
|
||||||
client_sock_fd6 = server_sock_fd6;
|
client_sock_fd6 = server_sock_fd6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD &&
|
if ((server_port && permanent_server_sockets &&
|
||||||
permanent_server_sockets
|
server_sock_fd4 == INVALID_SOCK_FD && server_sock_fd6 == INVALID_SOCK_FD) ||
|
||||||
#ifdef FEAT_IPV6
|
(!separate_client_sockets &&
|
||||||
&& server_sock_fd6 == INVALID_SOCK_FD
|
client_sock_fd4 == INVALID_SOCK_FD && client_sock_fd6 == INVALID_SOCK_FD)) {
|
||||||
#endif
|
|
||||||
) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
&& client_sock_fd6 == INVALID_SOCK_FD
|
|
||||||
#endif
|
|
||||||
)) {
|
|
||||||
LOG_FATAL("Could not open NTP sockets");
|
LOG_FATAL("Could not open NTP sockets");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,14 +227,11 @@ NIO_Finalise(void)
|
||||||
close_socket(client_sock_fd4);
|
close_socket(client_sock_fd4);
|
||||||
close_socket(server_sock_fd4);
|
close_socket(server_sock_fd4);
|
||||||
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
|
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
if (server_sock_fd6 != client_sock_fd6)
|
if (server_sock_fd6 != client_sock_fd6)
|
||||||
close_socket(client_sock_fd6);
|
close_socket(client_sock_fd6);
|
||||||
close_socket(server_sock_fd6);
|
close_socket(server_sock_fd6);
|
||||||
server_sock_fd6 = client_sock_fd6 = INVALID_SOCK_FD;
|
server_sock_fd6 = client_sock_fd6 = INVALID_SOCK_FD;
|
||||||
#endif
|
|
||||||
ARR_DestroyInstance(recv_headers);
|
|
||||||
ARR_DestroyInstance(recv_messages);
|
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
NIO_Linux_Finalise();
|
NIO_Linux_Finalise();
|
||||||
|
@ -475,25 +246,13 @@ int
|
||||||
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
|
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
|
||||||
{
|
{
|
||||||
if (separate_client_sockets) {
|
if (separate_client_sockets) {
|
||||||
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
|
return open_separate_client_socket(remote_addr);
|
||||||
|
|
||||||
if (sock_fd == INVALID_SOCK_FD)
|
|
||||||
return INVALID_SOCK_FD;
|
|
||||||
|
|
||||||
if (!connect_socket(sock_fd, remote_addr)) {
|
|
||||||
close_socket(sock_fd);
|
|
||||||
return INVALID_SOCK_FD;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sock_fd;
|
|
||||||
} else {
|
} else {
|
||||||
switch (remote_addr->ip_addr.family) {
|
switch (remote_addr->ip_addr.family) {
|
||||||
case IPADDR_INET4:
|
case IPADDR_INET4:
|
||||||
return client_sock_fd4;
|
return client_sock_fd4;
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
case IPADDR_INET6:
|
case IPADDR_INET6:
|
||||||
return client_sock_fd6;
|
return client_sock_fd6;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
return INVALID_SOCK_FD;
|
return INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
|
@ -510,20 +269,18 @@ NIO_OpenServerSocket(NTP_Remote_Address *remote_addr)
|
||||||
if (permanent_server_sockets)
|
if (permanent_server_sockets)
|
||||||
return server_sock_fd4;
|
return server_sock_fd4;
|
||||||
if (server_sock_fd4 == INVALID_SOCK_FD)
|
if (server_sock_fd4 == INVALID_SOCK_FD)
|
||||||
server_sock_fd4 = prepare_socket(AF_INET, CNF_GetNTPPort(), 0);
|
server_sock_fd4 = open_socket(IPADDR_INET4, CNF_GetNTPPort(), 0, NULL);
|
||||||
if (server_sock_fd4 != INVALID_SOCK_FD)
|
if (server_sock_fd4 != INVALID_SOCK_FD)
|
||||||
server_sock_ref4++;
|
server_sock_ref4++;
|
||||||
return server_sock_fd4;
|
return server_sock_fd4;
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
case IPADDR_INET6:
|
case IPADDR_INET6:
|
||||||
if (permanent_server_sockets)
|
if (permanent_server_sockets)
|
||||||
return server_sock_fd6;
|
return server_sock_fd6;
|
||||||
if (server_sock_fd6 == INVALID_SOCK_FD)
|
if (server_sock_fd6 == INVALID_SOCK_FD)
|
||||||
server_sock_fd6 = prepare_socket(AF_INET6, CNF_GetNTPPort(), 0);
|
server_sock_fd6 = open_socket(IPADDR_INET6, CNF_GetNTPPort(), 0, NULL);
|
||||||
if (server_sock_fd6 != INVALID_SOCK_FD)
|
if (server_sock_fd6 != INVALID_SOCK_FD)
|
||||||
server_sock_ref6++;
|
server_sock_ref6++;
|
||||||
return server_sock_fd6;
|
return server_sock_fd6;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
return INVALID_SOCK_FD;
|
return INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
|
@ -551,16 +308,12 @@ NIO_CloseServerSocket(int sock_fd)
|
||||||
close_socket(server_sock_fd4);
|
close_socket(server_sock_fd4);
|
||||||
server_sock_fd4 = INVALID_SOCK_FD;
|
server_sock_fd4 = INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
}
|
} else if (sock_fd == server_sock_fd6) {
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
else if (sock_fd == server_sock_fd6) {
|
|
||||||
if (--server_sock_ref6 <= 0) {
|
if (--server_sock_ref6 <= 0) {
|
||||||
close_socket(server_sock_fd6);
|
close_socket(server_sock_fd6);
|
||||||
server_sock_fd6 = INVALID_SOCK_FD;
|
server_sock_fd6 = INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,11 +324,7 @@ int
|
||||||
NIO_IsServerSocket(int sock_fd)
|
NIO_IsServerSocket(int sock_fd)
|
||||||
{
|
{
|
||||||
return sock_fd != INVALID_SOCK_FD &&
|
return sock_fd != INVALID_SOCK_FD &&
|
||||||
(sock_fd == server_sock_fd4
|
(sock_fd == server_sock_fd4 || sock_fd == server_sock_fd6);
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
|| sock_fd == server_sock_fd6
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -583,132 +332,61 @@ NIO_IsServerSocket(int sock_fd)
|
||||||
int
|
int
|
||||||
NIO_IsServerConnectable(NTP_Remote_Address *remote_addr)
|
NIO_IsServerConnectable(NTP_Remote_Address *remote_addr)
|
||||||
{
|
{
|
||||||
int sock_fd, r;
|
int sock_fd;
|
||||||
|
|
||||||
sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
|
sock_fd = open_separate_client_socket(remote_addr);
|
||||||
if (sock_fd == INVALID_SOCK_FD)
|
if (sock_fd == INVALID_SOCK_FD)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = connect_socket(sock_fd, remote_addr);
|
|
||||||
close_socket(sock_fd);
|
close_socket(sock_fd);
|
||||||
|
|
||||||
return r;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_message(struct msghdr *hdr, int length, int sock_fd)
|
process_message(SCK_Message *message, int sock_fd, int event)
|
||||||
{
|
{
|
||||||
NTP_Remote_Address remote_addr;
|
|
||||||
NTP_Local_Address local_addr;
|
NTP_Local_Address local_addr;
|
||||||
NTP_Local_Timestamp local_ts;
|
NTP_Local_Timestamp local_ts;
|
||||||
struct timespec sched_ts;
|
struct timespec sched_ts;
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
|
|
||||||
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
||||||
local_ts.source = NTP_TS_DAEMON;
|
local_ts.source = NTP_TS_DAEMON;
|
||||||
sched_ts = local_ts.ts;
|
sched_ts = local_ts.ts;
|
||||||
|
|
||||||
if (hdr->msg_namelen > sizeof (union sockaddr_in46)) {
|
if (message->addr_type != SCK_ADDR_IP) {
|
||||||
DEBUG_LOG("Truncated source address");
|
DEBUG_LOG("Unexpected address type");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr->msg_namelen >= sizeof (((struct sockaddr *)hdr->msg_name)->sa_family)) {
|
local_addr.ip_addr = message->local_addr.ip;
|
||||||
UTI_SockaddrToIPAndPort((struct sockaddr *)hdr->msg_name,
|
local_addr.if_index = message->if_index;;
|
||||||
&remote_addr.ip_addr, &remote_addr.port);
|
|
||||||
} else {
|
|
||||||
remote_addr.ip_addr.family = IPADDR_UNSPEC;
|
|
||||||
remote_addr.port = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
|
||||||
local_addr.if_index = INVALID_IF_INDEX;
|
|
||||||
local_addr.sock_fd = sock_fd;
|
local_addr.sock_fd = sock_fd;
|
||||||
|
|
||||||
if (hdr->msg_flags & MSG_TRUNC) {
|
|
||||||
DEBUG_LOG("Received truncated message from %s:%d",
|
|
||||||
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr->msg_flags & MSG_CTRUNC) {
|
|
||||||
DEBUG_LOG("Truncated control message");
|
|
||||||
/* Continue */
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
|
|
||||||
#ifdef HAVE_IN_PKTINFO
|
|
||||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
|
||||||
struct in_pktinfo ipi;
|
|
||||||
|
|
||||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
|
||||||
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
|
|
||||||
local_addr.ip_addr.family = IPADDR_INET4;
|
|
||||||
local_addr.if_index = ipi.ipi_ifindex;
|
|
||||||
}
|
|
||||||
#elif defined(IP_RECVDSTADDR)
|
|
||||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
|
|
||||||
struct in_addr addr;
|
|
||||||
|
|
||||||
memcpy(&addr, CMSG_DATA(cmsg), sizeof (addr));
|
|
||||||
local_addr.ip_addr.addr.in4 = ntohl(addr.s_addr);
|
|
||||||
local_addr.ip_addr.family = IPADDR_INET4;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_IN6_PKTINFO
|
|
||||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
|
||||||
struct in6_pktinfo ipi;
|
|
||||||
|
|
||||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
|
||||||
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
|
|
||||||
sizeof (local_addr.ip_addr.addr.in6));
|
|
||||||
local_addr.ip_addr.family = IPADDR_INET6;
|
|
||||||
local_addr.if_index = ipi.ipi6_ifindex;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SCM_TIMESTAMP
|
|
||||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) {
|
|
||||||
struct timeval tv;
|
|
||||||
struct timespec ts;
|
|
||||||
|
|
||||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
|
||||||
UTI_TimevalToTimespec(&tv, &ts);
|
|
||||||
LCL_CookTime(&ts, &local_ts.ts, &local_ts.err);
|
|
||||||
local_ts.source = NTP_TS_KERNEL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SCM_TIMESTAMPNS
|
|
||||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
|
|
||||||
struct timespec ts;
|
|
||||||
|
|
||||||
memcpy(&ts, CMSG_DATA(cmsg), sizeof (ts));
|
|
||||||
LCL_CookTime(&ts, &local_ts.ts, &local_ts.err);
|
|
||||||
local_ts.source = NTP_TS_KERNEL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
|
if (NIO_Linux_ProcessMessage(message, &local_addr, &local_ts, event))
|
||||||
return;
|
return;
|
||||||
|
#else
|
||||||
|
if (!UTI_IsZeroTimespec(&message->timestamp.kernel)) {
|
||||||
|
LCL_CookTime(&message->timestamp.kernel, &local_ts.ts, &local_ts.err);
|
||||||
|
local_ts.source = NTP_TS_KERNEL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG_LOG("Received %d bytes from %s:%d to %s fd=%d if=%d tss=%u delay=%.9f",
|
if (local_ts.source != NTP_TS_DAEMON)
|
||||||
length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
|
DEBUG_LOG("Updated RX timestamp delay=%.9f tss=%u",
|
||||||
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
|
UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts), local_ts.source);
|
||||||
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
|
|
||||||
|
|
||||||
/* Just ignore the packet if it's not of a recognized length */
|
/* Just ignore the packet if it's not of a recognized length */
|
||||||
if (length < NTP_NORMAL_PACKET_LENGTH || length > sizeof (NTP_Receive_Buffer))
|
if (message->length < NTP_NORMAL_PACKET_LENGTH ||
|
||||||
|
message->length > sizeof (NTP_Receive_Buffer)) {
|
||||||
|
DEBUG_LOG("Unexpected length");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NSR_ProcessRx(&remote_addr, &local_addr, &local_ts,
|
NSR_ProcessRx(&message->remote_addr.ip, &local_addr, &local_ts, message->data, message->length);
|
||||||
(NTP_Packet *)hdr->msg_iov[0].iov_base, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -719,65 +397,28 @@ read_from_socket(int sock_fd, int event, void *anything)
|
||||||
/* This should only be called when there is something
|
/* This should only be called when there is something
|
||||||
to read, otherwise it may block */
|
to read, otherwise it may block */
|
||||||
|
|
||||||
struct MessageHeader *hdr;
|
SCK_Message messages[SCK_MAX_RECV_MESSAGES];
|
||||||
unsigned int i, n;
|
int i, received, flags = 0;
|
||||||
int status, flags = 0;
|
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
if (NIO_Linux_ProcessEvent(sock_fd, event))
|
if (NIO_Linux_ProcessEvent(sock_fd, event))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
hdr = ARR_GetElements(recv_headers);
|
|
||||||
n = ARR_GetSize(recv_headers);
|
|
||||||
assert(n >= 1);
|
|
||||||
|
|
||||||
if (event == SCH_FILE_EXCEPTION) {
|
if (event == SCH_FILE_EXCEPTION) {
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
flags |= MSG_ERRQUEUE;
|
flags |= SCK_FLAG_MSG_ERRQUEUE;
|
||||||
#else
|
#else
|
||||||
assert(0);
|
assert(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RECVMMSG
|
received = SCK_ReceiveMessages(sock_fd, messages, SCK_MAX_RECV_MESSAGES, flags);
|
||||||
status = recvmmsg(sock_fd, hdr, n, flags | MSG_DONTWAIT, NULL);
|
if (received <= 0)
|
||||||
if (status >= 0)
|
|
||||||
n = status;
|
|
||||||
#else
|
|
||||||
n = 1;
|
|
||||||
status = recvmsg(sock_fd, &hdr[0].msg_hdr, flags);
|
|
||||||
if (status >= 0)
|
|
||||||
hdr[0].msg_len = status;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (status < 0) {
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
|
||||||
/* If reading from the error queue failed, the exception should be
|
|
||||||
for a socket error. Clear the error to avoid a busy loop. */
|
|
||||||
if (flags & MSG_ERRQUEUE) {
|
|
||||||
int error = 0;
|
|
||||||
socklen_t len = sizeof (error);
|
|
||||||
|
|
||||||
if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &error, &len))
|
|
||||||
DEBUG_LOG("Could not get SO_ERROR");
|
|
||||||
if (error)
|
|
||||||
errno = error;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DEBUG_LOG("Could not receive from fd %d : %s", sock_fd,
|
|
||||||
strerror(errno));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < received; i++)
|
||||||
hdr = ARR_GetElement(recv_headers, i);
|
process_message(&messages[i], sock_fd, event);
|
||||||
process_message(&hdr->msg_hdr, hdr->msg_len, sock_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore the buffers to their original state */
|
|
||||||
prepare_buffers(n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -787,12 +428,7 @@ int
|
||||||
NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
||||||
NTP_Local_Address *local_addr, int length, int process_tx)
|
NTP_Local_Address *local_addr, int length, int process_tx)
|
||||||
{
|
{
|
||||||
union sockaddr_in46 remote;
|
SCK_Message message;
|
||||||
struct msghdr msg;
|
|
||||||
struct iovec iov;
|
|
||||||
struct cmsghdr *cmsg, cmsgbuf[CMSGBUF_SIZE / sizeof (struct cmsghdr)];
|
|
||||||
int cmsglen;
|
|
||||||
socklen_t addrlen = 0;
|
|
||||||
|
|
||||||
assert(initialised);
|
assert(initialised);
|
||||||
|
|
||||||
|
@ -802,108 +438,34 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't set address with connected socket */
|
SCK_InitMessage(&message, SCK_ADDR_IP);
|
||||||
|
|
||||||
|
message.data = packet;
|
||||||
|
message.length = length;
|
||||||
|
|
||||||
|
/* Specify remote address if the socket is not connected */
|
||||||
if (NIO_IsServerSocket(local_addr->sock_fd) || !separate_client_sockets) {
|
if (NIO_IsServerSocket(local_addr->sock_fd) || !separate_client_sockets) {
|
||||||
addrlen = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port,
|
message.remote_addr.ip.ip_addr = remote_addr->ip_addr;
|
||||||
&remote.u);
|
message.remote_addr.ip.port = remote_addr->port;
|
||||||
if (!addrlen)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addrlen) {
|
message.if_index = local_addr->if_index;
|
||||||
msg.msg_name = &remote.u;
|
message.local_addr.ip = local_addr->ip_addr;
|
||||||
msg.msg_namelen = addrlen;
|
|
||||||
} else {
|
|
||||||
msg.msg_name = NULL;
|
|
||||||
msg.msg_namelen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
iov.iov_base = packet;
|
#if !defined(HAVE_IN_PKTINFO) && defined(IP_SENDSRCADDR)
|
||||||
iov.iov_len = length;
|
/* On FreeBSD a local IPv4 address cannot be specified on bound socket */
|
||||||
msg.msg_iov = &iov;
|
if (message.local_addr.ip.family == IPADDR_INET4 &&
|
||||||
msg.msg_iovlen = 1;
|
(local_addr->sock_fd != server_sock_fd4 || bound_server_sock_fd4))
|
||||||
msg.msg_control = cmsgbuf;
|
message.local_addr.ip.family = IPADDR_UNSPEC;
|
||||||
msg.msg_controllen = sizeof(cmsgbuf);
|
|
||||||
msg.msg_flags = 0;
|
|
||||||
cmsglen = 0;
|
|
||||||
|
|
||||||
#ifdef HAVE_IN_PKTINFO
|
|
||||||
if (local_addr->ip_addr.family == IPADDR_INET4) {
|
|
||||||
struct in_pktinfo *ipi;
|
|
||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
|
||||||
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in_pktinfo)));
|
|
||||||
cmsglen += CMSG_SPACE(sizeof(struct in_pktinfo));
|
|
||||||
|
|
||||||
cmsg->cmsg_level = IPPROTO_IP;
|
|
||||||
cmsg->cmsg_type = IP_PKTINFO;
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
|
||||||
|
|
||||||
ipi = (struct in_pktinfo *) CMSG_DATA(cmsg);
|
|
||||||
ipi->ipi_spec_dst.s_addr = htonl(local_addr->ip_addr.addr.in4);
|
|
||||||
if (local_addr->if_index != INVALID_IF_INDEX)
|
|
||||||
ipi->ipi_ifindex = local_addr->if_index;
|
|
||||||
}
|
|
||||||
#elif defined(IP_SENDSRCADDR)
|
|
||||||
/* Specify the IPv4 source address only if the socket is not bound */
|
|
||||||
if (local_addr->ip_addr.family == IPADDR_INET4 &&
|
|
||||||
local_addr->sock_fd == server_sock_fd4 && !bound_server_sock_fd4) {
|
|
||||||
struct in_addr *addr;
|
|
||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
|
||||||
memset(cmsg, 0, CMSG_SPACE(sizeof (struct in_addr)));
|
|
||||||
cmsglen += CMSG_SPACE(sizeof (struct in_addr));
|
|
||||||
|
|
||||||
cmsg->cmsg_level = IPPROTO_IP;
|
|
||||||
cmsg->cmsg_type = IP_SENDSRCADDR;
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_addr));
|
|
||||||
|
|
||||||
addr = (struct in_addr *)CMSG_DATA(cmsg);
|
|
||||||
addr->s_addr = htonl(local_addr->ip_addr.addr.in4);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_IN6_PKTINFO
|
|
||||||
if (local_addr->ip_addr.family == IPADDR_INET6) {
|
|
||||||
struct in6_pktinfo *ipi;
|
|
||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
|
||||||
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
|
|
||||||
cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
|
|
||||||
|
|
||||||
cmsg->cmsg_level = IPPROTO_IPV6;
|
|
||||||
cmsg->cmsg_type = IPV6_PKTINFO;
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
|
||||||
|
|
||||||
ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
|
|
||||||
memcpy(&ipi->ipi6_addr.s6_addr, &local_addr->ip_addr.addr.in6,
|
|
||||||
sizeof(ipi->ipi6_addr.s6_addr));
|
|
||||||
if (local_addr->if_index != INVALID_IF_INDEX)
|
|
||||||
ipi->ipi6_ifindex = local_addr->if_index;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
if (process_tx)
|
if (process_tx)
|
||||||
cmsglen = NIO_Linux_RequestTxTimestamp(&msg, cmsglen, local_addr->sock_fd);
|
NIO_Linux_RequestTxTimestamp(&message, local_addr->sock_fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
msg.msg_controllen = cmsglen;
|
if (!SCK_SendMessage(local_addr->sock_fd, &message, 0))
|
||||||
/* This is apparently required on some systems */
|
|
||||||
if (!cmsglen)
|
|
||||||
msg.msg_control = NULL;
|
|
||||||
|
|
||||||
if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
|
|
||||||
DEBUG_LOG("Could not send to %s:%d from %s fd %d : %s",
|
|
||||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
|
||||||
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd,
|
|
||||||
strerror(errno));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_LOG("Sent %d bytes to %s:%d from %s fd %d", length,
|
|
||||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
|
||||||
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
187
ntp_io_linux.c
187
ntp_io_linux.c
|
@ -29,7 +29,6 @@
|
||||||
#include "sysincl.h"
|
#include "sysincl.h"
|
||||||
|
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
#include <linux/errqueue.h>
|
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
#include <linux/net_tstamp.h>
|
#include <linux/net_tstamp.h>
|
||||||
#include <linux/sockios.h>
|
#include <linux/sockios.h>
|
||||||
|
@ -45,17 +44,10 @@
|
||||||
#include "ntp_io_linux.h"
|
#include "ntp_io_linux.h"
|
||||||
#include "ntp_sources.h"
|
#include "ntp_sources.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
|
#include "socket.h"
|
||||||
#include "sys_linux.h"
|
#include "sys_linux.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
union sockaddr_in46 {
|
|
||||||
struct sockaddr_in in4;
|
|
||||||
#ifdef FEAT_IPV6
|
|
||||||
struct sockaddr_in6 in6;
|
|
||||||
#endif
|
|
||||||
struct sockaddr u;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Interface {
|
struct Interface {
|
||||||
char name[IF_NAMESIZE];
|
char name[IF_NAMESIZE];
|
||||||
int if_index;
|
int if_index;
|
||||||
|
@ -133,7 +125,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||||
if (sock_fd < 0)
|
if (sock_fd < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -142,13 +134,13 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||||
|
|
||||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
||||||
sizeof (req.ifr_name)) {
|
sizeof (req.ifr_name)) {
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
|
if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
|
||||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
|
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +151,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||||
|
|
||||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,13 +159,13 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||||
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
|
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
|
||||||
DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
|
DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts_info.phc_index < 0) {
|
if (ts_info.phc_index < 0) {
|
||||||
DEBUG_LOG("PHC missing on %s", req.ifr_name);
|
DEBUG_LOG("PHC missing on %s", req.ifr_name);
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,12 +211,12 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||||
ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter)
|
ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
|
|
||||||
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||||
if (phc_fd < 0)
|
if (phc_fd < 0)
|
||||||
|
@ -293,7 +285,7 @@ update_interface_speed(struct Interface *iface)
|
||||||
struct ifreq req;
|
struct ifreq req;
|
||||||
int sock_fd, link_speed;
|
int sock_fd, link_speed;
|
||||||
|
|
||||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||||
if (sock_fd < 0)
|
if (sock_fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -306,11 +298,11 @@ update_interface_speed(struct Interface *iface)
|
||||||
|
|
||||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
|
|
||||||
link_speed = ethtool_cmd_speed(&cmd);
|
link_speed = ethtool_cmd_speed(&cmd);
|
||||||
|
|
||||||
|
@ -328,17 +320,17 @@ check_timestamping_option(int option)
|
||||||
{
|
{
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
|
|
||||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||||
if (sock_fd < 0)
|
if (sock_fd < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &option, sizeof (option)) < 0) {
|
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &option, sizeof (option)) < 0) {
|
||||||
DEBUG_LOG("Could not enable timestamping option %x", (unsigned int)option);
|
DEBUG_LOG("Could not enable timestamping option %x", (unsigned int)option);
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -350,19 +342,15 @@ open_dummy_socket(void)
|
||||||
{
|
{
|
||||||
int sock_fd, events = 0;
|
int sock_fd, events = 0;
|
||||||
|
|
||||||
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||||
#ifdef FEAT_IPV6
|
if (sock_fd < 0)
|
||||||
&& (sock_fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
return INVALID_SOCK_FD;
|
return INVALID_SOCK_FD;
|
||||||
|
|
||||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
return INVALID_SOCK_FD;
|
return INVALID_SOCK_FD;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTI_FdSetCloexec(sock_fd);
|
|
||||||
return sock_fd;
|
return sock_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +420,7 @@ NIO_Linux_Finalise(void)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||||
close(dummy_rxts_socket);
|
SCK_CloseSocket(dummy_rxts_socket);
|
||||||
|
|
||||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||||
iface = ARR_GetElement(interfaces, i);
|
iface = ARR_GetElement(interfaces, i);
|
||||||
|
@ -462,14 +450,12 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
||||||
if (client_only || permanent_ts_options)
|
if (client_only || permanent_ts_options)
|
||||||
flags |= ts_tx_flags;
|
flags |= ts_tx_flags;
|
||||||
|
|
||||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, &val, sizeof (val)) < 0) {
|
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, val)) {
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "SO_SELECT_ERR_QUEUE");
|
|
||||||
ts_flags = 0;
|
ts_flags = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof (flags)) < 0) {
|
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, flags)) {
|
||||||
LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMPING");
|
|
||||||
ts_flags = 0;
|
ts_flags = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -633,7 +619,6 @@ static int
|
||||||
extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||||
{
|
{
|
||||||
unsigned char *msg_start = msg;
|
unsigned char *msg_start = msg;
|
||||||
union sockaddr_in46 addr;
|
|
||||||
|
|
||||||
remote_addr->ip_addr.family = IPADDR_UNSPEC;
|
remote_addr->ip_addr.family = IPADDR_UNSPEC;
|
||||||
remote_addr->port = 0;
|
remote_addr->port = 0;
|
||||||
|
@ -656,19 +641,21 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||||
/* Parse destination address and port from IPv4/IPv6 and UDP headers */
|
/* Parse destination address and port from IPv4/IPv6 and UDP headers */
|
||||||
if (len >= 20 && msg[0] >> 4 == 4) {
|
if (len >= 20 && msg[0] >> 4 == 4) {
|
||||||
int ihl = (msg[0] & 0xf) * 4;
|
int ihl = (msg[0] & 0xf) * 4;
|
||||||
|
uint32_t addr;
|
||||||
|
|
||||||
if (len < ihl + 8 || msg[9] != 17)
|
if (len < ihl + 8 || msg[9] != 17)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memcpy(&addr.in4.sin_addr.s_addr, msg + 16, sizeof (uint32_t));
|
memcpy(&addr, msg + 16, sizeof (addr));
|
||||||
addr.in4.sin_port = *(uint16_t *)(msg + ihl + 2);
|
remote_addr->ip_addr.addr.in4 = ntohl(addr);
|
||||||
addr.in4.sin_family = AF_INET;
|
remote_addr->port = ntohs(*(uint16_t *)(msg + ihl + 2));
|
||||||
|
remote_addr->ip_addr.family = IPADDR_INET4;
|
||||||
len -= ihl + 8, msg += ihl + 8;
|
len -= ihl + 8, msg += ihl + 8;
|
||||||
#ifdef FEAT_IPV6
|
#ifdef FEAT_IPV6
|
||||||
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
||||||
int eh_len, next_header = msg[6];
|
int eh_len, next_header = msg[6];
|
||||||
|
|
||||||
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
|
memcpy(&remote_addr->ip_addr.addr.in6, msg + 24, sizeof (remote_addr->ip_addr.addr.in6));
|
||||||
len -= 40, msg += 40;
|
len -= 40, msg += 40;
|
||||||
|
|
||||||
/* Skip IPv6 extension headers if present */
|
/* Skip IPv6 extension headers if present */
|
||||||
|
@ -700,16 +687,14 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||||
len -= eh_len, msg += eh_len;
|
len -= eh_len, msg += eh_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.in6.sin6_port = *(uint16_t *)(msg + 2);
|
remote_addr->port = ntohs(*(uint16_t *)(msg + 2));
|
||||||
addr.in6.sin6_family = AF_INET6;
|
remote_addr->ip_addr.family = IPADDR_INET6;
|
||||||
len -= 8, msg += 8;
|
len -= 8, msg += 8;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UTI_SockaddrToIPAndPort(&addr.u, &remote_addr->ip_addr, &remote_addr->port);
|
|
||||||
|
|
||||||
/* Move the message to fix alignment of its fields */
|
/* Move the message to fix alignment of its fields */
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
memmove(msg_start, msg, len);
|
memmove(msg_start, msg, len);
|
||||||
|
@ -720,42 +705,25 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
int
|
int
|
||||||
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length)
|
NTP_Local_Timestamp *local_ts, int event)
|
||||||
{
|
{
|
||||||
struct Interface *iface;
|
struct Interface *iface;
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
int is_tx, ts_if_index, l2_length;
|
int is_tx, ts_if_index, l2_length;
|
||||||
|
|
||||||
is_tx = hdr->msg_flags & MSG_ERRQUEUE;
|
is_tx = event == SCH_FILE_EXCEPTION;
|
||||||
iface = NULL;
|
iface = NULL;
|
||||||
ts_if_index = local_addr->if_index;
|
|
||||||
l2_length = 0;
|
|
||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
|
ts_if_index = message->timestamp.if_index;
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
|
if (ts_if_index == INVALID_IF_INDEX)
|
||||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING_PKTINFO) {
|
ts_if_index = message->if_index;
|
||||||
struct scm_ts_pktinfo ts_pktinfo;
|
l2_length = message->timestamp.l2_length;
|
||||||
|
|
||||||
memcpy(&ts_pktinfo, CMSG_DATA(cmsg), sizeof (ts_pktinfo));
|
if (!UTI_IsZeroTimespec(&message->timestamp.hw)) {
|
||||||
|
|
||||||
ts_if_index = ts_pktinfo.if_index;
|
|
||||||
l2_length = ts_pktinfo.pkt_length;
|
|
||||||
|
|
||||||
DEBUG_LOG("Received HW timestamp info if=%d length=%d", ts_if_index, l2_length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) {
|
|
||||||
struct scm_timestamping ts3;
|
|
||||||
|
|
||||||
memcpy(&ts3, CMSG_DATA(cmsg), sizeof (ts3));
|
|
||||||
|
|
||||||
if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
|
|
||||||
iface = get_interface(ts_if_index);
|
iface = get_interface(ts_if_index);
|
||||||
if (iface) {
|
if (iface) {
|
||||||
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
|
process_hw_timestamp(iface, &message->timestamp.hw, local_ts, !is_tx ? message->length : 0,
|
||||||
remote_addr->ip_addr.family, l2_length);
|
message->remote_addr.ip.ip_addr.family, l2_length);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
||||||
}
|
}
|
||||||
|
@ -766,27 +734,11 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||||
resume_socket(local_addr->sock_fd);
|
resume_socket(local_addr->sock_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
|
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&message->timestamp.kernel) &&
|
||||||
(!is_tx || UTI_IsZeroTimespec(&ts3.ts[2]))) {
|
(!is_tx || UTI_IsZeroTimespec(&message->timestamp.hw))) {
|
||||||
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
|
LCL_CookTime(&message->timestamp.kernel, &local_ts->ts, &local_ts->err);
|
||||||
local_ts->source = NTP_TS_KERNEL;
|
local_ts->source = NTP_TS_KERNEL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ((cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) ||
|
|
||||||
(cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR)) {
|
|
||||||
struct sock_extended_err err;
|
|
||||||
|
|
||||||
memcpy(&err, CMSG_DATA(cmsg), sizeof (err));
|
|
||||||
|
|
||||||
if (err.ee_errno != ENOMSG || err.ee_info != SCM_TSTAMP_SND ||
|
|
||||||
err.ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
|
|
||||||
DEBUG_LOG("Unknown extended error");
|
|
||||||
/* Drop the message */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
||||||
socket to keep the kernel RX timestamping permanently enabled */
|
socket to keep the kernel RX timestamping permanently enabled */
|
||||||
|
@ -803,19 +755,19 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||||
/* The data from the error queue includes all layers up to UDP. We have to
|
/* The data from the error queue includes all layers up to UDP. We have to
|
||||||
extract the UDP data and also the destination address with port as there
|
extract the UDP data and also the destination address with port as there
|
||||||
currently doesn't seem to be a better way to get them both. */
|
currently doesn't seem to be a better way to get them both. */
|
||||||
l2_length = length;
|
l2_length = message->length;
|
||||||
length = extract_udp_data(hdr->msg_iov[0].iov_base, remote_addr, length);
|
message->length = extract_udp_data(message->data, &message->remote_addr.ip, message->length);
|
||||||
|
|
||||||
DEBUG_LOG("Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%u",
|
DEBUG_LOG("Extracted message for %s fd=%d len=%u",
|
||||||
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
UTI_IPSockAddrToString(&message->remote_addr.ip),
|
||||||
local_addr->sock_fd, local_addr->if_index, local_ts->source);
|
local_addr->sock_fd, message->length);
|
||||||
|
|
||||||
/* Update assumed position of UDP data at layer 2 for next received packet */
|
/* Update assumed position of UDP data at layer 2 for next received packet */
|
||||||
if (iface && length) {
|
if (iface && message->length) {
|
||||||
if (remote_addr->ip_addr.family == IPADDR_INET4)
|
if (message->remote_addr.ip.ip_addr.family == IPADDR_INET4)
|
||||||
iface->l2_udp4_ntp_start = l2_length - length;
|
iface->l2_udp4_ntp_start = l2_length - message->length;
|
||||||
else if (remote_addr->ip_addr.family == IPADDR_INET6)
|
else if (message->remote_addr.ip.ip_addr.family == IPADDR_INET6)
|
||||||
iface->l2_udp6_ntp_start = l2_length - length;
|
iface->l2_udp6_ntp_start = l2_length - message->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop the message if it has no timestamp or its processing failed */
|
/* Drop the message if it has no timestamp or its processing failed */
|
||||||
|
@ -824,24 +776,21 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length < NTP_NORMAL_PACKET_LENGTH)
|
if (message->length < NTP_NORMAL_PACKET_LENGTH)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
NSR_ProcessTx(remote_addr, local_addr, local_ts,
|
NSR_ProcessTx(&message->remote_addr.ip, local_addr, local_ts, message->data, message->length);
|
||||||
(NTP_Packet *)hdr->msg_iov[0].iov_base, length);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
int
|
void
|
||||||
NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd)
|
||||||
{
|
{
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
|
|
||||||
if (!ts_flags)
|
if (!ts_flags)
|
||||||
return cmsglen;
|
return;
|
||||||
|
|
||||||
/* If a HW transmit timestamp is requested on a client socket, monitor
|
/* If a HW transmit timestamp is requested on a client socket, monitor
|
||||||
events on the socket in order to avoid processing of a fast response
|
events on the socket in order to avoid processing of a fast response
|
||||||
|
@ -851,27 +800,9 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
||||||
|
|
||||||
/* Check if TX timestamping is disabled on this socket */
|
/* Check if TX timestamping is disabled on this socket */
|
||||||
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
||||||
return cmsglen;
|
return;
|
||||||
|
|
||||||
/* Add control message that will enable TX timestamping for this message.
|
message->timestamp.tx_flags = ts_tx_flags;
|
||||||
Don't use CMSG_NXTHDR as the one in glibc is buggy for creating new
|
|
||||||
control messages. */
|
|
||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(msg);
|
|
||||||
if (!cmsg || cmsglen + CMSG_SPACE(sizeof (ts_tx_flags)) > msg->msg_controllen)
|
|
||||||
return cmsglen;
|
|
||||||
|
|
||||||
cmsg = (struct cmsghdr *)((char *)cmsg + cmsglen);
|
|
||||||
memset(cmsg, 0, CMSG_SPACE(sizeof (ts_tx_flags)));
|
|
||||||
cmsglen += CMSG_SPACE(sizeof (ts_tx_flags));
|
|
||||||
|
|
||||||
cmsg->cmsg_level = SOL_SOCKET;
|
|
||||||
cmsg->cmsg_type = SO_TIMESTAMPING;
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof (ts_tx_flags));
|
|
||||||
|
|
||||||
memcpy(CMSG_DATA(cmsg), &ts_tx_flags, sizeof (ts_tx_flags));
|
|
||||||
|
|
||||||
return cmsglen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#ifndef GOT_NTP_IO_LINUX_H
|
#ifndef GOT_NTP_IO_LINUX_H
|
||||||
#define GOT_NTP_IO_LINUX_H
|
#define GOT_NTP_IO_LINUX_H
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
extern void NIO_Linux_Initialise(void);
|
extern void NIO_Linux_Initialise(void);
|
||||||
|
|
||||||
extern void NIO_Linux_Finalise(void);
|
extern void NIO_Linux_Finalise(void);
|
||||||
|
@ -35,10 +37,10 @@ extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int
|
||||||
|
|
||||||
extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
|
extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
|
||||||
|
|
||||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
extern int NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
NTP_Local_Timestamp *local_ts, int event);
|
||||||
|
|
||||||
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
extern void NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd);
|
||||||
|
|
||||||
extern void NIO_Linux_NotifySocketClosing(int sock_fd);
|
extern void NIO_Linux_NotifySocketClosing(int sock_fd);
|
||||||
|
|
||||||
|
|
43
ntp_signd.c
43
ntp_signd.c
|
@ -34,6 +34,7 @@
|
||||||
#include "ntp_io.h"
|
#include "ntp_io.h"
|
||||||
#include "ntp_signd.h"
|
#include "ntp_signd.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
|
#include "socket.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
|
/* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
|
||||||
|
@ -90,7 +91,7 @@ static ARR_Instance queue;
|
||||||
static unsigned int queue_head;
|
static unsigned int queue_head;
|
||||||
static unsigned int queue_tail;
|
static unsigned int queue_tail;
|
||||||
|
|
||||||
#define INVALID_SOCK_FD -1
|
#define INVALID_SOCK_FD (-6)
|
||||||
|
|
||||||
/* Unix domain socket connected to ntp_signd */
|
/* Unix domain socket connected to ntp_signd */
|
||||||
static int sock_fd;
|
static int sock_fd;
|
||||||
|
@ -116,7 +117,7 @@ static void
|
||||||
close_socket(void)
|
close_socket(void)
|
||||||
{
|
{
|
||||||
SCH_RemoveFileHandler(sock_fd);
|
SCH_RemoveFileHandler(sock_fd);
|
||||||
close(sock_fd);
|
SCK_CloseSocket(sock_fd);
|
||||||
sock_fd = INVALID_SOCK_FD;
|
sock_fd = INVALID_SOCK_FD;
|
||||||
|
|
||||||
/* Empty the queue */
|
/* Empty the queue */
|
||||||
|
@ -128,35 +129,23 @@ close_socket(void)
|
||||||
static int
|
static int
|
||||||
open_socket(void)
|
open_socket(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_un s;
|
char path[1024];
|
||||||
|
|
||||||
if (sock_fd >= 0)
|
if (sock_fd != INVALID_SOCK_FD)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
if (snprintf(path, sizeof (path), "%s/socket", CNF_GetNtpSigndSocket()) >= sizeof (path)) {
|
||||||
if (sock_fd < 0) {
|
|
||||||
DEBUG_LOG("Could not open signd socket : %s", strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UTI_FdSetCloexec(sock_fd);
|
|
||||||
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, NULL);
|
|
||||||
|
|
||||||
s.sun_family = AF_UNIX;
|
|
||||||
if (snprintf(s.sun_path, sizeof (s.sun_path), "%s/socket",
|
|
||||||
CNF_GetNtpSigndSocket()) >= sizeof (s.sun_path)) {
|
|
||||||
DEBUG_LOG("signd socket path too long");
|
DEBUG_LOG("signd socket path too long");
|
||||||
close_socket();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sock_fd, (struct sockaddr *)&s, sizeof (s)) < 0) {
|
sock_fd = SCK_OpenUnixStreamSocket(path, NULL, 0);
|
||||||
DEBUG_LOG("Could not connect to signd : %s", strerror(errno));
|
if (sock_fd < 0) {
|
||||||
close_socket();
|
sock_fd = INVALID_SOCK_FD;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Connected to signd");
|
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, NULL);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -218,16 +207,14 @@ read_write_socket(int sock_fd, int event, void *anything)
|
||||||
if (!inst->sent)
|
if (!inst->sent)
|
||||||
SCH_GetLastEventTime(NULL, NULL, &inst->request_ts);
|
SCH_GetLastEventTime(NULL, NULL, &inst->request_ts);
|
||||||
|
|
||||||
s = send(sock_fd, (char *)&inst->request + inst->sent,
|
s = SCK_Send(sock_fd, (char *)&inst->request + inst->sent,
|
||||||
inst->request_length - inst->sent, 0);
|
inst->request_length - inst->sent, 0);
|
||||||
|
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
DEBUG_LOG("signd socket error: %s", strerror(errno));
|
|
||||||
close_socket();
|
close_socket();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Sent %d bytes to signd", s);
|
|
||||||
inst->sent += s;
|
inst->sent += s;
|
||||||
|
|
||||||
/* Try again later if the request is not complete yet */
|
/* Try again later if the request is not complete yet */
|
||||||
|
@ -246,20 +233,14 @@ read_write_socket(int sock_fd, int event, void *anything)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(inst->received < sizeof (inst->response));
|
assert(inst->received < sizeof (inst->response));
|
||||||
s = recv(sock_fd, (char *)&inst->response + inst->received,
|
s = SCK_Receive(sock_fd, (char *)&inst->response + inst->received,
|
||||||
sizeof (inst->response) - inst->received, 0);
|
sizeof (inst->response) - inst->received, 0);
|
||||||
|
|
||||||
if (s <= 0) {
|
if (s <= 0) {
|
||||||
if (s < 0)
|
|
||||||
DEBUG_LOG("signd socket error: %s", strerror(errno));
|
|
||||||
else
|
|
||||||
DEBUG_LOG("signd socket closed");
|
|
||||||
|
|
||||||
close_socket();
|
close_socket();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Received %d bytes from signd", s);
|
|
||||||
inst->received += s;
|
inst->received += s;
|
||||||
|
|
||||||
if (inst->received < sizeof (inst->response.length))
|
if (inst->received < sizeof (inst->response.length))
|
||||||
|
|
|
@ -27,8 +27,10 @@ acquisitionport 123"; do
|
||||||
if check_config_h 'FEAT_DEBUG 1'; then
|
if check_config_h 'FEAT_DEBUG 1'; then
|
||||||
check_log_messages "HW clock samples" 190 200 || test_fail
|
check_log_messages "HW clock samples" 190 200 || test_fail
|
||||||
check_log_messages "HW clock reset" 0 0 || test_fail
|
check_log_messages "HW clock reset" 0 0 || test_fail
|
||||||
check_log_messages "Received.*tss=1" 1 1 || test_fail
|
check_log_messages "Received message.*tss=KH" 195 200 || test_fail
|
||||||
check_log_messages "Received.*tss=2" 390 400 || test_fail
|
check_log_messages "Received error.*message.*tss=KH" 195 200 || test_fail
|
||||||
|
check_log_messages "Updated RX timestamp.*tss=1" 1 1 || test_fail
|
||||||
|
check_log_messages "Updated RX timestamp.*tss=2" 195 200 || test_fail
|
||||||
check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail
|
check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail
|
||||||
check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail
|
check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in a new issue