* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)mci.c 8.2 (Berkeley) 7/11/93";
** Mail Connection Information (MCI) Caching Module.
** There are actually two separate things cached. The first is
** the set of all open connections -- these are stored in a
** (small) list. The second is stored in the symbol table; it
** has the overall status for all hosts, whether or not there
** is a connection open currently.
** There should never be too many connections open (since this
** could flood the socket table), nor should a connection be
** allowed to sit idly for too long.
** MaxMciCache is the maximum number of open connections that
** MciCacheTimeout is the time (in seconds) that a connection
** is permitted to survive without activity.
** We actually try any cached connections by sending a NOOP
** before we use them; if the NOOP fails we close down the
** connection and reopen it. Note that this means that a
** server SMTP that doesn't support NOOP will hose the
** algorithm -- but that doesn't seem too likely.
MCI
**MciCache
; /* the open connection cache */
** MCI_CACHE -- enter a connection structure into the open connection cache
** This may cause something else to be flushed.
** mci -- the connection to cache.
/* we don't support caching */
** Find the best slot. This may cause expired connections
/* if this is already cached, we are done */
if (bitset(MCIF_CACHED
, mci
->mci_flags
))
/* otherwise we may have to clear the slot */
mci_uncache(mcislot
, TRUE
);
mci
->mci_flags
|= MCIF_CACHED
;
** MCI_SCAN -- scan the cache, flush junk, and return best slot
** savemci -- never flush this one. Can be null.
** The LRU (or empty) slot.
MciCache
= (MCI
**) xalloc(MaxMciCache
* sizeof *MciCache
);
bzero((char *) MciCache
, MaxMciCache
* sizeof *MciCache
);
for (i
= 0; i
< MaxMciCache
; i
++)
if (mci
== NULL
|| mci
->mci_state
== MCIS_CLOSED
)
if (mci
->mci_lastuse
+ MciCacheTimeout
< now
&& mci
!= savemci
)
/* connection idle too long -- close it */
mci_uncache(bestmci
, TRUE
);
if (mci
->mci_lastuse
< (*bestmci
)->mci_lastuse
)
** MCI_UNCACHE -- remove a connection from a slot.
** May close a connection.
** mcislot -- the slot to empty.
** doquit -- if TRUE, send QUIT protocol on this connection.
** if FALSE, we are assumed to be in a forked child;
** all we want to do is close the file(s).
mci_uncache(mcislot
, doquit
)
extern ENVELOPE BlankEnvelope
;
message("Closing connection to %s", mci
->mci_host
);
mci
->mci_flags
&= ~MCIF_CACHED
;
/* only uses the envelope to flush the transcript file */
if (mci
->mci_state
!= MCIS_CLOSED
)
smtpquit(mci
->mci_mailer
, mci
, &BlankEnvelope
);
xla_host_end(mci
->mci_host
);
xfclose(mci
->mci_in
, "mci_uncache", "mci_in");
if (mci
->mci_out
!= NULL
)
xfclose(mci
->mci_out
, "mci_uncache", "mci_out");
mci
->mci_in
= mci
->mci_out
= NULL
;
mci
->mci_state
= MCIS_CLOSED
;
mci
->mci_exitstat
= EX_OK
;
** MCI_FLUSH -- flush the entire cache
** doquit -- if TRUE, send QUIT protocol.
** if FALSE, just close the connection.
** allbut -- but leave this one open.
mci_flush(doquit
, allbut
)
for (i
= 0; i
< MaxMciCache
; i
++)
if (allbut
!= MciCache
[i
])
mci_uncache(&MciCache
[i
], doquit
);
** MCI_GET -- get information about a particular host
extern SOCKADDR CurHostAddr
;
/* clear CurHostAddr so we don't get a bogus address with this name */
bzero(&CurHostAddr
, sizeof CurHostAddr
);
s
= stab(host
, ST_MCI
+ m
->m_mno
, ST_ENTER
);
mci
->mci_host
= s
->s_name
;
printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n",
host
, m
->m_name
, mci
->mci_state
, mci
->mci_flags
,
mci
->mci_exitstat
, mci
->mci_errno
);
if (mci
->mci_state
== MCIS_OPEN
)
/* poke the connection to see if it's still alive */
/* reset the stored state in the event of a timeout */
if (mci
->mci_state
!= MCIS_OPEN
)
mci
->mci_exitstat
= EX_OK
;
mci
->mci_state
= MCIS_CLOSED
;
** MCI_DUMP -- dump the contents of an MCI structure.
** mci -- the MCI structure to dump.
printf("flags=%o, errno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,\n",
mci
->mci_flags
, mci
->mci_errno
, mci
->mci_herrno
,
mci
->mci_exitstat
, mci
->mci_state
, mci
->mci_pid
);
printf("\tmaxsize=%ld, phase=%s, mailer=%s,\n",
mci
->mci_phase
== NULL
? "NULL" : mci
->mci_phase
,
mci
->mci_mailer
== NULL
? "NULL" : mci
->mci_mailer
->m_name
);
printf("\thost=%s, lastuse=%s\n",
mci
->mci_host
== NULL
? "NULL" : mci
->mci_host
,
ctime(&mci
->mci_lastuse
));