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. */