DEVEL15-viced-cleanup-old-addresses-as-they-become-invalid-20080225

LICENSE IPL10

otherwise we can end up with stale addresses when a client uses then leaves an
address never to return


(cherry picked from commit 428cac5d6dfc287452af51c08eba0f0fca276864)
This commit is contained in:
Jeffrey Altman 2008-02-26 04:14:17 +00:00 committed by Derrick Brashear
parent c403d93b55
commit 4b5dff37e0

View File

@ -1440,12 +1440,17 @@ h_GetHost_r(struct rx_connection *tcon)
char hoststr[16], hoststr2[16]; char hoststr[16], hoststr2[16];
Capabilities caps; Capabilities caps;
struct rx_connection *cb_conn = NULL; struct rx_connection *cb_conn = NULL;
struct rx_connection *cb_in = NULL;
caps.Capabilities_val = NULL; caps.Capabilities_val = NULL;
haddr = rxr_HostOf(tcon); haddr = rxr_HostOf(tcon);
hport = rxr_PortOf(tcon); hport = rxr_PortOf(tcon);
retry: retry:
if (cb_in) {
rx_DestroyConnection(cb_in);
cb_in = NULL;
}
if (caps.Capabilities_val) if (caps.Capabilities_val)
free(caps.Capabilities_val); free(caps.Capabilities_val);
caps.Capabilities_val = NULL; caps.Capabilities_val = NULL;
@ -1480,13 +1485,45 @@ h_GetHost_r(struct rx_connection *tcon)
} }
host->hostFlags |= HWHO_INPROGRESS; host->hostFlags |= HWHO_INPROGRESS;
host->hostFlags &= ~ALTADDR; host->hostFlags &= ~ALTADDR;
/* We received a new connection from an IP address/port
* that is associated with 'host' but the address/port of
* the callback connection does not have to match it.
* If there is a match, we can use the existing callback
* connection to verify the UUID. If they do not match
* we need to use a new callback connection to verify the
* UUID of the incoming caller and perhaps use the old
* callback connection to verify that the old address/port
* is still valid.
*/
cb_conn = host->callback_rxcon; cb_conn = host->callback_rxcon;
rx_GetConnection(cb_conn); rx_GetConnection(cb_conn);
H_UNLOCK; H_UNLOCK;
code = if (haddr == host->host && hport == host->port) {
RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps); /* The existing callback connection matches the
if (code == RXGEN_OPCODE) * incoming connection so just use it.
code = RXAFSCB_WhoAreYou(cb_conn, &interf); */
code =
RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
if (code == RXGEN_OPCODE)
code = RXAFSCB_WhoAreYou(cb_conn, &interf);
} else {
/* We do not have a match. Create a new connection
* for the new addr/port and use multi_Rx to probe
* both of them simultaneously.
*/
if (!sc)
sc = rxnull_NewClientSecurityObject();
cb_in = rx_NewConnection(haddr, hport, 1, sc, 0);
rx_SetConnDeadTime(cb_in, 50);
rx_SetConnHardDeadTime(cb_in, AFS_HARDDEADTIME);
code =
RXAFSCB_TellMeAboutYourself(cb_in, &interf, &caps);
if (code == RXGEN_OPCODE)
code = RXAFSCB_WhoAreYou(cb_in, &interf);
}
rx_PutConnection(cb_conn); rx_PutConnection(cb_conn);
cb_conn=NULL; cb_conn=NULL;
H_LOCK; H_LOCK;
@ -1499,23 +1536,39 @@ h_GetHost_r(struct rx_connection *tcon)
} }
identP->valid = 0; identP->valid = 0;
rx_SetSpecific(tcon, rxcon_ident_key, identP); rx_SetSpecific(tcon, rxcon_ident_key, identP);
/* The host on this connection was unable to respond to if (cb_in == NULL) {
* the WhoAreYou. We will treat this as a new connection /* The host on this connection was unable to respond to
* from the existing host. The worst that can happen is * the WhoAreYou. We will treat this as a new connection
* that we maintain some extra callback state information */ * from the existing host. The worst that can happen is
if (host->interface) { * that we maintain some extra callback state information */
ViceLog(0, if (host->interface) {
("Host %x (%s:%d) used to support WhoAreYou, deleting.\n", ViceLog(0,
host, ("Host %x (%s:%d) used to support WhoAreYou, deleting.\n",
afs_inet_ntoa_r(host->host, hoststr), host,
ntohs(host->port))); afs_inet_ntoa_r(host->host, hoststr),
host->hostFlags |= HOSTDELETED; ntohs(host->port)));
host->hostFlags &= ~HWHO_INPROGRESS; host->hostFlags |= HOSTDELETED;
h_Unlock_r(host); host->hostFlags &= ~HWHO_INPROGRESS;
h_Unlock_r(host);
if (!held)
h_Release_r(host);
host = NULL;
goto retry;
}
} else {
/* The incoming connection does not support WhoAreYou but
* the original one might have. Use removeAddress_r() to
* remove this addr/port from the host that was found.
* If there are no more addresses left for the host it
* will be deleted. Then we retry.
*/
removeAddress_r(host, haddr, hport);
host->hostFlags &= ~HWHO_INPROGRESS;
h_Unlock_r(host);
if (!held) if (!held)
h_Release_r(host); h_Release_r(host);
host = NULL; host = NULL;
goto retry; goto retry;
} }
} else if (code == 0) { } else if (code == 0) {
interfValid = 1; interfValid = 1;
@ -1532,24 +1585,102 @@ h_GetHost_r(struct rx_connection *tcon)
* then this is not the same host as before. */ * then this is not the same host as before. */
if (!host->interface if (!host->interface
|| !afs_uuid_equal(&interf.uuid, &host->interface->uuid)) { || !afs_uuid_equal(&interf.uuid, &host->interface->uuid)) {
ViceLog(25, if (cb_in) {
("Uuid doesn't match host %x (%s:%d).\n", ViceLog(25,
host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port))); ("Uuid doesn't match connection (%s:%d).\n",
afs_inet_ntoa_r(haddr, hoststr), ntohs(hport)));
removeAddress_r(host, host->host, host->port);
removeAddress_r(host, haddr, hport);
} else {
ViceLog(25,
("Uuid doesn't match host %x (%s:%d).\n",
host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
removeAddress_r(host, host->host, host->port);
}
host->hostFlags &= ~HWHO_INPROGRESS; host->hostFlags &= ~HWHO_INPROGRESS;
h_Unlock_r(host); h_Unlock_r(host);
if (!held) if (!held)
h_Release_r(host); h_Release_r(host);
host = NULL; host = NULL;
goto retry; goto retry;
} else if (cb_in) {
/* the UUID matched the client at the incoming addr/port
* but this is not the address of the active callback
* connection. Try that connection and see if the client
* is still there and if the reported UUID is the same.
*/
int code2;
afsUUID uuid = host->interface->uuid;
cb_conn = host->callback_rxcon;
rx_GetConnection(cb_conn);
rx_SetConnDeadTime(cb_conn, 2);
rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
H_UNLOCK;
code2 = RXAFSCB_ProbeUuid(cb_conn, &uuid);
H_LOCK;
rx_SetConnDeadTime(cb_conn, 50);
rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
rx_PutConnection(cb_conn);
cb_conn=NULL;
if (code2) {
/* The primary address is either not responding or
* is not the client we are looking for. Need to
* remove the primary address and add swap in the new
* callback connection, and destroy the old one.
*/
struct rx_connection *rxconn;
ViceLog(0,("CB: ProbeUuid for host %x (%s:%d) failed %d\n",
host,
afs_inet_ntoa_r(host->host, hoststr),
ntohs(host->port),code2));
removeInterfaceAddr_r(host, host->host, host->port);
addInterfaceAddr_r(host, haddr, hport);
host->host = haddr;
host->port = hport;
rxconn = host->callback_rxcon;
host->callback_rxcon = cb_in;
cb_in = NULL;
if (rxconn) {
struct client *client;
/*
* If rx_DestroyConnection calls h_FreeConnection we will
* deadlock on the host_glock_mutex. Work around the problem
* by unhooking the client from the connection before
* destroying the connection.
*/
client = rx_GetSpecific(rxconn, rxcon_client_key);
rx_SetSpecific(rxconn, rxcon_client_key, (void *)0);
rx_DestroyConnection(rxconn);
}
}
} }
} else { } else {
ViceLog(0, if (cb_in) {
("CB: WhoAreYou failed for host %x (%s:%d), error %d\n", /* A callback to the incoming connection address is failing.
host, afs_inet_ntoa_r(host->host, hoststr), * Assume that the addr/port is no longer associated with the host
ntohs(host->port), code)); * returned by h_Lookup_r.
host->hostFlags |= VENUSDOWN; */
ViceLog(0,
("CB: WhoAreYou failed for connection (%s:%d) , error %d\n",
afs_inet_ntoa_r(haddr, hoststr), ntohs(hport), code));
removeAddress_r(host, haddr, hport);
host->hostFlags &= ~HWHO_INPROGRESS;
h_Unlock_r(host);
if (!held)
h_Release_r(host);
host = NULL;
rx_DestroyConnection(cb_in);
return 0;
} else {
ViceLog(0,
("CB: WhoAreYou failed for host %x (%s:%d), error %d\n",
host, afs_inet_ntoa_r(host->host, hoststr),
ntohs(host->port), code));
host->hostFlags |= VENUSDOWN;
}
} }
if (caps.Capabilities_val if (caps.Capabilities_val
&& (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS)) && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))