This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / sendmail / src / mci.c
CommitLineData
6f14531a
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static char sccsid[] = "@(#)mci.c 8.1 (Berkeley) 6/7/93";
37#endif /* not lint */
38
39#include "sendmail.h"
40
41/*
42** Mail Connection Information (MCI) Caching Module.
43**
44** There are actually two separate things cached. The first is
45** the set of all open connections -- these are stored in a
46** (small) list. The second is stored in the symbol table; it
47** has the overall status for all hosts, whether or not there
48** is a connection open currently.
49**
50** There should never be too many connections open (since this
51** could flood the socket table), nor should a connection be
52** allowed to sit idly for too long.
53**
54** MaxMciCache is the maximum number of open connections that
55** will be supported.
56**
57** MciCacheTimeout is the time (in seconds) that a connection
58** is permitted to survive without activity.
59**
60** We actually try any cached connections by sending a NOOP
61** before we use them; if the NOOP fails we close down the
62** connection and reopen it. Note that this means that a
63** server SMTP that doesn't support NOOP will hose the
64** algorithm -- but that doesn't seem too likely.
65*/
66
67MCI **MciCache; /* the open connection cache */
68\f/*
69** MCI_CACHE -- enter a connection structure into the open connection cache
70**
71** This may cause something else to be flushed.
72**
73** Parameters:
74** mci -- the connection to cache.
75**
76** Returns:
77** none.
78*/
79
80mci_cache(mci)
81 register MCI *mci;
82{
83 register MCI **mcislot;
84 extern MCI **mci_scan();
85
86 if (MaxMciCache <= 0)
87 {
88 /* we don't support caching */
89 return;
90 }
91
92 /*
93 ** Find the best slot. This may cause expired connections
94 ** to be closed.
95 */
96
97 mcislot = mci_scan(mci);
98
99 /* if this is already cached, we are done */
100 if (bitset(MCIF_CACHED, mci->mci_flags))
101 return;
102
103 /* otherwise we may have to clear the slot */
104 if (*mcislot != NULL)
105 mci_uncache(mcislot, TRUE);
106
107 *mcislot = mci;
108 mci->mci_flags |= MCIF_CACHED;
109}
110\f/*
111** MCI_SCAN -- scan the cache, flush junk, and return best slot
112**
113** Parameters:
114** savemci -- never flush this one. Can be null.
115**
116** Returns:
117** The LRU (or empty) slot.
118*/
119
120MCI **
121mci_scan(savemci)
122 MCI *savemci;
123{
124 time_t now;
125 register MCI **bestmci;
126 register MCI *mci;
127 register int i;
128
129 if (MciCache == NULL)
130 {
131 /* first call */
132 MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache);
133 bzero((char *) MciCache, MaxMciCache * sizeof *MciCache);
134 return (&MciCache[0]);
135 }
136
137 now = curtime();
138 bestmci = &MciCache[0];
139 for (i = 0; i < MaxMciCache; i++)
140 {
141 mci = MciCache[i];
142 if (mci == NULL || mci->mci_state == MCIS_CLOSED)
143 {
144 bestmci = &MciCache[i];
145 continue;
146 }
147 if (mci->mci_lastuse + MciCacheTimeout < now && mci != savemci)
148 {
149 /* connection idle too long -- close it */
150 bestmci = &MciCache[i];
151 mci_uncache(bestmci, TRUE);
152 continue;
153 }
154 if (*bestmci == NULL)
155 continue;
156 if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
157 bestmci = &MciCache[i];
158 }
159 return bestmci;
160}
161\f/*
162** MCI_UNCACHE -- remove a connection from a slot.
163**
164** May close a connection.
165**
166** Parameters:
167** mcislot -- the slot to empty.
168** doquit -- if TRUE, send QUIT protocol on this connection.
169** if FALSE, we are assumed to be in a forked child;
170** all we want to do is close the file(s).
171**
172** Returns:
173** none.
174*/
175
176mci_uncache(mcislot, doquit)
177 register MCI **mcislot;
178 bool doquit;
179{
180 register MCI *mci;
181 extern ENVELOPE BlankEnvelope;
182
183 mci = *mcislot;
184 if (mci == NULL)
185 return;
186 *mcislot = NULL;
187
188 if (doquit)
189 {
190 message("Closing connection to %s", mci->mci_host);
191
192 mci->mci_flags &= ~MCIF_CACHED;
193
194 /* only uses the envelope to flush the transcript file */
195 if (mci->mci_state != MCIS_CLOSED)
196 smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
197#ifdef XLA
198 xla_host_end(mci->mci_host);
199#endif
200 }
201 else
202 {
203 if (mci->mci_in != NULL)
204 xfclose(mci->mci_in, "mci_uncache", "mci_in");
205 if (mci->mci_out != NULL)
206 xfclose(mci->mci_out, "mci_uncache", "mci_out");
207 mci->mci_in = mci->mci_out = NULL;
208 mci->mci_state = MCIS_CLOSED;
209 mci->mci_exitstat = EX_OK;
210 mci->mci_errno = 0;
211 mci->mci_flags = 0;
212 }
213}
214\f/*
215** MCI_FLUSH -- flush the entire cache
216**
217** Parameters:
218** doquit -- if TRUE, send QUIT protocol.
219** if FALSE, just close the connection.
220** allbut -- but leave this one open.
221**
222** Returns:
223** none.
224*/
225
226mci_flush(doquit, allbut)
227 bool doquit;
228 MCI *allbut;
229{
230 register int i;
231
232 if (MciCache == NULL)
233 return;
234
235 for (i = 0; i < MaxMciCache; i++)
236 if (allbut != MciCache[i])
237 mci_uncache(&MciCache[i], doquit);
238}
239\f/*
240** MCI_GET -- get information about a particular host
241*/
242
243MCI *
244mci_get(host, m)
245 char *host;
246 MAILER *m;
247{
248 register MCI *mci;
249 register STAB *s;
250
251#ifdef DAEMON
252 extern SOCKADDR CurHostAddr;
253
254 /* clear CurHostAddr so we don't get a bogus address with this name */
255 bzero(&CurHostAddr, sizeof CurHostAddr);
256#endif DAEMON
257
258 s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
259 mci = &s->s_mci;
260 mci->mci_host = s->s_name;
261
262 if (tTd(42, 2))
263 {
264 printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n",
265 host, m->m_name, mci->mci_state, mci->mci_flags,
266 mci->mci_exitstat, mci->mci_errno);
267 }
268
269 if (mci->mci_state == MCIS_OPEN)
270 {
271 /* poke the connection to see if it's still alive */
272 smtpprobe(mci);
273
274 /* reset the stored state in the event of a timeout */
275 if (mci->mci_state != MCIS_OPEN)
276 {
277 mci->mci_errno = 0;
278 mci->mci_exitstat = EX_OK;
279 mci->mci_state = MCIS_CLOSED;
280 }
281 }
282
283 return mci;
284}
285\f/*
286** MCI_DUMP -- dump the contents of an MCI structure.
287**
288** Parameters:
289** mci -- the MCI structure to dump.
290**
291** Returns:
292** none.
293**
294** Side Effects:
295** none.
296*/
297
298mci_dump(mci)
299 register MCI *mci;
300{
301 extern char *ctime();
302
303 printf("MCI@%x: ", mci);
304 if (mci == NULL)
305 {
306 printf("NULL\n");
307 return;
308 }
309 printf("flags=%o, errno=%d, exitstat=%d, state=%d, pid=%d, maxsize=%ld\n",
310 mci->mci_flags, mci->mci_errno, mci->mci_exitstat,
311 mci->mci_state, mci->mci_pid, mci->mci_maxsize);
312 printf("\tphase=%s, mailer=%s,\n",
313 mci->mci_phase == NULL ? "NULL" : mci->mci_phase,
314 mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name);
315 printf("\thost=%s, lastuse=%s\n",
316 mci->mci_host == NULL ? "NULL" : mci->mci_host,
317 ctime(&mci->mci_lastuse));
318}