/* ================================================== */
+/* Server IPv4/IPv6 sockets */
+static int server_sock_fd4;
+static int server_sock_fd6;
+
static ADF_AuthTable access_auth_table;
/* ================================================== */
void
NCR_Initialise(void)
{
+ NTP_Remote_Address addr;
+
do_size_checks();
do_time_checks();
access_auth_table = ADF_CreateTable();
broadcasts = ARR_CreateInstance(sizeof (BroadcastDestination));
+
+ addr.ip_addr.family = IPADDR_INET4;
+ server_sock_fd4 = NIO_OpenServerSocket(&addr);
+ addr.ip_addr.family = IPADDR_INET6;
+ server_sock_fd6 = NIO_OpenServerSocket(&addr);
}
/* ================================================== */
void
NCR_Finalise(void)
{
+ unsigned int i;
+
+ if (server_sock_fd4 != INVALID_SOCK_FD)
+ NIO_CloseServerSocket(server_sock_fd4);
+ if (server_sock_fd6 != INVALID_SOCK_FD)
+ NIO_CloseServerSocket(server_sock_fd6);
+
+ for (i = 0; i < ARR_GetSize(broadcasts); i++)
+ NIO_CloseServerSocket(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->local_addr.sock_fd);
+
ARR_DestroyInstance(broadcasts);
ADF_DestroyTable(access_auth_table);
}
if (instance->opmode != MD_OFFLINE)
take_offline(instance);
+ if (instance->mode == MODE_ACTIVE)
+ NIO_CloseServerSocket(instance->local_addr.sock_fd);
+
/* This will destroy the source instance inside the
structure, which will cause reselection if this was the
synchronising source etc. */
if (inst->mode == MODE_CLIENT)
close_client_socket(inst);
- else
+ else {
+ NIO_CloseServerSocket(inst->local_addr.sock_fd);
inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
+ }
/* Update the reference ID and reset the source/sourcestats instances */
SRC_SetRefid(inst->source, UTI_IPToRefid(&remote_addr->ip_addr),
static int client_sock_fd6;
#endif
+/* Reference counters for server sockets to keep them open only when needed */
+static int server_sock_ref4;
+#ifdef FEAT_IPV6
+static int server_sock_ref6;
+#endif
+
/* Flag indicating we create a new connected client socket for each
server instead of sharing client_sock_fd4 and client_sock_fd6 */
static int separate_client_sockets;
+/* Flag indicating the server sockets are not created dynamically when needed,
+ either to have a socket for client requests when separate client sockets
+ are disabled and client port is equal to server port, or the server port is
+ disabled */
+static int permanent_server_sockets;
+
/* Flag indicating that we have been initialised */
static int initialised=0;
if (client_port < 0)
client_port = 0;
+ permanent_server_sockets = !server_port || (!separate_client_sockets &&
+ client_port == server_port);
+
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;
client_sock_fd6 = INVALID_SOCK_FD;
+ server_sock_ref6 = 0;
#endif
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
- if (server_port)
+ if (permanent_server_sockets && server_port)
server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
}
#ifdef FEAT_IPV6
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
- if (server_port)
+ if (permanent_server_sockets && server_port)
server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
}
#endif
- if ((server_port && server_sock_fd4 == INVALID_SOCK_FD
+ if ((server_port && server_sock_fd4 == INVALID_SOCK_FD &&
+ permanent_server_sockets
#ifdef FEAT_IPV6
&& server_sock_fd6 == INVALID_SOCK_FD
#endif
{
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
+ if (permanent_server_sockets)
+ return server_sock_fd4;
+ if (server_sock_fd4 == INVALID_SOCK_FD)
+ server_sock_fd4 = prepare_socket(AF_INET, CNF_GetNTPPort(), 0);
+ if (server_sock_fd4 != INVALID_SOCK_FD)
+ server_sock_ref4++;
return server_sock_fd4;
#ifdef FEAT_IPV6
case IPADDR_INET6:
+ if (permanent_server_sockets)
+ return server_sock_fd6;
+ if (server_sock_fd6 == INVALID_SOCK_FD)
+ server_sock_fd6 = prepare_socket(AF_INET6, CNF_GetNTPPort(), 0);
+ if (server_sock_fd6 != INVALID_SOCK_FD)
+ server_sock_ref6++;
return server_sock_fd6;
#endif
default:
/* ================================================== */
+void
+NIO_CloseServerSocket(int sock_fd)
+{
+ if (permanent_server_sockets || sock_fd == INVALID_SOCK_FD)
+ return;
+
+ if (sock_fd == server_sock_fd4) {
+ if (--server_sock_ref4 <= 0) {
+ close_socket(server_sock_fd4);
+ server_sock_fd4 = INVALID_SOCK_FD;
+ }
+ }
+#ifdef FEAT_IPV6
+ else if (sock_fd == server_sock_fd6) {
+ if (--server_sock_ref6 <= 0) {
+ close_socket(server_sock_fd6);
+ server_sock_fd6 = INVALID_SOCK_FD;
+ }
+ }
+#endif
+ else {
+ assert(0);
+ }
+}
+
+/* ================================================== */
+
int
NIO_IsServerSocket(int sock_fd)
{