diff --git a/postfix/.indent.pro b/postfix/.indent.pro
index df478eb1f..d79ef9582 100644
--- a/postfix/.indent.pro
+++ b/postfix/.indent.pro
@@ -99,6 +99,7 @@
-TDICT_REGEXP_RULE
-TDICT_SDBM
-TDICT_SOCKMAP
+-TDICT_SOCKMAP_REFC_HANDLE
-TDICT_SQLITE
-TDICT_STACK
-TDICT_SURROGATE
diff --git a/postfix/HISTORY b/postfix/HISTORY
index 43d5a7943..0f30ecef8 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -17929,3 +17929,15 @@ Apologies for any names omitted.
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.
diff --git a/postfix/conf/header_checks b/postfix/conf/header_checks
index f10e2dfaf..490e214c7 100644
--- a/postfix/conf/header_checks
+++ b/postfix/conf/header_checks
@@ -108,11 +108,11 @@
# 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
diff --git a/postfix/html/header_checks.5.html b/postfix/html/header_checks.5.html
index 9705e12c7..c1d2fe860 100644
--- a/postfix/html/header_checks.5.html
+++ b/postfix/html/header_checks.5.html
@@ -114,11 +114,11 @@ HEADER_CHECKS(5) HEADER_CHECKS(5)
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
diff --git a/postfix/man/man5/header_checks.5 b/postfix/man/man5/header_checks.5
index 5ce90a80d..10cd89a00 100644
--- a/postfix/man/man5/header_checks.5
+++ b/postfix/man/man5/header_checks.5
@@ -117,8 +117,9 @@ insensitive.
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.
diff --git a/postfix/proto/header_checks b/postfix/proto/header_checks
index bf1cb0007..b797e6b5e 100644
--- a/postfix/proto/header_checks
+++ b/postfix/proto/header_checks
@@ -101,8 +101,9 @@
# 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.
#
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 6d55f5da8..ac51d149a 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* 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
diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c
index c7394cd67..88a7b67ec 100644
--- a/postfix/src/sendmail/sendmail.c
+++ b/postfix/src/sendmail/sendmail.c
@@ -612,7 +612,7 @@ static void output_header(void *context, int header_class,
/* 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)
{
@@ -726,6 +726,9 @@ static void enqueue(const int flags, const char *encoding,
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)
@@ -751,9 +754,6 @@ static void enqueue(const int flags, const char *encoding,
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",
@@ -893,10 +893,6 @@ static void enqueue(const int flags, const char *encoding,
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",
@@ -1354,7 +1350,7 @@ int main(int argc, char **argv)
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 */
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index 59bbc3587..48990a635 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -1080,6 +1080,7 @@ dict_sockmap.o: auto_clnt.h
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
diff --git a/postfix/src/util/dict_sockmap.c b/postfix/src/util/dict_sockmap.c
index b40393939..f177066bd 100644
--- a/postfix/src/util/dict_sockmap.c
+++ b/postfix/src/util/dict_sockmap.c
@@ -20,6 +20,11 @@
/* 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
@@ -89,6 +94,7 @@
#include
#include
#include
+#include
#include
/*
@@ -98,6 +104,7 @@ typedef struct {
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;
/*
@@ -111,13 +118,29 @@ typedef struct {
/*
* 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.
*/
@@ -139,6 +162,7 @@ static const char *dict_sockmap_lookup(DICT *dict, const char *key)
{
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;
@@ -167,7 +191,7 @@ static const char *dict_sockmap_lookup(DICT *dict, const char *key)
/*
* 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);
@@ -206,7 +230,7 @@ static const char *dict_sockmap_lookup(DICT *dict, const char *key)
*/
if (except_count == 0 && netstring_err == NETSTRING_ERR_EOF
&& errno != ETIMEDOUT) {
- auto_clnt_recover(dict_sockmap_clnt);
+ auto_clnt_recover(sockmap_clnt);
continue;
}
@@ -263,17 +287,21 @@ static const char *dict_sockmap_lookup(DICT *dict, const char *key)
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 */
@@ -283,6 +311,8 @@ DICT *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags)
DICT_SOCKMAP *dp;
char *saved_name;
char *sockmap;
+ DICT_SOCKMAP_REFC_HANDLE *ref_handle;
+ HTABLE_INFO *client_info;
/*
* Sanity checks.
@@ -299,7 +329,7 @@ DICT *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags)
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)
@@ -309,14 +339,24 @@ DICT *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags)
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.
@@ -324,6 +364,7 @@ DICT *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags)
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. */