SGI IRIX & ANSI C portability
[unix-history] / usr / src / usr.sbin / sendmail / src / mci.c
CommitLineData
eb980753
EA
1/*
2 * Copyright (c) 1983 Eric P. Allman
eb0bafab
KB
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
eb980753
EA
5 *
6 * %sccs.include.redist.c%
7 */
8
9#ifndef lint
e6cb9fc4 10static char sccsid[] = "@(#)mci.c 8.3 (Berkeley) %G%";
eb980753
EA
11#endif /* not lint */
12
13#include "sendmail.h"
14
15/*
f2e44ded
EA
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
41MCI **MciCache; /* the open connection cache */
42\f/*
eb980753
EA
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
54mci_cache(mci)
f2e44ded 55 register MCI *mci;
eb980753 56{
f2e44ded
EA
57 register MCI **mcislot;
58 extern MCI **mci_scan();
eb980753
EA
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)
1c7897ef 79 mci_uncache(mcislot, TRUE);
eb980753
EA
80
81 *mcislot = mci;
82 mci->mci_flags |= MCIF_CACHED;
83}
84\f/*
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
f2e44ded 94MCI **
eb980753 95mci_scan(savemci)
f2e44ded 96 MCI *savemci;
eb980753
EA
97{
98 time_t now;
f2e44ded
EA
99 register MCI **bestmci;
100 register MCI *mci;
eb980753
EA
101 register int i;
102
103 if (MciCache == NULL)
104 {
105 /* first call */
f2e44ded 106 MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache);
5031c0bb 107 bzero((char *) MciCache, MaxMciCache * sizeof *MciCache);
eb980753
EA
108 return (&MciCache[0]);
109 }
110
111 now = curtime();
112 bestmci = &MciCache[0];
113 for (i = 0; i < MaxMciCache; i++)
114 {
115 mci = MciCache[i];
116 if (mci == NULL || mci->mci_state == MCIS_CLOSED)
117 {
118 bestmci = &MciCache[i];
119 continue;
120 }
121 if (mci->mci_lastuse + MciCacheTimeout < now && mci != savemci)
122 {
123 /* connection idle too long -- close it */
124 bestmci = &MciCache[i];
1c7897ef 125 mci_uncache(bestmci, TRUE);
eb980753
EA
126 continue;
127 }
128 if (*bestmci == NULL)
129 continue;
130 if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
131 bestmci = &MciCache[i];
132 }
133 return bestmci;
134}
135\f/*
136** MCI_UNCACHE -- remove a connection from a slot.
137**
138** May close a connection.
139**
140** Parameters:
141** mcislot -- the slot to empty.
1c7897ef
EA
142** doquit -- if TRUE, send QUIT protocol on this connection.
143** if FALSE, we are assumed to be in a forked child;
144** all we want to do is close the file(s).
eb980753
EA
145**
146** Returns:
147** none.
148*/
149
1c7897ef 150mci_uncache(mcislot, doquit)
f2e44ded 151 register MCI **mcislot;
1c7897ef 152 bool doquit;
eb980753 153{
f2e44ded 154 register MCI *mci;
0cf5a7ba 155 extern ENVELOPE BlankEnvelope;
eb980753
EA
156
157 mci = *mcislot;
158 if (mci == NULL)
159 return;
160 *mcislot = NULL;
eb980753 161
1c7897ef
EA
162 if (doquit)
163 {
b6edea3d 164 message("Closing connection to %s", mci->mci_host);
1c7897ef
EA
165
166 mci->mci_flags &= ~MCIF_CACHED;
4e20c4d2 167
1c7897ef
EA
168 /* only uses the envelope to flush the transcript file */
169 if (mci->mci_state != MCIS_CLOSED)
170 smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
b4f81c5d
EA
171#ifdef XLA
172 xla_host_end(mci->mci_host);
173#endif
1c7897ef
EA
174 }
175 else
176 {
177 if (mci->mci_in != NULL)
bc854e30 178 xfclose(mci->mci_in, "mci_uncache", "mci_in");
1c7897ef 179 if (mci->mci_out != NULL)
bc854e30 180 xfclose(mci->mci_out, "mci_uncache", "mci_out");
1c7897ef
EA
181 mci->mci_in = mci->mci_out = NULL;
182 mci->mci_state = MCIS_CLOSED;
183 mci->mci_exitstat = EX_OK;
184 mci->mci_errno = 0;
185 mci->mci_flags = 0;
186 }
eb980753
EA
187}
188\f/*
189** MCI_FLUSH -- flush the entire cache
1c7897ef
EA
190**
191** Parameters:
192** doquit -- if TRUE, send QUIT protocol.
193** if FALSE, just close the connection.
194** allbut -- but leave this one open.
195**
196** Returns:
197** none.
eb980753
EA
198*/
199
1c7897ef
EA
200mci_flush(doquit, allbut)
201 bool doquit;
202 MCI *allbut;
eb980753
EA
203{
204 register int i;
205
206 if (MciCache == NULL)
207 return;
208
209 for (i = 0; i < MaxMciCache; i++)
1c7897ef
EA
210 if (allbut != MciCache[i])
211 mci_uncache(&MciCache[i], doquit);
eb980753
EA
212}
213\f/*
214** MCI_GET -- get information about a particular host
215*/
216
f2e44ded 217MCI *
eb980753
EA
218mci_get(host, m)
219 char *host;
220 MAILER *m;
221{
f2e44ded 222 register MCI *mci;
4e20c4d2 223 register STAB *s;
f2e44ded 224
3f2dcbd6
EA
225#ifdef DAEMON
226 extern SOCKADDR CurHostAddr;
227
228 /* clear CurHostAddr so we don't get a bogus address with this name */
229 bzero(&CurHostAddr, sizeof CurHostAddr);
e6cb9fc4 230#endif
3f2dcbd6 231
4e20c4d2
EA
232 s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
233 mci = &s->s_mci;
234 mci->mci_host = s->s_name;
f2e44ded
EA
235
236 if (tTd(42, 2))
237 {
238 printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n",
239 host, m->m_name, mci->mci_state, mci->mci_flags,
240 mci->mci_exitstat, mci->mci_errno);
241 }
242
aa102c71 243 if (mci->mci_state == MCIS_OPEN)
f2e44ded 244 {
aa102c71 245 /* poke the connection to see if it's still alive */
c428b1b2 246 smtpprobe(mci);
aa102c71
EA
247
248 /* reset the stored state in the event of a timeout */
249 if (mci->mci_state != MCIS_OPEN)
250 {
251 mci->mci_errno = 0;
252 mci->mci_exitstat = EX_OK;
253 mci->mci_state = MCIS_CLOSED;
254 }
f2e44ded
EA
255 }
256
257 return mci;
eb980753 258}
fdd3df4f
EA
259\f/*
260** MCI_DUMP -- dump the contents of an MCI structure.
261**
262** Parameters:
263** mci -- the MCI structure to dump.
264**
265** Returns:
266** none.
267**
268** Side Effects:
269** none.
270*/
271
272mci_dump(mci)
273 register MCI *mci;
274{
275 extern char *ctime();
276
277 printf("MCI@%x: ", mci);
278 if (mci == NULL)
279 {
280 printf("NULL\n");
281 return;
282 }
8e5c6745
EA
283 printf("flags=%o, errno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,\n",
284 mci->mci_flags, mci->mci_errno, mci->mci_herrno,
285 mci->mci_exitstat, mci->mci_state, mci->mci_pid);
286 printf("\tmaxsize=%ld, phase=%s, mailer=%s,\n",
287 mci->mci_maxsize,
fdd3df4f
EA
288 mci->mci_phase == NULL ? "NULL" : mci->mci_phase,
289 mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name);
290 printf("\thost=%s, lastuse=%s\n",
291 mci->mci_host == NULL ? "NULL" : mci->mci_host,
292 ctime(&mci->mci_lastuse));
293}