-TDICT_REGEXP_RULE
-TDICT_SDBM
-TDICT_SOCKMAP
+-TDICT_SOCKMAP_REFC_HANDLE
-TDICT_SQLITE
-TDICT_STACK
-TDICT_SURROGATE
Documentation: updated TUNING_README with new pointers to
the STRESS_README and POSTSCREEN_README documents. Miscellaneous
documentation clarifications based on postfix-users discussions.
+
+20120903
+
+ Bugfix (introduced 20120317): the socketmap client should
+ not share unrelated client endpoint handles. File:
+ util/dict_sockmap.c.
+
+20120907
+
+ Cleanup (for change 20120824): the DSN RET attribute should
+ not be stored once per recipient. It is a message property
+ just like DSN ENVID. File: sendmail/sendmail.c.
# This document assumes that header and body_checks rules
# are specified in the form of Postfix regular expression
# lookup tables. Usually the best performance is obtained
-# with pcre (Perl Compatible Regular Expression) tables, but
-# the slower regexp (POSIX regular expressions) support is
-# more widely available. Use the command "postconf -m" to
-# find out what lookup table types your Postfix system sup-
-# ports.
+# with pcre (Perl Compatible Regular Expression) tables. The
+# regexp (POSIX regular expressions) tables are usually
+# slower, but more widely available. Use the command "post-
+# conf -m" to find out what lookup table types your Postfix
+# system supports.
#
# The general format of Postfix regular expression tables is
# given below. For a discussion of specific pattern or
This document assumes that header and <a href="postconf.5.html#body_checks">body_checks</a> rules
are specified in the form of Postfix regular expression
lookup tables. Usually the best performance is obtained
- with <b>pcre</b> (Perl Compatible Regular Expression) tables, but
- the slower <b>regexp</b> (POSIX regular expressions) support is
- more widely available. Use the command "<b>postconf -m</b>" to
- find out what lookup table types your Postfix system sup-
- ports.
+ with <b>pcre</b> (Perl Compatible Regular Expression) tables. The
+ <b>regexp</b> (POSIX regular expressions) tables are usually
+ slower, but more widely available. Use the command "<b>post-</b>
+ <b>conf -m</b>" to find out what lookup table types your Postfix
+ system supports.
The general format of Postfix regular expression tables is
given below. For a discussion of specific pattern or
This document assumes that header and body_checks rules are specified
in the form of Postfix regular expression lookup tables. Usually the
best performance is obtained with \fBpcre\fR (Perl Compatible Regular
-Expression) tables, but the slower \fBregexp\fR (POSIX regular
-expressions) support is more widely available.
+Expression) tables. The \fBregexp\fR (POSIX regular
+expressions) tables are usually slower, but more widely
+available.
Use the command "\fBpostconf -m\fR" to find out what lookup table
types your Postfix system supports.
# This document assumes that header and body_checks rules are specified
# in the form of Postfix regular expression lookup tables. Usually the
# best performance is obtained with \fBpcre\fR (Perl Compatible Regular
-# Expression) tables, but the slower \fBregexp\fR (POSIX regular
-# expressions) support is more widely available.
+# Expression) tables. The \fBregexp\fR (POSIX regular
+# expressions) tables are usually slower, but more widely
+# available.
# Use the command "\fBpostconf -m\fR" to find out what lookup table
# types your Postfix system supports.
#
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20120902"
+#define MAIL_RELEASE_DATE "20120908"
#define MAIL_VERSION_NUMBER "2.10"
#ifdef SNAPSHOT
/* enqueue - post one message */
static void enqueue(const int flags, const char *encoding,
- const char *dsn_envid, int dsn_notify, int dsn_ret,
+ const char *dsn_envid, int dsn_ret, int dsn_notify,
const char *rewrite_context, const char *sender,
const char *full_name, char **recipients)
{
if (dsn_envid)
rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_DSN_ENVID, dsn_envid);
+ if (dsn_ret)
+ rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
+ MAIL_ATTR_DSN_RET, dsn_ret);
rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_RWR_CONTEXT, rewrite_context);
if (full_name || (full_name = fullname()) != 0)
if (dsn_notify)
rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
MAIL_ATTR_DSN_NOTIFY, dsn_notify);
- if (dsn_ret)
- rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
- MAIL_ATTR_DSN_RET, dsn_ret);
if (REC_PUT_BUF(dst, REC_TYPE_RCPT, buf) < 0)
msg_fatal_status(EX_TEMPFAIL,
"%s(%ld): error writing queue file: %m",
if (dsn_notify)
rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
MAIL_ATTR_DSN_NOTIFY, dsn_notify);
- if (dsn_ret)
- rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d",
- MAIL_ATTR_DSN_RET, dsn_ret);
-
if (rec_put(dst, REC_TYPE_RCPT, *cpp, strlen(*cpp)) < 0)
msg_fatal_status(EX_TEMPFAIL,
"%s(%ld): error writing queue file: %m",
mail_run_replace(var_command_dir, ext_argv->argv);
/* NOTREACHED */
} else {
- enqueue(flags, encoding, dsn_envid, dsn_notify, dsn_ret,
+ enqueue(flags, encoding, dsn_envid, dsn_ret, dsn_notify,
rewrite_context, sender, full_name, argv + OPTIND);
exit(0);
/* NOTREACHED */
dict_sockmap.o: dict.h
dict_sockmap.o: dict_sockmap.c
dict_sockmap.o: dict_sockmap.h
+dict_sockmap.o: htable.h
dict_sockmap.o: msg.h
dict_sockmap.o: mymalloc.h
dict_sockmap.o: netstring.h
/* Postfix socketmap names have the form inet:host:port:socketmap-name
/* or unix:pathname:socketmap-name, where socketmap-name
/* specifies the socketmap name that the socketmap server uses.
+/*
+/* To test this module, build the netstring and dict_open test
+/* programs. Run "./netstring nc -l portnumber" as the server,
+/* and "./dict_open socketmap:127.0.0.1:portnumber:socketmapname"
+/* as the client.
/* PROTOCOL
/* .ad
/* .fi
#include <netstring.h>
#include <split_at.h>
#include <stringops.h>
+#include <htable.h>
#include <dict_sockmap.h>
/*
DICT dict; /* parent class */
char *sockmap_name; /* on-the-wire socketmap name */
VSTRING *rdwr_buf; /* read/write buffer */
+ HTABLE_INFO *client_info; /* shared endpoint name and handle */
} DICT_SOCKMAP;
/*
/*
* Class variables.
*/
-static AUTO_CLNT *dict_sockmap_clnt; /* auto_clnt handle */
-static int dict_sockmap_refcount; /* handle reference count */
static int dict_sockmap_timeout = DICT_SOCKMAP_DEF_TIMEOUT;
static int dict_sockmap_max_reply = DICT_SOCKMAP_DEF_MAX_REPLY;
static int dict_sockmap_max_idle = DICT_SOCKMAP_DEF_MAX_IDLE;
static int dict_sockmap_max_ttl = DICT_SOCKMAP_DEF_MAX_TTL;
+ /*
+ * The client handle is shared between socketmap instances that have the
+ * same inet:host:port or unix:pathame information. This could be factored
+ * out as a general module for reference-counted handles of any kind.
+ */
+static HTABLE *dict_sockmap_handles; /* shared handles */
+
+typedef struct {
+ AUTO_CLNT *client_handle; /* the client handle */
+ int refcount; /* the reference count */
+} DICT_SOCKMAP_REFC_HANDLE;
+
+#define DICT_SOCKMAP_RH_NAME(ht) (ht)->key
+#define DICT_SOCKMAP_RH_HANDLE(ht) \
+ ((DICT_SOCKMAP_REFC_HANDLE *) (ht)->value)->client_handle
+#define DICT_SOCKMAP_RH_REFCOUNT(ht) \
+ ((DICT_SOCKMAP_REFC_HANDLE *) (ht)->value)->refcount
+
/*
* Socketmap protocol elements.
*/
{
const char *myname = "dict_sockmap_lookup";
DICT_SOCKMAP *dp = (DICT_SOCKMAP *) dict;
+ AUTO_CLNT *sockmap_clnt = DICT_SOCKMAP_RH_HANDLE(dp->client_info);
VSTREAM *fp;
int netstring_err;
char *reply_payload;
/*
* Look up the stream.
*/
- if ((fp = auto_clnt_access(dict_sockmap_clnt)) == 0) {
+ if ((fp = auto_clnt_access(sockmap_clnt)) == 0) {
msg_warn("table %s:%s lookup error: %m", dict->type, dict->name);
dict->error = DICT_ERR_RETRY;
return (0);
*/
if (except_count == 0 && netstring_err == NETSTRING_ERR_EOF
&& errno != ETIMEDOUT) {
- auto_clnt_recover(dict_sockmap_clnt);
+ auto_clnt_recover(sockmap_clnt);
continue;
}
static void dict_sockmap_close(DICT *dict)
{
+ const char *myname = "dict_sockmap_close";
DICT_SOCKMAP *dp = (DICT_SOCKMAP *) dict;
+ if (dict_sockmap_handles == 0 || dict_sockmap_handles->used == 0)
+ msg_panic("%s: attempt to close a non-existent map", myname);
vstring_free(dp->rdwr_buf);
myfree(dp->sockmap_name);
- if (--dict_sockmap_refcount == 0) {
- auto_clnt_free(dict_sockmap_clnt);
- dict_sockmap_clnt = 0;
+ if (--DICT_SOCKMAP_RH_REFCOUNT(dp->client_info) == 0) {
+ auto_clnt_free(DICT_SOCKMAP_RH_HANDLE(dp->client_info));
+ htable_delete(dict_sockmap_handles,
+ DICT_SOCKMAP_RH_NAME(dp->client_info), myfree);
}
if (dict->fold_buf)
vstring_free(dict->fold_buf);
- myfree((char *) dp);
+ dict_free(dict);
}
/* dict_sockmap_open - open socket map */
DICT_SOCKMAP *dp;
char *saved_name;
char *sockmap;
+ DICT_SOCKMAP_REFC_HANDLE *ref_handle;
+ HTABLE_INFO *client_info;
/*
* Sanity checks.
DICT_TYPE_SOCKMAP, mapname));
/*
- * Split the socketmap name off the Postfix mapname.
+ * Separate the socketmap name from the socketmap server name.
*/
saved_name = mystrdup(mapname);
if ((sockmap = split_at_right(saved_name, ':')) == 0)
DICT_TYPE_SOCKMAP));
/*
- * Instantiate the shared client handle.
+ * Use one reference-counted client handle for all socketmaps with the
+ * same inet:host:port or unix:pathname information.
*
* XXX Todo: graceful degradation after endpoint syntax error.
*/
- if (dict_sockmap_refcount == 0)
- dict_sockmap_clnt = auto_clnt_create(saved_name, dict_sockmap_timeout,
- dict_sockmap_max_idle, dict_sockmap_max_ttl);
- dict_sockmap_refcount += 1;
+ if (dict_sockmap_handles == 0)
+ dict_sockmap_handles = htable_create(1);
+ if ((client_info = htable_locate(dict_sockmap_handles, saved_name)) == 0) {
+ ref_handle = (DICT_SOCKMAP_REFC_HANDLE *) mymalloc(sizeof(*ref_handle));
+ client_info = htable_enter(dict_sockmap_handles,
+ saved_name, (char *) ref_handle);
+ /* XXX Late initialization, so we can reuse macros for consistency. */
+ DICT_SOCKMAP_RH_REFCOUNT(client_info) = 1;
+ DICT_SOCKMAP_RH_HANDLE(client_info) =
+ auto_clnt_create(saved_name, dict_sockmap_timeout,
+ dict_sockmap_max_idle, dict_sockmap_max_ttl);
+ } else
+ DICT_SOCKMAP_RH_REFCOUNT(client_info) += 1;
/*
* Instantiate a socket map handle.
dp = (DICT_SOCKMAP *) dict_alloc(DICT_TYPE_SOCKMAP, mapname, sizeof(*dp));
dp->rdwr_buf = vstring_alloc(100);
dp->sockmap_name = mystrdup(sockmap);
+ dp->client_info = client_info;
dp->dict.lookup = dict_sockmap_lookup;
dp->dict.close = dict_sockmap_close;
/* Don't look up parent domains or network superblocks. */