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