1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)mci.c 5.4 (Berkeley) 07/20/92"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 15 /* 16 ** Mail Connection Information (MCI) Caching Module. 17 ** 18 ** There are actually two separate things cached. The first is 19 ** the set of all open connections -- these are stored in a 20 ** (small) list. The second is stored in the symbol table; it 21 ** has the overall status for all hosts, whether or not there 22 ** is a connection open currently. 23 ** 24 ** There should never be too many connections open (since this 25 ** could flood the socket table), nor should a connection be 26 ** allowed to sit idly for too long. 27 ** 28 ** MaxMciCache is the maximum number of open connections that 29 ** will be supported. 30 ** 31 ** MciCacheTimeout is the time (in seconds) that a connection 32 ** is permitted to survive without activity. 33 ** 34 ** We actually try any cached connections by sending a NOOP 35 ** before we use them; if the NOOP fails we close down the 36 ** connection and reopen it. Note that this means that a 37 ** server SMTP that doesn't support NOOP will hose the 38 ** algorithm -- but that doesn't seem too likely. 39 */ 40 41 MCI **MciCache; /* the open connection cache */ 42 /* 43 ** MCI_CACHE -- enter a connection structure into the open connection cache 44 ** 45 ** This may cause something else to be flushed. 46 ** 47 ** Parameters: 48 ** mci -- the connection to cache. 49 ** 50 ** Returns: 51 ** none. 52 */ 53 54 mci_cache(mci) 55 register MCI *mci; 56 { 57 register MCI **mcislot; 58 extern MCI **mci_scan(); 59 60 if (MaxMciCache <= 0) 61 { 62 /* we don't support caching */ 63 return; 64 } 65 66 /* 67 ** Find the best slot. This may cause expired connections 68 ** to be closed. 69 */ 70 71 mcislot = mci_scan(mci); 72 73 /* if this is already cached, we are done */ 74 if (bitset(MCIF_CACHED, mci->mci_flags)) 75 return; 76 77 /* otherwise we may have to clear the slot */ 78 if (*mcislot != NULL) 79 mci_uncache(mcislot); 80 81 *mcislot = mci; 82 mci->mci_flags |= MCIF_CACHED; 83 } 84 /* 85 ** MCI_SCAN -- scan the cache, flush junk, and return best slot 86 ** 87 ** Parameters: 88 ** savemci -- never flush this one. Can be null. 89 ** 90 ** Returns: 91 ** The LRU (or empty) slot. 92 */ 93 94 MCI ** 95 mci_scan(savemci) 96 MCI *savemci; 97 { 98 time_t now; 99 register MCI **bestmci; 100 register MCI *mci; 101 register int i; 102 103 if (MciCache == NULL) 104 { 105 /* first call */ 106 MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache); 107 return (&MciCache[0]); 108 } 109 110 now = curtime(); 111 bestmci = &MciCache[0]; 112 for (i = 0; i < MaxMciCache; i++) 113 { 114 mci = MciCache[i]; 115 if (mci == NULL || mci->mci_state == MCIS_CLOSED) 116 { 117 bestmci = &MciCache[i]; 118 continue; 119 } 120 if (mci->mci_lastuse + MciCacheTimeout < now && mci != savemci) 121 { 122 /* connection idle too long -- close it */ 123 bestmci = &MciCache[i]; 124 mci_uncache(bestmci); 125 continue; 126 } 127 if (*bestmci == NULL) 128 continue; 129 if (mci->mci_lastuse < (*bestmci)->mci_lastuse) 130 bestmci = &MciCache[i]; 131 } 132 return bestmci; 133 } 134 /* 135 ** MCI_UNCACHE -- remove a connection from a slot. 136 ** 137 ** May close a connection. 138 ** 139 ** Parameters: 140 ** mcislot -- the slot to empty. 141 ** 142 ** Returns: 143 ** none. 144 */ 145 146 mci_uncache(mcislot) 147 register MCI **mcislot; 148 { 149 register MCI *mci; 150 extern ENVELOPE BlankEnvelope; 151 152 mci = *mcislot; 153 if (mci == NULL) 154 return; 155 *mcislot = NULL; 156 mci->mci_flags &= ~MCIF_CACHED; 157 158 message(Arpa_Info, "Closing connection to %s", mci->mci_host); 159 160 /* only uses the envelope to flush the transcript file */ 161 if (mci->mci_state != MCIS_CLOSED) 162 smtpquit(mci->mci_mailer, mci, &BlankEnvelope); 163 } 164 /* 165 ** MCI_FLUSH -- flush the entire cache 166 */ 167 168 mci_flush() 169 { 170 register int i; 171 172 if (MciCache == NULL) 173 return; 174 175 for (i = 0; i < MaxMciCache; i++) 176 mci_uncache(&MciCache[i]); 177 } 178 /* 179 ** MCI_GET -- get information about a particular host 180 */ 181 182 MCI * 183 mci_get(host, m) 184 char *host; 185 MAILER *m; 186 { 187 register MCI *mci; 188 register STAB *s; 189 190 s = stab(host, ST_MCI + m->m_mno, ST_ENTER); 191 mci = &s->s_mci; 192 mci->mci_host = s->s_name; 193 194 if (tTd(42, 2)) 195 { 196 printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n", 197 host, m->m_name, mci->mci_state, mci->mci_flags, 198 mci->mci_exitstat, mci->mci_errno); 199 } 200 201 /* try poking this to see if it is still usable */ 202 switch (mci->mci_state) 203 { 204 case MCIS_OPEN: 205 smtpnoop(mci); 206 break; 207 } 208 209 return mci; 210 } 211