discarded" warning when mail is dropped on the floor.
Requested by Michael Hasenstein, SuSE, Germany.
+19990516
+
+ Feature: per-service peak and average process limit. When
+ the system is lightly loaded, use the per-service peak
+ process limit. When the system is under stress, use the
+ per-service average process limit. The per-service average
+ process count is computed once a minute.
+
19990517
Bugfix: reject_non_fqdn_sender/recipient would pass
user@[ip_address] regardless of destination. Eric Cholet
had the honor of suffering from this one.
+
+19990527
+
+ More SMTP client logging for easier debugging: the smtp
+ client now logs hostname[ip.addr], and logs every failed
+ attempt to reach an MX host, not just the last one.
Major changes with snapshot-19990513:
=====================================
-- New USER, EXTENSION, LOCAL and DOMAIN environment variables for
-delivery to command (including mailbox_command) by the local delivery
-agent. As you might expect, the information is censored. The list
-of acceptable characters is specified with the command_expansion_filter
-configuration parameter. Unacceptable characters are replaced by
-underscores.
+- New USER, EXTENSION, LOCAL, DOMAIN. and RECIPIENT environment
+variables for delivery to command (including mailbox_command) by
+the local delivery agent. As you might expect, the information is
+censored. The list of acceptable characters is specified with the
+command_expansion_filter configuration parameter. Unacceptable
+characters are replaced by underscores. See html/local.8.html.
- Specify "forward_path = /var/forward/$user" to avoid looking up
.forward files in user home directories. The default value is
}
if (type == REC_TYPE_MESG) {
if (cleanup_sender == 0 || cleanup_time == 0) {
- msg_warn("missing sender or time envelope record");
+ msg_warn("%s: missing sender or time envelope record",
+ cleanup_queue_id);
cleanup_errs |= CLEANUP_STAT_BAD;
} else {
if (warn_time == 0 && var_delay_warn_time > 0)
break;
}
if (strchr(REC_TYPE_ENVELOPE, type) == 0) {
- msg_warn("unexpected record type %d in envelope", type);
+ msg_warn("%s: unexpected record type %d in envelope", type,
+ cleanup_queue_id);
cleanup_errs |= CLEANUP_STAT_BAD;
break;
}
cleanup_sender = mystrdup(STR(clean_addr));
} else if (type == REC_TYPE_RCPT) {
if (cleanup_sender == 0) { /* protect showq */
- msg_warn("envelope recipient precedes sender");
+ msg_warn("%s: envelope recipient precedes sender",
+ cleanup_queue_id);
cleanup_errs |= CLEANUP_STAT_BAD;
break;
}
} else if (type == REC_TYPE_END) {
break;
} else {
- msg_warn("unexpected record type %d in extracted segment", type);
+ msg_warn("%s: unexpected record type %d in extracted segment",
+ cleanup_queue_id, type);
cleanup_errs |= CLEANUP_STAT_BAD;
if (type >= 0)
cleanup_skip();
for (count = 0; count < MAX_RECURSION; count++) {
if ((new_addr = mail_addr_map(maps, STR(addr), propagate)) != 0) {
if (new_addr->argc > 1)
- msg_warn("multi-valued %s entry for %s",
- maps->title, STR(addr));
+ msg_warn("%s: multi-valued %s entry for %s",
+ cleanup_queue_id, maps->title, STR(addr));
saved_addr = mystrdup(STR(addr));
vstring_strcpy(addr, new_addr->argv[0]);
expand_to_self = !strcasecmp(saved_addr, STR(addr));
break;
}
if (strchr(REC_TYPE_CONTENT, type) == 0) {
- msg_warn("%s: unexpected record type %d", myname, type);
+ msg_warn("%s: %s: unexpected record type %d",
+ cleanup_queue_id, myname, type);
cleanup_errs |= CLEANUP_STAT_BAD;
break;
}
if (CLEANUP_OUT_OK()) {
if (rec_put(cleanup_dst, type, string, len) < 0) {
if (errno == EFBIG) {
- msg_warn("queue file size limit exceeded");
+ msg_warn("%s: queue file size limit exceeded",
+ cleanup_queue_id);
cleanup_errs |= CLEANUP_STAT_SIZE;
} else {
msg_warn("%s: write queue file: %m", cleanup_queue_id);
{
int type;
- msg_warn("skipping further client input");
+ msg_warn("%s: skipping further client input", cleanup_queue_id);
/*
* XXX Rely on the front-end programs to enforce record size limits.
mail_name = Postfix
mail_owner = postfix
mail_spool_directory = /var/mail
-mail_version = Snapshot-19990513
+mail_version = Snapshot-19990527
mailbox_command =
mailbox_transport =
maps_rbl_domains = rbl.maps.vix.com
owner_request_special = yes
process_id_directory = pid
program_directory = /usr/libexec/postfix
-propagate_unmatched_extension = canonical, virtual
+propagate_unmatched_extensions = canonical, virtual
qmgr_message_active_limit = 1000
qmgr_message_recipient_limit = 10000
queue_directory = /var/spool/postfix
#define DEF_FORWARD_PATH "$home/.forward${recipient_delimiter}${extension},$home/.forward"
extern char *var_forward_path;
-#define VAR_PROP_EXTENSION "propagate_unmatched_extension"
+#define VAR_PROP_EXTENSION "propagate_unmatched_extensions"
#define DEF_PROP_EXTENSION "canonical, virtual"
extern char *var_prop_extension;
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-19990518"
+#define DEF_MAIL_VERSION "Snapshot-19990527"
extern char *var_mail_version;
/* LICENSE
<li><a href="#firewall">Running Postfix on a firewall</a>
+<li><a href="#dialup">Running Postfix on a dialup machine</a>
+
+<p>
+
<li><a href="#local">Delivering some users locally while sending mail as user@domain</a>
<li><a href="#maildir">Support for maildir-style mailboxes</a>
<li><a href="#approve">Postfix breaks the majordomo "approve" command</a>
+<p>
+
<li><a href="#uucp">Setting up an Internet to UUCP gateway</a>
<li><a href="#uucp-only">Using UUCP as the default transport</a>
<li><a href="#fax">Sending mail to a FAX machine</a>
+<p>
+
<li><a href="#timeouts">Mail fails with timeout or lost connection</a>
<li><a href="#bind">Undefined symbols: ___dn_expand, ___res_init etc.</a>
that table is ignored for destinations that match <b>$mydestination</b>.
That's an implementation error, and it will be removed.
+<hr>
+
+<a name="dialup"><h2>Running Postfix on a dialup machine</h2></a>
+
+<ul>
+
+<li> Route all outgoing mail to your provider.
+
+<p>
+
+If your machine is disconnected most of the time, there isn't
+a lot of opportunity for Postfix to deliver mail to hard-to-reach
+corners of the Internet. It's better to drop the mail to a machine
+that is connected all the time.
+
+<p>
+
+<dl>
+
+<dt><b>/etc/postfix/main.cf:</b>
+
+<dd><b>relayhost = smtprelay.someprovider.com</b>
+
+</dl>
+
+<p>
+
+<li> <a name="spontaneous_smtp">Disable spontaneous SMTP mail
+delivery.</a>
+
+<p>
+
+Normally, Postfix attempts to deliver outbound mail at its convenience.
+If your machine uses on-demand dialup IP, this causes your system
+to place a telephone call whenever you submit mail, and whenever
+Postfix retries to deliver delayed mail. To prevent such telephone
+calls from being placed, disable spontaneous SMTP mail deliveries.
+
+<p>
+
+<dl>
+
+<dt><b>/etc/postfix/main.cf:</b>
+
+<dd><b>defer_transports = smtp</b> (Only for systems that use
+on-demand dialup IP)
+
+</dl>
+
+<p>
+
+<li> Disable SMTP client DNS lookups.
+
+<p>
+
+Some people use Postfix to deliver mail across a LAN that is
+disconnected most of the time. Under such conditions, mail delivery
+can suffer from delays while the Postfix SMTP client performs sender
+and recipient domain DNS lookups in order to be standards-compliant.
+To prevent these delays, disable all SMTP client DNS lookups.
+
+<p>
+
+<dl>
+
+<dt><b>/etc/postfix/main.cf:</b>
+
+<dd><b>disable_dns_lookups = yes</b> (Only for delivery across LANs
+that are disconnected most of the time)
+
+</dl>
+
+<p>
+
+<li> Flush the mail queue whenever the Internet link is established.
+
+<p>
+
+Put the following command into your PPP or SLIP dialup scripts:
+
+<p>
+
+<dl>
+
+<dd><b>/usr/sbin/sendmail -q</b> (whenever the Internet link is up)
+
+</dl>
+
+<p>
+
+The exact location of the <b>sendmail</b> command is system-specific.
+With some UNIX versions, usr <b>/usr/lib/sendmail</b>.
+
+If you have disabled <a href="#spontaneous_smtp">spontaneous SMTP
+mail delivery</a> you need to run this command occasionally while
+the dialup link is up, so that newly-posted mail is flushed from
+the queue.
+
+</ul>
<hr>
<ul>
<li>In order to send mail as <i>user@domain</i>, edit
-<b>/etc/postfix/main.cf</b> and specify that the local domain
+<b>/etc/postfix/main.cf</b> and specify what domain
is to be appended to addresses that do not have a domain:
<p>
<dl>
-<dd><b>myorigin = </b><i>$mydomain</i>
+<dd><b>myorigin = </b><i>domain</i>
</dl>
<dl>
-<dd><b>root root@</b><i>my.host.name</i>
+<dd><b>root root@localhost</b>
-<dd><b>postmaster postmaster@</b><i>my.host.name</i>
+<dd><b>postmaster postmaster@localhost</b>
</dl>
<dd><b>mailbox_command = </b><i>/path/to/procmail</i>
+<p>
+
+<dd><b>mailbox_command = </b><i>/path/to/procmail</i><b> -a
+ "$EXTENSION"</b>
+
</dl>
<p>
-Do not use any shell meta characters or built-ins
-such as <b>IFS</b> or <b>&&</b>, because they force Postfix
-to run an expensive shell process.
+If you can, avoid using any shell meta characters or built-ins
+such as <b>$</b> or <b>"</b> or <b>IFS</b> or <b>&&</b>,
+because they force Postfix to run an expensive shell process.
<p>
</ul>
+Postfix exports information via environment variables. The contents
+are censored. Any characters that may have special meaning to the
+shell are replaced by underscores.
+
+<p>
+
+<dl>
+
+<dl>
+
+<dt><b>DOMAIN</b> <dd> The text to the right-hand side of the
+<b>@</b> in the recipient address.
+
+<dt><b>EXTENSION</b> <dd> Optional address extension part.
+
+<dt><b>HOME</b> <dd> The recpient's home directory.
+
+<dt><b>LOCAL</b> <dd> The text to the left-hand side of the <b>@</b>
+in the recipient address, for example, <b>$USER+$EXTENSION</b>.
+
+<dt><b>LOGNAME</b> <dd> The recipient username.
+
+<dt><b>RECIPIENT</b> <dd> The entire recipient address,
+<b>$LOCAL@$DOMAIN</b>.
+
+<dt><b>SHELL</b> <dd> The recipient's login shell.
+
+<dt><b>USER</b> <dd> The recipient username.
+
+</dl>
+
+</dl>
+
<hr>
<a name="verbose"><h2>Postfix breaks "sendmail -v"</h2> </a>
*/gcc|gcc) case `$CC -v` in
"gcc version 2.8"*) : ${OPT=};;
esac;;
- *) : ${OPT='-O'};;
+ *CC) echo "Don't use CC. That's the C++ compiler" 1>&2; exit 1;;
+ *) : ${OPT='-O'};;
esac
: ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'}
SRCS = master.c master_conf.c master_ent.c master_sig.c master_avail.c \
master_spawn.c master_service.c master_status.o master_listen.c \
master_proto.c single_server.c multi_server.c master_vars.c \
- master_wakeup.c
+ master_wakeup.c master_sample.c
OBJS = master.o master_conf.o master_ent.o master_sig.o master_avail.o \
master_spawn.o master_service.o master_status.o master_listen.o \
- master_vars.o master_wakeup.o
+ master_vars.o master_wakeup.o master_sample.o
LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o
HDRS = mail_server.h master_proto.h
INT_HDR = master.h
master_ent.o: ../include/stringops.h
master_ent.o: ../include/readlline.h
master_ent.o: ../include/inet_addr_list.h
+master_ent.o: ../include/split_at.h
master_ent.o: ../include/mail_proto.h
master_ent.o: ../include/iostuff.h
master_ent.o: ../include/mail_params.h
master_proto.o: ../include/sys_defs.h
master_proto.o: ../include/msg.h
master_proto.o: master_proto.h
+master_sample.o: master_sample.c
+master_sample.o: ../include/sys_defs.h
+master_sample.o: ../include/events.h
+master_sample.o: ../include/msg.h
+master_sample.o: master.h
master_service.o: master_service.c
master_service.o: ../include/sys_defs.h
master_service.o: ../include/msg.h
* that there are no concurrency conflicts within the master process.
*/
signal(SIGALRM, master_watchdog);
+ master_sample_start();
for (;;) {
#ifdef HAS_VOLATILE_LOCKS
if (myflock(vstream_fileno(lock_fp), MYFLOCK_EXCLUSIVE) < 0)
struct INET_ADDR_LIST *inet;
} addr_list;
int max_proc; /* upper bound on # processes */
+ int max_proc_pk; /* peak upper bound */
+ int max_proc_avg; /* average upper bound */
char *path; /* command pathname */
struct ARGV *args; /* argument vector */
int avail_proc; /* idle processes */
int total_proc; /* number of processes */
+ float total_proc_avg; /* average number of processes */
int throttle_delay; /* failure recovery parameter */
int status_fd[2]; /* child status reports */
struct BINHASH *children; /* linkage */
extern void master_reap_child(void);
extern void master_delete_children(MASTER_SERV *);
+ /*
+ * master_sample.c
+ */
+extern void master_sample_start(void);
+extern void master_sample_stop(void);
+
/* DIAGNOSTICS
/* BUGS
/* SEE ALSO
* request.
*/
if (msg_verbose)
- msg_info("%s: avail %d total %d max %d", myname,
- serv->avail_proc, serv->total_proc, serv->max_proc);
+ msg_info("%s: avail %d total/avg %d/%.1f max/pk/avg %d/%d/%d", myname,
+ serv->avail_proc, serv->total_proc, serv->total_proc_avg,
+ serv->max_proc, serv->max_proc, serv->max_proc_pk,
+ serv->max_proc_avg);
if (serv->avail_proc < 1
&& MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)
&& !MASTER_THROTTLED(serv)) {
else {
serv->flags &= ~MASTER_FLAG_MARK;
serv->wakeup_time = entry->wakeup_time;
- serv->max_proc = entry->max_proc;
+ serv->max_proc_pk = entry->max_proc_pk;
+ serv->max_proc_avg = entry->max_proc_avg;
serv->throttle_delay = entry->throttle_delay;
SWAP(char *, serv->path, entry->path);
SWAP(ARGV *, serv->args, entry->args);
#include <stringops.h>
#include <readlline.h>
#include <inet_addr_list.h>
+#include <split_at.h>
/* Global library. */
}
}
-/* get_bool_ent - extract boolean field */
+/* cvt_bool_ent - convert boolean field */
-static int get_bool_ent(char **bufp, char *name, char *def_val)
+static int cvt_bool_ent(char *name, char *value)
{
- char *value;
-
- value = get_str_ent(bufp, name, def_val);
if (strcmp("y", value) == 0) {
return (1);
} else if (strcmp("n", value) == 0) {
/* NOTREACHED */
}
-/* get_int_ent - extract integer field */
+/* get_bool_ent - extract boolean field */
-static int get_int_ent(char **bufp, char *name, char *def_val, int min_val)
+static int get_bool_ent(char **bufp, char *name, char *def_val)
{
char *value;
- int n;
value = get_str_ent(bufp, name, def_val);
+ return (cvt_bool_ent(name, value));
+}
+
+/* cvt_int_ent - convert integer field */
+
+static int cvt_int_ent(char *name, char *value, int min_val)
+{
+ int n;
+
if (!ISDIGIT(*value) || (n = atoi(value)) < min_val)
fatal_invalid_field(name, value);
return (n);
}
+/* get_int_ent - extract integer field */
+
+static int get_int_ent(char **bufp, char *name, char *def_val, int min_val)
+{
+ char *value;
+
+ value = get_str_ent(bufp, name, def_val);
+ return (cvt_int_ent(name, value, min_val));
+}
+
/* get_master_ent - read entry from configuration file */
MASTER_SERV *get_master_ent()
char *command;
int n;
char *bufp;
+ char *cp2;
if (master_fp == 0)
msg_panic("get_master_ent: config file not open");
* Concurrency limit. Zero means no limit.
*/
vstring_sprintf(junk, "%d", var_proc_limit);
- serv->max_proc = get_int_ent(&bufp, "max_proc", vstring_str(junk), 0);
+ cp = get_str_ent(&bufp, "max_proc", vstring_str(junk));
+ if ((cp2 = split_at(cp, '/')) != 0) {
+ serv->max_proc_pk = cvt_int_ent("max_proc", strcmp(cp, "-") != 0 ?
+ cp : vstring_str(junk), 0);
+ serv->max_proc_avg = cvt_int_ent("max_proc", strcmp(cp2, "-") != 0 ?
+ cp2 : vstring_str(junk), 0);
+ if (serv->max_proc_pk == 0 && serv->max_proc_avg != 0)
+ fatal_with_context("specify a non-zero peak process limit");
+ if (serv->max_proc_pk != 0 && serv->max_proc_avg == 0)
+ fatal_with_context("specify a non-zero average process limit");
+ if (serv->max_proc_pk < serv->max_proc_avg)
+ fatal_with_context("peak < average process limit");
+ } else {
+ serv->max_proc_pk = cvt_int_ent("max_proc", cp, 0);
+ serv->max_proc_avg = serv->max_proc;
+ }
+ serv->max_proc = serv->max_proc_pk;
/*
* Path to command,
*/
serv->avail_proc = 0;
serv->total_proc = 0;
+ serv->total_proc_avg = 0;
/*
* Backoff time in case a service is broken.
*/
serv->args = argv_alloc(0);
argv_add(serv->args, command, (char *) 0);
- if (serv->max_proc == 1)
+ if (serv->max_proc_pk == 1)
argv_add(serv->args, "-l", (char *) 0);
if (strcmp(basename(command), name) != 0)
argv_add(serv->args, "-n", name, (char *) 0);
msg_info("listen_fd_count: %d", serv->listen_fd_count);
msg_info("wakeup: %d", serv->wakeup_time);
msg_info("max_proc: %d", serv->max_proc);
+ msg_info("max_proc_pk: %d", serv->max_proc_pk);
+ msg_info("max_proc_avg: %d", serv->max_proc_avg);
msg_info("path: %s", serv->path);
for (cpp = serv->args->argv; *cpp; cpp++)
msg_info("arg[%d]: %s", (int) (cpp - serv->args->argv), *cpp);
msg_info("avail_proc: %d", serv->avail_proc);
msg_info("total_proc: %d", serv->total_proc);
+ msg_info("total_proc_avg: %f", serv->total_proc_avg);
msg_info("throttle_delay: %d", serv->throttle_delay);
msg_info("status_fd %d %d", serv->status_fd[0], serv->status_fd[1]);
msg_info("children: 0x%lx", (long) serv->children);
--- /dev/null
+/*++
+/* NAME
+/* master_sample 3
+/* SUMMARY
+/* Postfix master - statistics sampling
+/* SYNOPSIS
+/* #include "master.h"
+/*
+/* void master_sample_start()
+/*
+/* void master_sample_stop(serv)
+/* DESCRIPTION
+/* This module samples statistics at one-minute intervals.
+/* Currently, it maintains the average process counts.
+/*
+/* master_sample_start() resets the statistics and starts
+/* the statistics sampling process.
+/*
+/* master_sample_start() stops the statistics sampling process.
+/* DIAGNOSTICS
+/* BUGS
+/* SEE ALSO
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <events.h>
+#include <msg.h>
+
+/* Application-specific. */
+
+#include "master.h"
+
+/* master_sample_action - take sample */
+
+static void master_sample_action(int unused_event, char *unused_context)
+{
+ MASTER_SERV *serv;
+
+#define TSAMPLE 60
+#define NSAMPLE 5
+
+ /*
+ * Update the process limit for services that have different peak/average
+ * concurrency limits. Gradually change from idle mode (allowing peak
+ * concurrency) to stress mode (long-term average process limit).
+ */
+ for (serv = master_head; serv != 0; serv = serv->next) {
+ if (serv->max_proc_pk == 0 || serv->max_proc_avg == 0
+ || serv->max_proc_pk == serv->max_proc_avg)
+ continue;
+ serv->total_proc_avg +=
+ (serv->total_proc - serv->total_proc_avg) / NSAMPLE;
+ if (msg_verbose)
+ msg_info("%s total/avg %d/%.1f",
+ serv->name, serv->total_proc, serv->total_proc_avg);
+ if (serv->max_proc_pk < serv->max_proc_avg)
+ msg_panic("%s: process limit botch: %d < %d",
+ serv->name, serv->max_proc_pk, serv->max_proc_avg);
+ if (serv->total_proc_avg >= serv->max_proc_avg)
+ serv->max_proc = serv->max_proc_avg;
+ else
+ serv->max_proc = serv->max_proc_pk
+ - serv->total_proc_avg * (serv->max_proc_pk - serv->max_proc_avg) / (double) serv->max_proc_avg;
+ }
+ event_request_timer(master_sample_action, (char *) 0, TSAMPLE);
+}
+
+/* master_sample_start - start sampling */
+
+void master_sample_start(void)
+{
+ MASTER_SERV *serv;
+
+ for (serv = master_head; serv != 0; serv = serv->next)
+ serv->total_proc_avg = 0;
+ event_request_timer(master_sample_action, (char *) 0, TSAMPLE);
+}
+
+/* master_sample_stop - stop sampling */
+
+void master_sample_stop(void)
+{
+ event_cancel_timer(master_sample_action, (char *) 0);
+}
VSTREAM *stream; /* network connection */
char *host; /* mail exchanger */
char *addr; /* mail exchanger */
+ char *namaddr; /* mail exchanger */
int best; /* most preferred host */
} SMTP_SESSION;
*/
if (ISDIGIT(host[0]) && (inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
memset((char *) &fixed, 0, sizeof(fixed));
- return (dns_rr_append(addr_list,
- dns_rr_create(host, &fixed, pref,
- (char *) &inaddr, sizeof(inaddr))));
+ rr = dns_rr_create(host, &fixed, pref,
+ (char *) &inaddr, sizeof(inaddr));
+ if (msg_verbose)
+ smtp_print_addr(host, rr);
+ return (dns_rr_append(addr_list, rr));
}
/*
smtp_errno = SMTP_FAIL;
} else {
while (hp->h_addr_list[0]) {
- addr_list = dns_rr_append(addr_list,
- dns_rr_create(host, &fixed, pref,
- hp->h_addr_list[0],
- sizeof(inaddr)));
+ rr = dns_rr_create(host, &fixed, pref,
+ hp->h_addr_list[0],
+ sizeof(inaddr));
+ if (msg_verbose)
+ smtp_print_addr(host, rr);
+ addr_list = dns_rr_append(addr_list, rr);
hp->h_addr_list++;
}
}
case DNS_OK:
for (rr = addr; rr; rr = rr->next)
rr->pref = pref;
+ if (msg_verbose)
+ smtp_print_addr(host, addr_list);
addr_list = dns_rr_append(addr_list, addr);
break;
default:
* program is trying to do.
*/
if (msg_verbose)
- msg_info("> %s: %s", session->host, STR(state->buffer));
+ msg_info("> %s: %s", session->namaddr, STR(state->buffer));
/*
* Send the command to the SMTP server.
cp = printable(STR(state->buffer), '?');
if (last_char != '\n')
msg_warn("%s: response longer than %d: %.30s...",
- session->host, var_line_limit, cp);
+ session->namaddr, var_line_limit, cp);
if (msg_verbose)
- msg_info("< %s: %s", session->host, cp);
+ msg_info("< %s: %s", session->namaddr, cp);
while (ISDIGIT(*cp))
cp++;
rdata.code = (cp - STR(state->buffer) == 3 ?
mail_addr_mail_daemon());
post_mail_fprintf(notice, "To: %s (Postmaster)", var_error_rcpt);
post_mail_fprintf(notice, "Subject: %s SMTP client: errors from %s",
- var_mail_name, session->host);
+ var_mail_name, session->namaddr);
post_mail_fputs(notice, "");
- post_mail_fprintf(notice, "Unexpected response from %s.", session->host);
+ post_mail_fprintf(notice, "Unexpected response from %s.", session->namaddr);
post_mail_fputs(notice, "");
post_mail_fputs(notice, "Transcript of session follows.");
post_mail_fputs(notice, "");
SMTP_SESSION *smtp_connect_domain(char *name, unsigned port, VSTRING *why)
{
+ struct in_addr inaddr;
SMTP_SESSION *session = 0;
DNS_RR *addr_list;
DNS_RR *addr;
session->best = (addr->pref == addr_list->pref);
break;
}
+ if (addr->next) {
+ memcpy((char *) &inaddr, addr->data, sizeof(inaddr));
+ msg_info("%s: connect to %s port %d: %s",
+ name, inet_ntoa(inaddr), port, vstring_str(why));
+ }
}
dns_rr_free(addr_list);
return (session);
if (((resp = smtp_chat_resp(state))->code / 100) != 2)
return (smtp_site_fail(state, resp->code,
"host %s refused to talk to me: %s",
- session->host, translit(resp->str, "\n", " ")));
+ session->namaddr, translit(resp->str, "\n", " ")));
/*
* See if we are talking to ourself. This should not be possible with the
for (n = 0; (word = mystrtok(&words, " \t\n")) != 0; n++) {
if (n == 0 && strcasecmp(word, var_myhostname) == 0) {
msg_warn("host %s greeted me with my own hostname %s",
- session->host, var_myhostname);
+ session->namaddr, var_myhostname);
return (smtp_site_fail(state, session->best ? 550 : 450,
"mail for %s loops back to myself",
request->nexthop));
if ((resp = smtp_chat_resp(state))->code / 100 != 2)
return (smtp_site_fail(state, resp->code,
"host %s refused to talk to me: %s",
- session->host,
+ session->namaddr,
translit(resp->str, "\n", " ")));
}
case SMTP_STATE_MAIL:
if (resp->code / 100 != 2) {
smtp_mesg_fail(state, resp->code,
- "host %s said: %s", session->host,
+ "host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
mail_from_rejected = 1;
}
} else {
rcpt = request->rcpt_list.info + recv_rcpt;
smtp_rcpt_fail(state, resp->code, rcpt,
- "host %s said: %s", session->host,
+ "host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
rcpt->offset = 0; /* in case deferred */
}
if (resp->code / 100 != 3) {
if (nrcpt > 0)
smtp_mesg_fail(state, resp->code,
- "host %s said: %s", session->host,
+ "host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
nrcpt = -1;
}
if (resp->code / 100 != 2) {
smtp_mesg_fail(state, resp->code,
"host %s said: %s",
- session->host,
+ session->namaddr,
translit(resp->str, "\n", " "));
} else {
for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset) {
sent(request->queue_id, rcpt->address,
- session->host, request->arrival_time, "%s",
+ session->namaddr,
+ request->arrival_time, "%s",
resp->str);
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
msg_fatal("queue file read error");
if (rec_type != REC_TYPE_XTRA)
RETURN(mark_corrupt(state->src));
+#if 0
+ vstream_fflush(session->stream);
+#endif
}
/*
#include <mymalloc.h>
#include <vstream.h>
+#include <stringops.h>
/* Application-specific. */
session->stream = stream;
session->host = mystrdup(host);
session->addr = mystrdup(addr);
+ session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
session->best = 1;
return (session);
}
vstream_fclose(session->stream);
myfree(session->host);
myfree(session->addr);
+ myfree(session->namaddr);
myfree((char *) session);
}
continue;
status = (soft_error ? defer_append : bounce_append)
(KEEP, request->queue_id, rcpt->address,
- session ? session->host : "none",
+ session ? session->namaddr : "none",
request->arrival_time, "%s", vstring_str(why));
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
continue;
status = (SMTP_SOFT(code) ? defer_append : bounce_append)
(KEEP, request->queue_id, rcpt->address,
- session->host, request->arrival_time,
+ session->namaddr, request->arrival_time,
"%s", vstring_str(why));
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
*/
va_start(ap, format);
status = (SMTP_SOFT(code) ? vdefer_append : vbounce_append)
- (KEEP, request->queue_id, rcpt->address, session->host,
+ (KEEP, request->queue_id, rcpt->address, session->namaddr,
request->arrival_time, format, ap);
va_end(ap);
if (status == 0) {
msg_panic("smtp_stream_except: unknown exception %d", code);
case SMTP_ERR_EOF:
vstring_sprintf(why, "lost connection with %s while %s",
- session->host, description);
+ session->namaddr, description);
break;
case SMTP_ERR_TIME:
vstring_sprintf(why, "conversation with %s timed out while %s",
- session->host, description);
+ session->namaddr, description);
break;
}
if (rcpt->offset == 0)
continue;
state->status |= defer_append(KEEP, request->queue_id,
- rcpt->address, session->host,
+ rcpt->address, session->namaddr,
request->arrival_time,
"%s", vstring_str(why));
}