[ntp:questions] Re: Need ntpdc command to recreate sockets

Enrique Perez-Terron enrio at online.no
Thu Jan 13 22:13:36 UTC 2005


On Thu, 2005-01-13 at 08:49, Harlan Stenn wrote:
> Enrique,
> 
> I'd love to see more folks contributing ideas and code.
> 
> Would you be willing to work with Danny on this?

Yes. Perhaps the effort will be a little intermittent, as I find time to
work with it more easily some weeks than others.

Danny Mayer suggested I add a patch to bug 51, but I understand it to
mean when I have something usable. What I have now is entirely sketchy,
and highly incomplete.

Since you have not yet seen a line of code from my hand, I include below
the diff as it is at the moment, and comment it, so you can have some
idea how I work.

All I have done so far is more like an exploration, there is little in
the way of planning and designing.

I first wrote the rescan code, calling it "reopen_sockets_perhaps()".
That name reflected the expectations I had a the time as to what was
needed.  As Danny pointed out, it is a bit more complicated than I was
imagining. 

I concluded it by calling unwritten functions interface_added(),
interface_gone(), and interface_changed(), then I went on coding
interface_changed(), only to notice that I needed to do quite a bit of
research to be able to fill in something meaningful.  

The rescan code of course is a clone of the initial scan code, with
everything else thrown out. In particular, I did not call open_socket()
in the rescan routine because it adds to the global list of open
sockets, and I do not want to mess with any global state untill I know
for sure what is needed. In interface_added() I call open_socket(), and
then I imagined a scenario where ntpd had been started before the
network was available, and we had a list of peers we had been unable to
contact, and this could be the time to try to do something about it.
Again I invented a name for the task, with the intention of filling in
more code later. That was when I began looking around to find out what
the program currently does in such a situation, and that led me to post
a couple of questions.

Writing about it, it crosses my mind that the program should process
interfaces gone and changed before interfaces added, because it will
perhaps need to take note of peers who have lost the interface they were
using, in order to have that list at hand when processing interfaces
added.  

Once again, I have not quite understood how the program deals with
interfaces, and why.  It looks like the interface (i.e. local) address
is used by the protocol, but I have not yet read the appropriate parts
of the protocol. Perhaps that is what I should do first, to put my
efforts on a sound basis. Still I would appreciate if someone could say
a word of wisdom about it.

--- ntp_io.c	2005-01-10 12:28:35.000000000 +0100
+++ qio.c	2005-01-13 12:35:34.000000000 +0100
@@ -650,6 +650,159 @@
 	return ninterfaces;
 }
 
