xref: /csrg-svn/usr.sbin/sendmail/src/mci.c (revision 54967)
154963Seric /*
254963Seric  * Copyright (c) 1983 Eric P. Allman
354963Seric  * Copyright (c) 1988 Regents of the University of California.
454963Seric  * All rights reserved.
554963Seric  *
654963Seric  * %sccs.include.redist.c%
754963Seric  */
854963Seric 
954963Seric #ifndef lint
10*54967Seric static char sccsid[] = "@(#)mci.c	5.2 (Berkeley) 07/11/92";
1154963Seric #endif /* not lint */
1254963Seric 
1354963Seric #include "sendmail.h"
1454963Seric 
1554963Seric /*
16*54967Seric **  Mail Connection Information (MCI) Caching Module.
17*54967Seric **
18*54967Seric **	There are actually two separate things cached.  The first is
19*54967Seric **	the set of all open connections -- these are stored in a
20*54967Seric **	(small) list.  The second is stored in the symbol table; it
21*54967Seric **	has the overall status for all hosts, whether or not there
22*54967Seric **	is a connection open currently.
23*54967Seric **
24*54967Seric **	There should never be too many connections open (since this
25*54967Seric **	could flood the socket table), nor should a connection be
26*54967Seric **	allowed to sit idly for too long.
27*54967Seric **
28*54967Seric **	MaxMciCache is the maximum number of open connections that
29*54967Seric **	will be supported.
30*54967Seric **
31*54967Seric **	MciCacheTimeout is the time (in seconds) that a connection
32*54967Seric **	is permitted to survive without activity.
33*54967Seric **
34*54967Seric **	We actually try any cached connections by sending a NOOP
35*54967Seric **	before we use them; if the NOOP fails we close down the
36*54967Seric **	connection and reopen it.  Note that this means that a
37*54967Seric **	server SMTP that doesn't support NOOP will hose the
38*54967Seric **	algorithm -- but that doesn't seem too likely.
39*54967Seric */
40*54967Seric 
41*54967Seric MCI	**MciCache;		/* the open connection cache */
42*54967Seric /*
4354963Seric **  MCI_CACHE -- enter a connection structure into the open connection cache
4454963Seric **
4554963Seric **	This may cause something else to be flushed.
4654963Seric **
4754963Seric **	Parameters:
4854963Seric **		mci -- the connection to cache.
4954963Seric **
5054963Seric **	Returns:
5154963Seric **		none.
5254963Seric */
5354963Seric 
5454963Seric mci_cache(mci)
55*54967Seric 	register MCI *mci;
5654963Seric {
57*54967Seric 	register MCI **mcislot;
58*54967Seric 	extern MCI **mci_scan();
5954963Seric 
6054963Seric 	if (MaxMciCache <= 0)
6154963Seric 	{
6254963Seric 		/* we don't support caching */
6354963Seric 		return;
6454963Seric 	}
6554963Seric 
6654963Seric 	/*
6754963Seric 	**  Find the best slot.  This may cause expired connections
6854963Seric 	**  to be closed.
6954963Seric 	*/
7054963Seric 
7154963Seric 	mcislot = mci_scan(mci);
7254963Seric 
7354963Seric 	/* if this is already cached, we are done */
7454963Seric 	if (bitset(MCIF_CACHED, mci->mci_flags))
7554963Seric 		return;
7654963Seric 
7754963Seric 	/* otherwise we may have to clear the slot */
7854963Seric 	if (*mcislot != NULL)
7954963Seric 		mci_uncache(mcislot);
8054963Seric 
8154963Seric 	*mcislot = mci;
8254963Seric 	mci->mci_flags |= MCIF_CACHED;
8354963Seric }
8454963Seric /*
8554963Seric **  MCI_SCAN -- scan the cache, flush junk, and return best slot
8654963Seric **
8754963Seric **	Parameters:
8854963Seric **		savemci -- never flush this one.  Can be null.
8954963Seric **
9054963Seric **	Returns:
9154963Seric **		The LRU (or empty) slot.
9254963Seric */
9354963Seric 
94*54967Seric MCI **
9554963Seric mci_scan(savemci)
96*54967Seric 	MCI *savemci;
9754963Seric {
9854963Seric 	time_t now;
99*54967Seric 	register MCI **bestmci;
100*54967Seric 	register MCI *mci;
10154963Seric 	register int i;
10254963Seric 
10354963Seric 	if (MciCache == NULL)
10454963Seric 	{
10554963Seric 		/* first call */
106*54967Seric 		MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache);
10754963Seric 		return (&MciCache[0]);
10854963Seric 	}
10954963Seric 
11054963Seric 	now = curtime();
11154963Seric 	bestmci = &MciCache[0];
11254963Seric 	for (i = 0; i < MaxMciCache; i++)
11354963Seric 	{
11454963Seric 		mci = MciCache[i];
11554963Seric 		if (mci == NULL || mci->mci_state == MCIS_CLOSED)
11654963Seric 		{
11754963Seric 			bestmci = &MciCache[i];
11854963Seric 			continue;
11954963Seric 		}
12054963Seric 		if (mci->mci_lastuse + MciCacheTimeout < now && mci != savemci)
12154963Seric 		{
12254963Seric 			/* connection idle too long -- close it */
12354963Seric 			bestmci = &MciCache[i];
12454963Seric 			mci_uncache(bestmci);
12554963Seric 			continue;
12654963Seric 		}
12754963Seric 		if (*bestmci == NULL)
12854963Seric 			continue;
12954963Seric 		if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
13054963Seric 			bestmci = &MciCache[i];
13154963Seric 	}
13254963Seric 	return bestmci;
13354963Seric }
13454963Seric /*
13554963Seric **  MCI_UNCACHE -- remove a connection from a slot.
13654963Seric **
13754963Seric **	May close a connection.
13854963Seric **
13954963Seric **	Parameters:
14054963Seric **		mcislot -- the slot to empty.
14154963Seric **
14254963Seric **	Returns:
14354963Seric **		none.
14454963Seric */
14554963Seric 
14654963Seric mci_uncache(mcislot)
147*54967Seric 	register MCI **mcislot;
14854963Seric {
149*54967Seric 	register MCI *mci;
15054963Seric 	extern ENVELOPE *BlankEnvelope;
15154963Seric 
15254963Seric 	mci = *mcislot;
15354963Seric 	if (mci == NULL)
15454963Seric 		return;
15554963Seric 	*mcislot = NULL;
15654963Seric 	mci->mci_flags &= ~MCIF_CACHED;
15754963Seric 
15854963Seric 	/* only uses the envelope to flush the transcript file */
15954963Seric 	if (mci->mci_state != MCIS_CLOSED)
16054963Seric 		smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
16154963Seric }
16254963Seric /*
16354963Seric **  MCI_FLUSH -- flush the entire cache
16454963Seric */
16554963Seric 
16654963Seric mci_flush()
16754963Seric {
16854963Seric 	register int i;
16954963Seric 
17054963Seric 	if (MciCache == NULL)
17154963Seric 		return;
17254963Seric 
17354963Seric 	for (i = 0; i < MaxMciCache; i++)
17454963Seric 		mci_uncache(&MciCache[i]);
17554963Seric }
17654963Seric /*
17754963Seric **  MCI_GET -- get information about a particular host
17854963Seric */
17954963Seric 
180*54967Seric MCI *
18154963Seric mci_get(host, m)
18254963Seric 	char *host;
18354963Seric 	MAILER *m;
18454963Seric {
185*54967Seric 	register MCI *mci;
186*54967Seric 
187*54967Seric 	mci = &(stab(host, ST_MCI + m->m_mno, ST_ENTER))->s_mci;
188*54967Seric 
189*54967Seric 	if (tTd(42, 2))
190*54967Seric 	{
191*54967Seric 		printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n",
192*54967Seric 			host, m->m_name, mci->mci_state, mci->mci_flags,
193*54967Seric 			mci->mci_exitstat, mci->mci_errno);
194*54967Seric 	}
195*54967Seric 
196*54967Seric 	/* try poking this to see if it is still usable */
197*54967Seric 	switch (mci->mci_state)
198*54967Seric 	{
199*54967Seric 	  case MCIS_OPEN:
200*54967Seric 		smtpnoop(mci);
201*54967Seric 		break;
202*54967Seric 	}
203*54967Seric 
204*54967Seric 	return mci;
20554963Seric }
206