#endif /* KERNEL */
#include <opr/queue.h>
+#include <hcrypto/rand.h>
#include "rx.h"
#include "rx_clock.h"
static void rxi_CancelKeepAliveEvent(struct rx_call *call);
static void rxi_CancelDelayedAbortEvent(struct rx_call *call);
static void rxi_CancelGrowMTUEvent(struct rx_call *call);
+static void update_nextCid(void);
#ifdef RX_ENABLE_LOCKS
struct rx_tq_debug {
static unsigned int rxi_rpc_process_stat_cnt;
-/*
- * rxi_busyChannelError is a boolean. It indicates whether or not RX_CALL_BUSY
- * errors should be reported to the application when a call channel appears busy
- * (inferred from the receipt of RX_PACKET_TYPE_BUSY packets on the channel),
- * and there are other call channels in the connection that are not busy.
- * If 0, we do not return errors upon receiving busy packets; we just keep
- * trying on the same call channel until we hit a timeout.
- */
-static afs_int32 rxi_busyChannelError = 0;
-
rx_atomic_t rx_nWaiting = RX_ATOMIC_INIT(0);
rx_atomic_t rx_nWaited = RX_ATOMIC_INIT(0);
extern afs_kmutex_t rx_refcnt_mutex;
extern afs_kmutex_t des_init_mutex;
extern afs_kmutex_t des_random_mutex;
+#ifndef KERNEL
extern afs_kmutex_t rx_clock_mutex;
extern afs_kmutex_t rxi_connCacheMutex;
extern afs_kmutex_t event_handler_mutex;
extern afs_kcondvar_t rx_event_handler_cond;
extern afs_kcondvar_t rx_listener_cond;
+#endif /* !KERNEL */
static afs_kmutex_t epoch_mutex;
static afs_kmutex_t rx_init_mutex;
static void
rxi_InitPthread(void)
{
- MUTEX_INIT(&rx_clock_mutex, "clock", MUTEX_DEFAULT, 0);
- MUTEX_INIT(&rx_stats_mutex, "stats", MUTEX_DEFAULT, 0);
- MUTEX_INIT(&rx_atomic_mutex, "atomic", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_quota_mutex, "quota", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_pthread_mutex, "pthread", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_packets_mutex, "packets", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_refcnt_mutex, "refcnts", MUTEX_DEFAULT, 0);
- MUTEX_INIT(&epoch_mutex, "epoch", MUTEX_DEFAULT, 0);
- MUTEX_INIT(&rx_init_mutex, "init", MUTEX_DEFAULT, 0);
- MUTEX_INIT(&event_handler_mutex, "event handler", MUTEX_DEFAULT, 0);
+#ifndef KERNEL
+ MUTEX_INIT(&rx_clock_mutex, "clock", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rxi_connCacheMutex, "conn cache", MUTEX_DEFAULT, 0);
+ MUTEX_INIT(&event_handler_mutex, "event handler", MUTEX_DEFAULT, 0);
MUTEX_INIT(&listener_mutex, "listener", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_if_init_mutex, "if init", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_if_mutex, "if", MUTEX_DEFAULT, 0);
+#endif
+ MUTEX_INIT(&rx_stats_mutex, "stats", MUTEX_DEFAULT, 0);
+ MUTEX_INIT(&rx_atomic_mutex, "atomic", MUTEX_DEFAULT, 0);
+ MUTEX_INIT(&epoch_mutex, "epoch", MUTEX_DEFAULT, 0);
+ MUTEX_INIT(&rx_init_mutex, "init", MUTEX_DEFAULT, 0);
MUTEX_INIT(&rx_debug_mutex, "debug", MUTEX_DEFAULT, 0);
+#ifndef KERNEL
CV_INIT(&rx_event_handler_cond, "evhand", CV_DEFAULT, 0);
CV_INIT(&rx_listener_cond, "rxlisten", CV_DEFAULT, 0);
+#endif
osi_Assert(pthread_key_create(&rx_thread_id_key, NULL) == 0);
osi_Assert(pthread_key_create(&rx_ts_info_key, NULL) == 0);
MUTEX_INIT(&rx_connHashTable_lock, "rx_connHashTable_lock", MUTEX_DEFAULT,
0);
MUTEX_INIT(&rx_serverPool_lock, "rx_serverPool_lock", MUTEX_DEFAULT, 0);
+#ifndef KERNEL
MUTEX_INIT(&rxi_keyCreate_lock, "rxi_keyCreate_lock", MUTEX_DEFAULT, 0);
+#endif
#endif /* RX_ENABLE_LOCKS */
}
* tiers:
*
* rx_connHashTable_lock - synchronizes conn creation, rx_connHashTable access
+ * also protects updates to rx_nextCid
* conn_call_lock - used to synchonize rx_EndCall and rx_NewCall
* call->lock - locks call data fields.
* These are independent of each other:
#define CLEAR_CALL_QUEUE_LOCK(C)
#endif /* RX_ENABLE_LOCKS */
struct rx_serverQueueEntry *rx_waitForPacket = 0;
-struct rx_serverQueueEntry *rx_waitingForPacket = 0;
/* ------------Exported Interfaces------------- */
-/* This function allows rxkad to set the epoch to a suitably random number
- * which rx_NewConnection will use in the future. The principle purpose is to
- * get rxnull connections to use the same epoch as the rxkad connections do, at
- * least once the first rxkad connection is established. This is important now
- * that the host/port addresses aren't used in FindConnection: the uniqueness
- * of epoch/cid matters and the start time won't do. */
-
-#ifdef AFS_PTHREAD_ENV
-/*
- * This mutex protects the following global variables:
- * rx_epoch
- */
-
-#define LOCK_EPOCH MUTEX_ENTER(&epoch_mutex)
-#define UNLOCK_EPOCH MUTEX_EXIT(&epoch_mutex)
-#else
-#define LOCK_EPOCH
-#define UNLOCK_EPOCH
-#endif /* AFS_PTHREAD_ENV */
-
-void
-rx_SetEpoch(afs_uint32 epoch)
-{
- LOCK_EPOCH;
- rx_epoch = epoch;
- UNLOCK_EPOCH;
-}
-
/* Initialize rx. A port number may be mentioned, in which case this
* becomes the default port number for any service installed later.
* If 0 is provided for the port number, a random port will be chosen
* by the kernel. Whether this will ever overlap anything in
* /etc/services is anybody's guess... Returns 0 on success, -1 on
* error. */
-#ifndef AFS_NT40_ENV
+#if !(defined(AFS_NT40_ENV) || defined(RXK_UPCALL_ENV))
static
#endif
rx_atomic_t rxinit_status = RX_ATOMIC_INIT(1);
#endif
}
rx_stats.minRtt.sec = 9999999;
-#ifdef KERNEL
- rx_SetEpoch(tv.tv_sec | 0x80000000);
-#else
- rx_SetEpoch(tv.tv_sec); /* Start time of this package, rxkad
- * will provide a randomer value. */
-#endif
+ if (RAND_bytes(&rx_epoch, sizeof(rx_epoch)) != 1)
+ return -1;
+ rx_epoch = (rx_epoch & ~0x40000000) | 0x80000000;
+ if (RAND_bytes(&rx_nextCid, sizeof(rx_nextCid)) != 1)
+ return -1;
+ rx_nextCid &= RX_CIDMASK;
MUTEX_ENTER(&rx_quota_mutex);
rxi_dataQuota += rx_extraQuota; /* + extra pkts caller asked to rsrv */
MUTEX_EXIT(&rx_quota_mutex);
static_inline void
rxi_rto_cancel(struct rx_call *call)
{
- rxevent_Cancel(&call->resendEvent);
- CALL_RELE(call, RX_CALL_REFCOUNT_RESEND);
+ if (call->resendEvent != NULL) {
+ rxevent_Cancel(&call->resendEvent);
+ CALL_RELE(call, RX_CALL_REFCOUNT_RESEND);
+ }
}
/*!
}
/**
- * Enables or disables the busy call channel error (RX_CALL_BUSY).
- *
- * @param[in] onoff Non-zero to enable busy call channel errors.
- *
- * @pre Neither rx_Init nor rx_InitHost have been called yet
- */
-void
-rx_SetBusyChannelError(afs_int32 onoff)
-{
- osi_Assert(rx_atomic_test_bit(&rxinit_status, 0));
- rxi_busyChannelError = onoff ? 1 : 0;
-}
-
-/**
* Set a delayed ack event on the specified call for the given time
*
* @param[in] call - the call on which to set the event
int serviceSecurityIndex)
{
int hashindex, i;
- afs_int32 cid;
struct rx_connection *conn;
SPLVAR;
#endif
NETPRI;
MUTEX_ENTER(&rx_connHashTable_lock);
- cid = (rx_nextCid += RX_MAXCALLS);
conn->type = RX_CLIENT_CONNECTION;
- conn->cid = cid;
conn->epoch = rx_epoch;
+ conn->cid = rx_nextCid;
+ update_nextCid();
conn->peer = rxi_FindPeer(shost, sport, 1);
conn->serviceId = sservice;
conn->securityObject = securityObject;
rx_SetConnIdleDeadTime(struct rx_connection *conn, int seconds)
{
conn->idleDeadTime = seconds;
- conn->idleDeadDetection = (seconds ? 1 : 0);
rxi_CheckConnTimeouts(conn);
}
}
if (i < RX_MAXCALLS) {
conn->lastBusy[i] = 0;
- call->flags &= ~RX_CALL_PEER_BUSY;
break;
}
if (!wait)
service->minProcs = 0;
service->maxProcs = 1;
service->idleDeadTime = 60;
- service->idleDeadErr = 0;
service->connDeadTime = rx_connDeadTime;
service->executeRequestProc = serviceProc;
service->checkReach = 0;
opr_queue_Append(&rx_idleServerQueue, &sq->entry);
#ifndef AFS_AIX41_ENV
rx_waitForPacket = sq;
-#else
- rx_waitingForPacket = sq;
#endif /* AFS_AIX41_ENV */
do {
CV_WAIT(&sq->cv, &rx_serverPool_lock);
MUTEX_ENTER(&conn->conn_call_lock);
MUTEX_ENTER(&call->lock);
- if (!(call->flags & RX_CALL_PEER_BUSY)) {
+ if (!call->error) {
+ /* While there are some circumstances where a call with an error is
+ * obviously not on a "busy" channel, be conservative (clearing
+ * lastBusy is just best-effort to possibly speed up rx_NewCall).
+ * The call channel is definitely not busy if we just successfully
+ * completed a call on it. */
conn->lastBusy[call->channel] = 0;
+
+ } else if (call->error == RX_CALL_TIMEOUT) {
+ /* The call is still probably running on the server side, so try to
+ * avoid this call channel in the future. */
+ conn->lastBusy[call->channel] = clock_Sec();
}
MUTEX_ENTER(&conn->conn_data_lock);
* Map errors to the local host's errno.h format.
*/
error = ntoh_syserr_conv(error);
+
+ /* If the caller said the call failed with some error, we had better
+ * return an error code. */
+ osi_Assert(!rc || error);
return error;
}
if (peer->ifMTU < OLD_MAX_PACKET_SIZE)
peer->maxDgramPackets = 1;
/* We no longer have valid peer packet information */
- if (peer->maxPacketSize-RX_IPUDP_SIZE > peer->ifMTU)
+ if (peer->maxPacketSize + RX_HEADER_SIZE > peer->ifMTU)
peer->maxPacketSize = 0;
MUTEX_EXIT(&peer->peer_lock);
conn->nSpecific = 0;
conn->specific = NULL;
rx_SetConnDeadTime(conn, service->connDeadTime);
- conn->idleDeadTime = service->idleDeadTime;
- conn->idleDeadDetection = service->idleDeadErr ? 1 : 0;
+ rx_SetConnIdleDeadTime(conn, service->idleDeadTime);
for (i = 0; i < RX_MAXCALLS; i++) {
conn->twind[i] = rx_initSendWindow;
conn->rwind[i] = rx_initReceiveWindow;
return conn;
}
-/**
- * Timeout a call on a busy call channel if appropriate.
- *
- * @param[in] call The busy call.
- *
- * @pre 'call' is marked as busy (namely,
- * call->conn->lastBusy[call->channel] != 0)
- *
- * @pre call->lock is held
- * @pre rxi_busyChannelError is nonzero
- *
- * @note call->lock is dropped and reacquired
- */
-static void
-rxi_CheckBusy(struct rx_call *call)
-{
- struct rx_connection *conn = call->conn;
- int channel = call->channel;
- int freechannel = 0;
- int i;
-
- MUTEX_EXIT(&call->lock);
-
- MUTEX_ENTER(&conn->conn_call_lock);
-
- /* Are there any other call slots on this conn that we should try? Look for
- * slots that are empty and are either non-busy, or were marked as busy
- * longer than conn->secondsUntilDead seconds before this call started. */
-
- for (i = 0; i < RX_MAXCALLS && !freechannel; i++) {
- if (i == channel) {
- /* only look at channels that aren't us */
- continue;
- }
-
- if (conn->lastBusy[i]) {
- /* if this channel looked busy too recently, don't look at it */
- if (conn->lastBusy[i] >= call->startTime.sec) {
- continue;
- }
- if (call->startTime.sec - conn->lastBusy[i] < conn->secondsUntilDead) {
- continue;
- }
- }
-
- if (conn->call[i]) {
- struct rx_call *tcall = conn->call[i];
- MUTEX_ENTER(&tcall->lock);
- if (tcall->state == RX_STATE_DALLY) {
- freechannel = 1;
- }
- MUTEX_EXIT(&tcall->lock);
- } else {
- freechannel = 1;
- }
- }
-
- MUTEX_ENTER(&call->lock);
-
- /* Since the call->lock has been released it is possible that the call may
- * no longer be busy (the call channel cannot have been reallocated as we
- * haven't dropped the conn_call_lock) Therefore, we must confirm
- * that the call state has not changed when deciding whether or not to
- * force this application thread to retry by forcing a Timeout error. */
-
- if (freechannel && (call->flags & RX_CALL_PEER_BUSY)) {
- /* Since 'freechannel' is set, there exists another channel in this
- * rx_conn that the application thread might be able to use. We know
- * that we have the correct call since callNumber is unchanged, and we
- * know that the call is still busy. So, set the call error state to
- * rxi_busyChannelError so the application can retry the request,
- * presumably on a less-busy call channel. */
-
- rxi_CallError(call, RX_CALL_BUSY);
- }
- MUTEX_EXIT(&conn->conn_call_lock);
-}
-
/*!
* Abort the call if the server is over the busy threshold. This
* can be used without requiring a call structure be initialised,
channel = np->header.cid & RX_CHANNELMASK;
MUTEX_ENTER(&conn->conn_call_lock);
call = conn->call[channel];
+ if (np->header.type == RX_PACKET_TYPE_BUSY) {
+ conn->lastBusy[channel] = clock_Sec();
+ }
if (!call || conn->callNumber[channel] != np->header.callNumber) {
MUTEX_EXIT(&conn->conn_call_lock);
if (rx_stats_active)
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = host;
+ memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
addr.sin_len = sizeof(addr);
#endif /* AFS_OSF_ENV */
putConnection(conn);
return np; /* xmitting; drop packet */
}
- case RX_PACKET_TYPE_BUSY: {
- struct clock busyTime;
- clock_NewTime();
- clock_GetTime(&busyTime);
-
- MUTEX_EXIT(&call->lock);
-
- MUTEX_ENTER(&conn->conn_call_lock);
- MUTEX_ENTER(&call->lock);
- conn->lastBusy[call->channel] = busyTime.sec;
- call->flags |= RX_CALL_PEER_BUSY;
- MUTEX_EXIT(&call->lock);
- MUTEX_EXIT(&conn->conn_call_lock);
-
- putConnection(conn);
- return np;
- }
+ case RX_PACKET_TYPE_BUSY:
+ /* Mostly ignore BUSY packets. We will update lastReceiveTime below,
+ * so we don't think the endpoint is completely dead, but otherwise
+ * just act as if we never saw anything. If all we get are BUSY packets
+ * back, then we will eventually error out with RX_CALL_TIMEOUT if the
+ * connection is configured with idle/hard timeouts. */
+ break;
case RX_PACKET_TYPE_ACKALL:
/* All packets acknowledged, so we can drop all packets previously
* the packet will be delivered to the user before any get time is required
* (if not, then the time won't actually be re-evaluated here). */
call->lastReceiveTime = clock_Sec();
- /* we've received a legit packet, so the channel is not busy */
- call->flags &= ~RX_CALL_PEER_BUSY;
MUTEX_EXIT(&call->lock);
putConnection(conn);
return np;
* but we are clearly receiving.
*/
if (!peer->maxPacketSize)
- peer->maxPacketSize = RX_MIN_PACKET_SIZE+RX_IPUDP_SIZE;
+ peer->maxPacketSize = RX_MIN_PACKET_SIZE - RX_HEADER_SIZE;
if (pktsize > peer->maxPacketSize) {
peer->maxPacketSize = pktsize;
- if ((pktsize-RX_IPUDP_SIZE > peer->ifMTU)) {
- peer->ifMTU=pktsize-RX_IPUDP_SIZE;
+ if ((pktsize + RX_HEADER_SIZE > peer->ifMTU)) {
+ peer->ifMTU = pktsize + RX_HEADER_SIZE;
peer->natMTU = rxi_AdjustIfMTU(peer->ifMTU);
rxi_ScheduleGrowMTUEvent(call, 1);
}
if (RXS_CheckAuthentication(conn->securityObject, conn) == 0)
return np;
+ if (!conn->securityChallengeSent) {
+ /* We've never sent out a challenge for this connection, so this
+ * response cannot possibly be correct; ignore it. This can happen
+ * if we sent a challenge to the client, then we were restarted, and
+ * then the client sent us a response. If we ignore the response, the
+ * client will eventually resend a data packet, causing us to send a
+ * new challenge and the client to send a new response. */
+ return np;
+ }
+
/* Otherwise, have the security object evaluate the response packet */
error = RXS_CheckResponse(conn->securityObject, conn, np);
if (error) {
/* If the response is invalid, reset the connection, sending
- * an abort to the peer */
-#ifndef KERNEL
- rxi_Delay(1);
-#endif
+ * an abort to the peer. Send the abort with a 1 second delay,
+ * to avoid a peer hammering us by constantly recreating a
+ * connection with bad credentials. */
rxi_ConnectionError(conn, error);
MUTEX_ENTER(&conn->conn_data_lock);
- np = rxi_SendConnectionAbort(conn, np, istack, 0);
+ rxi_SendConnectionAbortLater(conn, 1000);
MUTEX_EXIT(&conn->conn_data_lock);
return np;
} else {
rxi_SendCallAbort(struct rx_call *call, struct rx_packet *packet,
int istack, int force)
{
- afs_int32 error, cerror;
+ afs_int32 error;
struct clock when, now;
if (!call->error)
return packet;
- switch (call->error) {
- case RX_CALL_IDLE:
- case RX_CALL_BUSY:
- cerror = RX_CALL_TIMEOUT;
- break;
- default:
- cerror = call->error;
- }
-
/* Clients should never delay abort messages */
if (rx_IsClientConn(call->conn))
force = 1;
- if (call->abortCode != cerror) {
- call->abortCode = cerror;
+ if (call->abortCode != call->error) {
+ call->abortCode = call->error;
call->abortCount = 0;
}
if (force || rxi_callAbortThreshhold == 0
|| call->abortCount < rxi_callAbortThreshhold) {
rxi_CancelDelayedAbortEvent(call);
- error = htonl(cerror);
+ error = htonl(call->error);
call->abortCount++;
packet =
rxi_SendSpecial(call, call->conn, packet, RX_PACKET_TYPE_ABORT,
}
call->flags = 0;
- if (!newcall && (flags & RX_CALL_PEER_BUSY)) {
- /* The call channel is still busy; resetting the call doesn't change
- * that. However, if 'newcall' is set, we are processing a call
- * structure that has either been recycled from the free list, or has
- * been newly allocated. So, RX_CALL_PEER_BUSY is not relevant if
- * 'newcall' is set, since it describes a completely different call
- * channel which we do not care about. */
- call->flags |= RX_CALL_PEER_BUSY;
- }
-
rxi_ClearReceiveQueue(call);
/* why init the queue if you just emptied it? queue_Init(&call->rq); */
int reason; Reason an acknowledge was prompted
*/
+#define RX_ZEROS 1024
+static char rx_zeros[RX_ZEROS];
+
struct rx_packet *
rxi_SendAck(struct rx_call *call,
struct rx_packet *optionalPacket, int serial, int reason,
*/
if (call->conn->peer->maxPacketSize &&
(call->conn->peer->maxPacketSize < OLD_MAX_PACKET_SIZE
- +RX_IPUDP_SIZE))
+ - RX_HEADER_SIZE))
padbytes = call->conn->peer->maxPacketSize+16;
else
padbytes = call->conn->peer->maxMTU + 128;
ap->nAcks = offset;
p->length = rx_AckDataSize(offset) + 4 * sizeof(afs_int32);
+ /* Must zero the 3 octets that rx_AckDataSize skips at the end of the
+ * ACK list.
+ */
+ rx_packetwrite(p, rx_AckDataSize(offset) - 3, 3, rx_zeros);
+
/* these are new for AFS 3.3 */
templ = rxi_AdjustMaxMTU(call->conn->peer->ifMTU, rx_maxReceiveSize);
templ = htonl(templ);
rx_packetwrite(p, rx_AckDataSize(offset) + 3 * sizeof(afs_int32),
sizeof(afs_int32), &templ);
+ p->length = rx_AckDataSize(offset) + 4 * sizeof(afs_int32);
+
p->header.serviceId = call->conn->serviceId;
p->header.cid = (call->conn->cid | call->channel);
p->header.callNumber = *call->callNumber;
p->header.epoch = call->conn->epoch;
p->header.type = RX_PACKET_TYPE_ACK;
p->header.flags = RX_SLOW_START_OK;
- if (reason == RX_ACK_PING) {
+ if (reason == RX_ACK_PING)
p->header.flags |= RX_REQUEST_ACK;
- if (padbytes) {
- p->length = padbytes +
- rx_AckDataSize(call->rwind) + 4 * sizeof(afs_int32);
- while (padbytes--)
- /* not fast but we can potentially use this if truncated
- * fragments are delivered to figure out the mtu.
- */
- rx_packetwrite(p, rx_AckDataSize(offset) + 4 *
- sizeof(afs_int32), sizeof(afs_int32),
- &padbytes);
+ while (padbytes > 0) {
+ if (padbytes > RX_ZEROS) {
+ rx_packetwrite(p, p->length, RX_ZEROS, rx_zeros);
+ p->length += RX_ZEROS;
+ padbytes -= RX_ZEROS;
+ } else {
+ rx_packetwrite(p, p->length, padbytes, rx_zeros);
+ p->length += padbytes;
+ padbytes = 0;
}
}
+
if (call->conn->type == RX_CLIENT_CONNECTION)
p->header.flags |= RX_CLIENT_INITIATED;
* processing), and for the connection (so that we can discover
* idle connections) */
conn->lastSendTime = call->lastSendTime = clock_Sec();
- /* Let a set of retransmits trigger an idle timeout */
- if (!xmit->resending)
- call->lastSendData = call->lastSendTime;
}
/* When sending packets we need to follow these rules:
rxi_CheckPeerDead(call);
- if (rxi_busyChannelError && (call->flags & RX_CALL_PEER_BUSY)) {
- rxi_CheckBusy(call);
- }
-
if (opr_queue_IsEmpty(&call->tq)) {
/* Nothing to do. This means that we've been raced, and that an
* ACK has come in between when we were triggered, and when we
(p->length <= (rx_AckDataSize(call->rwind) + 4 * sizeof(afs_int32))))
{
conn->lastSendTime = call->lastSendTime = clock_Sec();
- /* Don't count keepalive ping/acks here, so idleness can be tracked. */
- if ((p->header.type != RX_PACKET_TYPE_ACK) ||
- ((((struct rx_ackPacket *)rx_DataOf(p))->reason != RX_ACK_PING) &&
- (((struct rx_ackPacket *)rx_DataOf(p))->reason !=
- RX_ACK_PING_RESPONSE)))
- call->lastSendData = call->lastSendTime;
}
}
* number of seconds. */
if (now > (call->lastReceiveTime + deadTime)) {
if (call->state == RX_STATE_ACTIVE) {
-#ifdef AFS_ADAPT_PMTU
-# if defined(KERNEL) && defined(AFS_SUN5_ENV)
- ire_t *ire;
-# if defined(AFS_SUN510_ENV) && defined(GLOBAL_NETSTACKID)
- netstack_t *ns = netstack_find_by_stackid(GLOBAL_NETSTACKID);
- ip_stack_t *ipst = ns->netstack_ip;
-# endif
- ire = ire_cache_lookup(conn->peer->host
-# if defined(AFS_SUN510_ENV) && defined(ALL_ZONES)
- , ALL_ZONES
-# if defined(ICL_3_ARG) || defined(GLOBAL_NETSTACKID)
- , NULL
-# if defined(GLOBAL_NETSTACKID)
- , ipst
-# endif
-# endif
-# endif
- );
-
- if (ire && ire->ire_max_frag > 0)
- rxi_SetPeerMtu(NULL, conn->peer->host, 0,
- ire->ire_max_frag);
-# if defined(GLOBAL_NETSTACKID)
- netstack_rele(ns);
-# endif
-# endif
-#endif /* AFS_ADAPT_PMTU */
cerror = RX_CALL_DEAD;
goto mtuout;
} else {
* attached process can die reasonably gracefully. */
}
- if (conn->idleDeadDetection) {
- if (conn->idleDeadTime) {
- idleDeadTime = conn->idleDeadTime + fudgeFactor;
- }
-
- if (idleDeadTime) {
- /* see if we have a non-activity timeout */
- if (call->startWait && ((call->startWait + idleDeadTime) < now) &&
- (call->flags & RX_CALL_READER_WAIT)) {
- if (call->state == RX_STATE_ACTIVE) {
- cerror = RX_CALL_TIMEOUT;
- goto mtuout;
- }
- }
+ if (conn->idleDeadTime) {
+ idleDeadTime = conn->idleDeadTime + fudgeFactor;
+ }
- if (call->lastSendData && ((call->lastSendData + idleDeadTime) < now)) {
- if (call->state == RX_STATE_ACTIVE) {
- cerror = conn->service ? conn->service->idleDeadErr : RX_CALL_IDLE;
- idle_timeout = 1;
- goto mtuout;
- }
- }
- }
+ if (idleDeadTime) {
+ /* see if we have a non-activity timeout */
+ if (call->startWait && ((call->startWait + idleDeadTime) < now)) {
+ if (call->state == RX_STATE_ACTIVE) {
+ cerror = RX_CALL_TIMEOUT;
+ goto mtuout;
+ }
+ }
}
if (conn->hardDeadTime) {
call->lastReceiveTime) {
int oldMTU = conn->peer->ifMTU;
- /* if we thought we could send more, perhaps things got worse */
- if (conn->peer->maxPacketSize > conn->lastPacketSize)
- /* maxpacketsize will be cleared in rxi_SetPeerMtu */
- newmtu = MAX(conn->peer->maxPacketSize-RX_IPUDP_SIZE,
- conn->lastPacketSize-(128+RX_IPUDP_SIZE));
+ /* If we thought we could send more, perhaps things got worse.
+ * Shrink by 128 bytes and try again. */
+ if (conn->peer->maxPacketSize < conn->lastPacketSize)
+ /* maxPacketSize will be cleared in rxi_SetPeerMtu */
+ newmtu = MAX(conn->peer->maxPacketSize + RX_HEADER_SIZE,
+ conn->lastPacketSize - 128 + RX_HEADER_SIZE);
else
- newmtu = conn->lastPacketSize-(128+RX_IPUDP_SIZE);
+ newmtu = conn->lastPacketSize - 128 + RX_HEADER_SIZE;
/* minimum capped in SetPeerMtu */
rxi_SetPeerMtu(conn->peer, 0, 0, newmtu);
/* clean up */
- conn->lastPacketSize = 0;
+ conn->lastPacketSize = conn->lastPacketSizeSeq = 0;
/* needed so ResetCall doesn't clobber us. */
call->MTU = conn->peer->ifMTU;
taddr.sin_family = AF_INET;
taddr.sin_port = rx_PortOf(rx_PeerOf(conn));
taddr.sin_addr.s_addr = rx_HostOf(rx_PeerOf(conn));
+ memset(&taddr.sin_zero, 0, sizeof(taddr.sin_zero));
#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
taddr.sin_len = sizeof(struct sockaddr_in);
#endif
*/
if ((conn->peer->maxPacketSize != 0) &&
(conn->peer->natMTU < RX_MAX_PACKET_SIZE) &&
- conn->idleDeadDetection)
+ conn->idleDeadTime)
(void)rxi_SendAck(call, NULL, 0, RX_ACK_MTU, 0);
rxi_ScheduleGrowMTUEvent(call, 0);
MUTEX_EXIT(&call->lock);
}
}
+/*
+ * Increment the counter for the next connection ID, handling overflow.
+ */
+static void
+update_nextCid(void)
+{
+ /* Overflow is technically undefined behavior; avoid it. */
+ if (rx_nextCid > MAX_AFS_INT32 - (1 << RX_CIDSHIFT))
+ rx_nextCid = -1 * ((MAX_AFS_INT32 / RX_CIDSHIFT) * RX_CIDSHIFT);
+ else
+ rx_nextCid += 1 << RX_CIDSHIFT;
+}
+
static void
rxi_KeepAliveOn(struct rx_call *call)
{
rxi_ScheduleKeepAliveEvent(call);
}
-void
-rx_KeepAliveOff(struct rx_call *call)
-{
- MUTEX_ENTER(&call->lock);
- rxi_CancelKeepAliveEvent(call);
- MUTEX_EXIT(&call->lock);
-}
-
-void
-rx_KeepAliveOn(struct rx_call *call)
-{
- MUTEX_ENTER(&call->lock);
- rxi_KeepAliveOn(call);
- MUTEX_EXIT(&call->lock);
-}
-
static void
rxi_GrowMTUOn(struct rx_call *call)
{
rxi_SendSpecial((struct rx_call *)0, conn, packet,
RX_PACKET_TYPE_CHALLENGE, NULL, -1, 0);
rxi_FreePacket(packet);
+ conn->securityChallengeSent = 1;
}
clock_GetTime(&now);
when = now;
taddr.sin_family = AF_INET;
taddr.sin_port = remotePort;
taddr.sin_addr.s_addr = remoteAddr;
+ memset(&taddr.sin_zero, 0, sizeof(taddr.sin_zero));
#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
taddr.sin_len = sizeof(struct sockaddr_in);
#endif
rxi_StopListener();
#endif /* AFS_PTHREAD_ENV */
shutdown_rxevent();
- rx_SetEpoch(0);
+ rx_epoch = 0;
#ifndef AFS_PTHREAD_ENV
#ifndef AFS_USE_GETTIMEOFDAY
clock_UnInit();
"rqc=%u,%u, tqc=%u,%u, iovqc=%u,%u, "
"lstatus=%u, rstatus=%u, error=%d, timeout=%u, "
"resendEvent=%d, keepAliveEvt=%d, delayedAckEvt=%d, delayedAbortEvt=%d, abortCode=%d, abortCount=%d, "
- "lastSendTime=%u, lastRecvTime=%u, lastSendData=%u"
+ "lastSendTime=%u, lastRecvTime=%u"
#ifdef RX_ENABLE_LOCKS
", refCount=%u"
#endif
(afs_uint32)c->rqc, (afs_uint32)rqc, (afs_uint32)c->tqc, (afs_uint32)tqc, (afs_uint32)c->iovqc, (afs_uint32)iovqc,
(afs_uint32)c->localStatus, (afs_uint32)c->remoteStatus, c->error, c->timeout,
c->resendEvent?1:0, c->keepAliveEvent?1:0, c->delayedAckEvent?1:0, c->delayedAbortEvent?1:0,
- c->abortCode, c->abortCount, c->lastSendTime, c->lastReceiveTime, c->lastSendData
+ c->abortCode, c->abortCount, c->lastSendTime, c->lastReceiveTime
#ifdef RX_ENABLE_LOCKS
, (afs_uint32)c->refCount
#endif