+static void
+interface_added(struct interface *newif)
+{
+	int i;
+
+	if (ninterfaces >= MAXINTERFACES)
+		return;
+	i = ninterfaces++;
+
+	inter_list[i] = *newif;
+	
+	open_socket(&inter_list[i].sin,
+		    inter_list[i].flags & INT_BROADCAST,
+		    0, &inter_list[i], i);
+	if (inter_list[i].fd != INVALID_SOCKET)
+		msyslog(LOG_INFO, "Listening on interface %s, %s#%d",
+			inter_list[i].name,
+			stoa((&inter_list[i].sin)),
+			NTP_PORT);
+	if ((inter_list[i].flags & INT_BROADCAST) &&
+	    inter_list[i].bfd != INVALID_SOCKET)
+		msyslog(LOG_INFO, "Listening on broadcast address %s#%d",
+			stoa((&inter_list[i].bcast)),
+			NTP_PORT);
+	check_peers_for_new_interface();
+	
+	return;
+}
+
+static void
+interface_changed(struct interface *oldif, struct interface *newif)
+{
+	return;
+}
+
+static void
+interface_gone(struct interface *oldif)
+{
+	return;
+}
+
+/*
+ * recreate_sockets_perhaps - close and reopen sockets if the IP
+ *                            address of the interface has changed.
+ */
+static int
+recreate_sockets_perhaps(
+	 u_short port
+	 )
+{
+	struct sockaddr_storage resmask;
+	int i;
+	isc_mem_t *mctx = NULL;
+	isc_interfaceiter_t *iter = NULL;
+	isc_boolean_t scan_ipv4 = ISC_FALSE;
+	isc_boolean_t scan_ipv6 = ISC_FALSE;
+	isc_result_t result;
+	int idx = 0;
+
+	struct interface new_inter_list[MAXINTERFACES]; /* Interface list */
+	int new_ninterfaces;			/* Total number of interfaces */
+
+	/* Strategy: create a new temporary list of interfaces, and
+	   compare with the existing list. */
+	result = isc_interfaceiter_create(mctx, &iter);
+	if (result != ISC_R_SUCCESS)
+		return (result);
+
+	for (result = isc_interfaceiter_first(iter);
+	     result == ISC_R_SUCCESS;
+	     result = isc_interfaceiter_next(iter))
+	{
+		isc_interface_t isc_if;
+		unsigned int family; 
+
+		result = isc_interfaceiter_current(iter, &isc_if);
+		if (result != ISC_R_SUCCESS)
+			break;
+
+		/* See if we have a valid family to use */
+		family = isc_if.address.family;
+		if (family != AF_INET && family != AF_INET6)
+			continue;
+		if (scan_ipv4 == ISC_FALSE && family == AF_INET)
+			continue;
+		if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
+			continue;
+
+		/* Check to see if we are going to use the interface */
+		if (address_okay(&isc_if) == ISC_TRUE) {
+			convert_isc_if(&isc_if, &new_inter_list[idx], port);
+			new_inter_list[idx].fd = INVALID_SOCKET;
+			new_inter_list[idx].bfd = INVALID_SOCKET;
+			new_inter_list[idx].num_mcast = 0;
+			new_inter_list[idx].received = 0;
+			new_inter_list[idx].sent = 0;
+			new_inter_list[idx].notsent = 0;
+			idx++;
+		}
+	}
+	isc_interfaceiter_destroy(&iter);
+
+	new_ninterfaces = idx;
+
+	/*
+	 * Compare the interface addresses
+	 */
+	int size_found_ifs = (ninterfaces + 7)/8;
+	char *found_ifs = malloc(size_found_ifs);
+	if (!found_ifs) return(ISC_R_UNEXPECTED);
+	memset(found_ifs, 0, size_found_ifs);
+	
+	for (idx = 0; idx < new_ninterfaces; idx++) {
+		struct interface *newif = &new_inter_list[idx];
+		u_short family = newif->sin.ss_family;
+		for (i = 0; i < ninterfaces; i++) {
+			struct interface *oldif = &inter_list[i];
+			if (oldif->sin.ss_family != family)
+				continue;
+			if (0 != strncmp(oldif->name, newif->name, sizeof(newif->name)))
+				continue;
+			found_ifs[i/8] |= 1 << (i%8);
+			switch (family) {
+			case AF_INET:
+				if (0 == memcmp(&(((struct sockaddr_in*)&oldif->sin)->sin_addr),
+						&(((struct sockaddr_in*)&newif->sin)->sin_addr),
+						sizeof(struct in_addr)))
+					goto next_newif;
+			case AF_INET6:
+				if (0 == memcmp(&(((struct sockaddr_in6 *)&oldif->sin)->sin6_addr),
+						&(((struct sockaddr_in6 *)&newif->sin)->sin6_addr),
+						sizeof(struct in6_addr)))
+					goto next_newif;
+			}
+			interface_changed(newif, oldif);
+		}
+		interface_added(newif);
+	next_newif:
+	}
+
+	for (i = 0; i < ninterfaces; ++i) {
+		if (found_ifs[i/8] & (1 << (i % 8)))
+			continue;
+		if (i == wildipv4 || i == wildipv6)
+			continue;
+		interface_gone(&inter_list[i]);
+	}
+
+	free(found_ifs);
+	
+	return ninterfaces;
+}
+
 
 /*
  * set_reuseaddr() - set/clear REUSEADDR on all sockets

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <http://lists.ntp.org/pipermail/questions/attachments/20050113/20905181/attachment.pgp>


More information about the questions mailing list