mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 06:05:37 +00:00
snapshot-19991209
This commit is contained in:
@@ -25,8 +25,8 @@ Append one or more -v options to selected daemon definitions in
|
||||
/etc/postfix/master.cf and type "postfix reload". This will cause
|
||||
a lot of activity to be logged to the syslog daemon.
|
||||
|
||||
4 - Tracing a Postfix daemon process
|
||||
====================================
|
||||
4 - Manually tracing a Postfix daemon process
|
||||
=============================================
|
||||
|
||||
Some systems allow you to inspect a running process with a system
|
||||
call tracer. For example:
|
||||
@@ -41,12 +41,30 @@ See your system documentation for details.
|
||||
Tracing a running process can give valuable information about what
|
||||
a process is attempting to do. This is as much information as you
|
||||
can get without running an interactive debugger program, as described
|
||||
in the next section.
|
||||
in a later section.
|
||||
|
||||
See the next section on how to automatically attach a program to
|
||||
a Postfix daemon.
|
||||
5 - Automatically tracing a Postfix daemon process
|
||||
==================================================
|
||||
|
||||
5 - Running daemon programs under an interactive debugger
|
||||
Postfix can attach a call tracer whenever a daemon process starts.
|
||||
|
||||
Append a -D option to the suspect command in /etc/postfix/master.cf,
|
||||
for example:
|
||||
|
||||
smtp inet n - n - - smtpd -D
|
||||
|
||||
Edit the debugger_command definition in /etc/postfix/main.cf so
|
||||
that it invokes the call tracer of your choice, for example:
|
||||
|
||||
debugger_command =
|
||||
PATH=/bin:/usr/bin:/usr/local/bin
|
||||
(truss -p $process_id 2>&1 | logger -p mail.info) & sleep 5
|
||||
|
||||
Instead of truss use trace or strace.
|
||||
|
||||
Type "postfix reload" and watch the logfile.
|
||||
|
||||
6 - Running daemon programs under an interactive debugger
|
||||
=========================================================
|
||||
|
||||
Append a -D option to the suspect command in /etc/postfix/master.cf,
|
||||
@@ -72,7 +90,7 @@ Stop and start the Postfix system.
|
||||
Whenever the suspect daemon process is started, a debugger window
|
||||
pops up and you can watch in detail what happens.
|
||||
|
||||
6 - Unreasonable behavior
|
||||
7 - Unreasonable behavior
|
||||
=========================
|
||||
|
||||
Sometimes the behavior exhibit by Postfix just does not match the
|
||||
|
@@ -3317,15 +3317,43 @@ Apologies for any names omitted.
|
||||
|
||||
19991207
|
||||
|
||||
Performance: the queue manager now frees in-memory recipients
|
||||
as soon as a message is delivered to one destination, rather
|
||||
than waiting until all in-memory recipients of that message
|
||||
have been tried. This means that one message with many
|
||||
recipients no longer stops other mail from being delivered.
|
||||
Performance: one message with many recipients no longer
|
||||
stops other mail from being delivered. The queue manager
|
||||
now frees in-memory recipients as soon as a message is
|
||||
delivered to one destination, rather than waiting until
|
||||
all in-memory destinations of that message have been tried.
|
||||
Patch by Patrik Rak @ ein.cz. Files: qmgr/qmgr_entry.c,
|
||||
qmgr/qmgr_message.c.
|
||||
|
||||
Performance: when delivering a huge list of recipients,
|
||||
the queue manager now reads new recipients from queue file
|
||||
before delivery concurrency starts dropping. Files:
|
||||
qmgr/qmgr_entry.c, qmgr/qmgr_message.c.
|
||||
Performance: when delivering mail to a huge list of
|
||||
recipients, the queue manager now reads more recipients
|
||||
from the queue file before delivery concurrency starts
|
||||
to drop. Files: qmgr/qmgr_entry.c, qmgr/qmgr_message.c.
|
||||
|
||||
19991208
|
||||
|
||||
Performance: improved worst-case behavior. A fully loaded
|
||||
Postfix inflicts the same delay to messages with any number
|
||||
of recipients (up to qmgr_message_recipient_limit.) Inspired
|
||||
by discussions with Patrik Rak (although he disagrees with
|
||||
the strategy). File: qmgr/qmgr_message.c.
|
||||
|
||||
Updated LDAP client code by John Hensley with escape
|
||||
sequences as per RFC 2254. File: util/dict_ldap.c.
|
||||
|
||||
Updated MYSQL client code by Scott Cotton. File: dict_mysql.c.
|
||||
|
||||
Feature: added -N/-n options to include/exclude terminating
|
||||
nulls in keys and values in postmap/postalias DB or DBM
|
||||
files. Normally, Postfix uses whatever is appropriate for
|
||||
the host system. A non-default setting can be necessary
|
||||
for inter-operability with third-party software.
|
||||
|
||||
Bugfix: the local delivery agent would deliver to the user
|
||||
instead of the .forward file when the .forward file was
|
||||
already visited via some non-recursive path. Patch by Patrik
|
||||
Rak @ ein.cz. Files: global/been_here.c, local/dotforward.c.
|
||||
|
||||
Robustness: attempt to deliver all addresses in the expansion
|
||||
of an alias or .forward file, even when some addresses must
|
||||
be deferred. File: local/token.c.
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Incompatible changes with snapshot 19991127
|
||||
Incompatible changes with snapshot 19991209
|
||||
===========================================
|
||||
|
||||
- In an SMTPD access map, an all-numeric right-hand side now means
|
||||
@@ -18,7 +18,7 @@ $mydestination domains matches a transport specification, you also
|
||||
need to add a "domain.name local:" entry in your transport_maps.
|
||||
See the html/faq.html sections for firewalls and intranets.
|
||||
|
||||
Major changes with snapshot 19991127
|
||||
Major changes with snapshot 19991209
|
||||
====================================
|
||||
|
||||
- It is now relatively safe to configure 550 status codes for the
|
||||
|
@@ -222,9 +222,9 @@ mail_owner = postfix
|
||||
# DELIVERY TO MAILBOX
|
||||
#
|
||||
# The home_mailbox parameter specifies the optional pathname of a
|
||||
# mailbox relative to a user's home directory. The default is to
|
||||
# deliver to the UNIX-style /var/spool/mail/user or /var/mail/user.
|
||||
# Specify "Maildir/" for qmail-style delivery (the / is required).
|
||||
# mailbox file relative to a user's home directory. The default
|
||||
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
|
||||
# "Maildir/" for qmail-style delivery (the / is required).
|
||||
#
|
||||
#home_mailbox = Mailbox
|
||||
#home_mailbox = Maildir/
|
||||
@@ -298,12 +298,14 @@ mail_owner = postfix
|
||||
#header_checks = regexp:/etc/postfix/filename
|
||||
#header_checks = pcre:/etc/postfix/filename
|
||||
|
||||
# The relay_domains parameter restricts what domains (and subdomains
|
||||
# thereof) this mail system will relay mail from or to. See the
|
||||
# smtpd_recipient_restrictions restriction in the file sample-smtpd.cf.
|
||||
# The relay_domains parameter restricts what client hostname domains
|
||||
# (and subdomains thereof) this mail system will relay mail from,
|
||||
# and restricts what destination domains (and subdomains thereof)
|
||||
# this system will relay mail to. See the smtpd_recipient_restrictions
|
||||
# restriction in the file sample-smtpd.cf.
|
||||
#
|
||||
# By default, Postfix relays mail only from or to sites in or below
|
||||
# $mydestination, or in the optional virtual domain list.
|
||||
# By default, Postfix relays mail only from clients or to destinations
|
||||
# in or below $mydestination, or in the optional virtual domain list.
|
||||
#
|
||||
# Specify a list of hosts or domains, /file/name patterns or type:name
|
||||
# lookup tables, separated by commas and/or whitespace. Continue
|
||||
|
@@ -66,9 +66,9 @@ default_privs = nobody
|
||||
#
|
||||
|
||||
# The home_mailbox parameter specifies the optional pathname of a
|
||||
# mailbox relative to a user's home directory. The default is to
|
||||
# deliver to the UNIX-style /var/spool/mail/user or /var/mail/user.
|
||||
# Specify "Maildir/" for qmail-style delivery (the / is required).
|
||||
# mailbox file relative to a user's home directory. The default
|
||||
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
|
||||
# "Maildir/" for qmail-style delivery (the / is required).
|
||||
#
|
||||
# home_mailbox = Mailbox
|
||||
# home_mailbox = Maildir/
|
||||
|
@@ -181,7 +181,7 @@ smtpd_sender_restrictions =
|
||||
#
|
||||
# The default is to permit any destination from clients that match
|
||||
# $mynetworks, and to otherwise permit only mail from clients or to
|
||||
# domains that match $relay_domains or a subdomain thereof.
|
||||
# destinations that match $relay_domains or a subdomain thereof.
|
||||
#
|
||||
# The following restrictions are available:
|
||||
#
|
||||
@@ -191,8 +191,8 @@ smtpd_sender_restrictions =
|
||||
# reject_invalid_hostname: reject HELO hostname with bad syntax.
|
||||
# reject_unknown_hostname: reject HELO hostname without DNS A or MX record.
|
||||
# reject_unknown_sender_domain: reject sender domain without A or MX record.
|
||||
# check_relay_domains: permit only mail from/to domains in $relay_domains
|
||||
or to the local machine.
|
||||
# check_relay_domains: permit only mail from clients/to domains matching
|
||||
# $relay_domains, or to the local machine.
|
||||
# permit_auth_destination: permit mail to self or to $relay_domains.
|
||||
# reject_unauth_destination: reject mail not to self or to $relay_domains.
|
||||
# reject_unauth_pipelining: reject mail from improperly pipelining spamware
|
||||
@@ -238,11 +238,13 @@ smtpd_recipient_restrictions = permit_mynetworks,check_relay_domains
|
||||
#
|
||||
maps_rbl_domains = rbl.maps.vix.com
|
||||
|
||||
# The relay_domains parameter restricts what domains (and subdomains
|
||||
# thereof) this mail system will relay mail from or to.
|
||||
# The relay_domains parameter restricts what client hostname domains
|
||||
# (and subdomains thereof) this mail system will relay mail from,
|
||||
# and restricts what destination domains (and subdomains thereof)
|
||||
# this system will relay mail to.
|
||||
#
|
||||
# By default, Postfix relays mail only from or to sites in or below
|
||||
# $mydestination, or in the optional virtual domain list.
|
||||
# By default, Postfix relays mail only from clients or to destinations
|
||||
# in or below $mydestination, or in the optional virtual domain list.
|
||||
#
|
||||
# Specify a list of hosts or domains, /file/name patterns or type:name
|
||||
# lookup tables, separated by commas and/or whitespace. Continue
|
||||
|
@@ -17,6 +17,14 @@
|
||||
/* BH_TABLE *dup_filter;
|
||||
/* char *format;
|
||||
/*
|
||||
/* int been_here_check_fixed(dup_filter, string)
|
||||
/* BH_TABLE *dup_filter;
|
||||
/* char *string;
|
||||
/*
|
||||
/* int been_here_check(dup_filter, format, ...)
|
||||
/* BH_TABLE *dup_filter;
|
||||
/* char *format;
|
||||
/*
|
||||
/* void been_here_free(dup_filter)
|
||||
/* BH_TABLE *dup_filter;
|
||||
/* DESCRIPTION
|
||||
@@ -34,6 +42,9 @@
|
||||
/* not found. The result is non-zero (true) if the formatted result was
|
||||
/* found, zero (false) otherwise.
|
||||
/*
|
||||
/* been_here_check_fixed() and been_here_check() are similar
|
||||
/* but do not update the duplicate filter.
|
||||
/*
|
||||
/* been_here_free() releases storage for a duplicate filter.
|
||||
/*
|
||||
/* Arguments:
|
||||
@@ -173,3 +184,65 @@ int been_here_fixed(BH_TABLE *dup_filter, const char *string)
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* been_here_check - query duplicate detector with finer control */
|
||||
|
||||
int been_here_check(BH_TABLE *dup_filter, const char *fmt,...)
|
||||
{
|
||||
VSTRING *buf = vstring_alloc(100);
|
||||
int status;
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* Construct the string to be checked.
|
||||
*/
|
||||
va_start(ap, fmt);
|
||||
vstring_vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* Do the duplicate check.
|
||||
*/
|
||||
status = been_here_check_fixed(dup_filter, vstring_str(buf));
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
vstring_free(buf);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* been_here_check_fixed - query duplicate detector */
|
||||
|
||||
int been_here_check_fixed(BH_TABLE *dup_filter, const char *string)
|
||||
{
|
||||
char *folded_string;
|
||||
const char *lookup_key;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Special processing: case insensitive lookup.
|
||||
*/
|
||||
if (dup_filter->flags & BH_FLAG_FOLD) {
|
||||
folded_string = mystrdup(string);
|
||||
lookup_key = lowercase(folded_string);
|
||||
} else {
|
||||
folded_string = 0;
|
||||
lookup_key = string;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the duplicate check.
|
||||
*/
|
||||
status = (htable_locate(dup_filter->table, lookup_key) != 0);
|
||||
if (msg_verbose)
|
||||
msg_info("been_here_check: %s: %d", string, status);
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
if (folded_string)
|
||||
myfree(folded_string);
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
@@ -32,6 +32,8 @@ extern BH_TABLE *been_here_init(int, int);
|
||||
extern void been_here_free(BH_TABLE *);
|
||||
extern int been_here_fixed(BH_TABLE *, const char *);
|
||||
extern int been_here(BH_TABLE *, const char *,...);
|
||||
extern int been_here_check_fixed(BH_TABLE *, const char *);
|
||||
extern int been_here_check(BH_TABLE *, const char *,...);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-19991207"
|
||||
#define DEF_MAIL_VERSION "Snapshot-19991209"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@@ -9,7 +9,7 @@ POSTALIAS(1) POSTALIAS(1)
|
||||
postalias - Postfix alias database maintenance
|
||||
|
||||
<b>SYNOPSIS</b>
|
||||
<b>postalias</b> [<b>-ivw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
||||
<b>postalias</b> [<b>-Ninvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
||||
[<i>file_type</i>:]<i>file_name</i> ...
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
@@ -26,15 +26,25 @@ POSTALIAS(1) POSTALIAS(1)
|
||||
|
||||
Options:
|
||||
|
||||
<b>-N</b> Include the terminating null character that termi-
|
||||
nates lookup keys and values. By default, Postfix
|
||||
does whatever is the default for the host operating
|
||||
system.
|
||||
|
||||
<b>-c</b> <i>config_dir</i>
|
||||
Read the <b>main.cf</b> configuration file in the named
|
||||
Read the <b>main.cf</b> configuration file in the named
|
||||
directory.
|
||||
|
||||
<b>-i</b> Incremental mode. Read entries from standard input
|
||||
<b>-i</b> Incremental mode. Read entries from standard input
|
||||
and do not truncate an existing database. By
|
||||
default, <b>postalias</b> creates a new database from the
|
||||
default, <b>postalias</b> creates a new database from the
|
||||
entries in <b>file</b><i>_</i><b>name</b>.
|
||||
|
||||
<b>-n</b> Don't include the terminating null character that
|
||||
terminates lookup keys and values. By default,
|
||||
Postfix does whatever is the default for the host
|
||||
operating system.
|
||||
|
||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
||||
first value found on the standard output stream.
|
||||
The exit status is non-zero if the requested infor-
|
||||
@@ -49,16 +59,6 @@ POSTALIAS(1) POSTALIAS(1)
|
||||
|
||||
Arguments:
|
||||
|
||||
<i>file_type</i>
|
||||
The type of database to be produced.
|
||||
|
||||
<b>btree</b> The output is a btree file, named
|
||||
<i>file_name</i><b>.db</b>. This is available only on
|
||||
systems with support for <b>db</b> databases.
|
||||
|
||||
<b>dbm</b> The output consists of two files, named
|
||||
<i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
|
||||
available only on systems with support for
|
||||
|
||||
|
||||
|
||||
@@ -71,6 +71,16 @@ POSTALIAS(1) POSTALIAS(1)
|
||||
POSTALIAS(1) POSTALIAS(1)
|
||||
|
||||
|
||||
<i>file_type</i>
|
||||
The type of database to be produced.
|
||||
|
||||
<b>btree</b> The output is a btree file, named
|
||||
<i>file_name</i><b>.db</b>. This is available only on
|
||||
systems with support for <b>db</b> databases.
|
||||
|
||||
<b>dbm</b> The output consists of two files, named
|
||||
<i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
|
||||
available only on systems with support for
|
||||
<b>dbm</b> databases.
|
||||
|
||||
<b>hash</b> The output is a hashed file, named
|
||||
@@ -114,6 +124,19 @@ POSTALIAS(1) POSTALIAS(1)
|
||||
<a href="aliases.5.html">aliases(5)</a> format of alias database input file.
|
||||
<a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
POSTALIAS(1) POSTALIAS(1)
|
||||
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
@@ -128,7 +151,50 @@ POSTALIAS(1) POSTALIAS(1)
|
||||
|
||||
|
||||
|
||||
2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3
|
||||
|
||||
|
||||
</pre> </body> </html>
|
||||
|
@@ -9,7 +9,7 @@ POSTMAP(1) POSTMAP(1)
|
||||
postmap - Postfix lookup table management
|
||||
|
||||
<b>SYNOPSIS</b>
|
||||
<b>postmap</b> [<b>-ivw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
||||
<b>postmap</b> [<b>-Ninvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
||||
[<i>file_type</i>:]<i>file_name</i> ...
|
||||
|
||||
<b>DESCRIPTION</b>
|
||||
@@ -45,20 +45,20 @@ POSTMAP(1) POSTMAP(1)
|
||||
|
||||
Options:
|
||||
|
||||
<b>-N</b> Include the terminating null character that termi-
|
||||
nates lookup keys and values. By default, Postfix
|
||||
does whatever is the default for the host operating
|
||||
system.
|
||||
|
||||
<b>-c</b> <i>config_dir</i>
|
||||
Read the <b>main.cf</b> configuration file in the named
|
||||
Read the <b>main.cf</b> configuration file in the named
|
||||
directory.
|
||||
|
||||
<b>-i</b> Incremental mode. Read entries from standard input
|
||||
<b>-i</b> Incremental mode. Read entries from standard input
|
||||
and do not truncate an existing database. By
|
||||
default, <b>postmap</b> creates a new database from the
|
||||
default, <b>postmap</b> creates a new database from the
|
||||
entries in <b>file</b><i>_</i><b>name</b>.
|
||||
|
||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
||||
first value found on the standard output stream.
|
||||
The exit status is non-zero if the requested infor-
|
||||
mation was not found.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -71,6 +71,16 @@ POSTMAP(1) POSTMAP(1)
|
||||
POSTMAP(1) POSTMAP(1)
|
||||
|
||||
|
||||
<b>-n</b> Don't include the terminating null character that
|
||||
terminates lookup keys and values. By default,
|
||||
Postfix does whatever is the default for the host
|
||||
operating system.
|
||||
|
||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
||||
first value found on the standard output stream.
|
||||
The exit status is non-zero if the requested infor-
|
||||
mation was not found.
|
||||
|
||||
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
|
||||
tiple <b>-v</b> options make the software increasingly
|
||||
verbose.
|
||||
@@ -116,16 +126,6 @@ POSTMAP(1) POSTMAP(1)
|
||||
<b>MAIL</b><i>_</i><b>VERBOSE</b>
|
||||
Enable verbose logging for debugging purposes.
|
||||
|
||||
<b>CONFIGURATION</b> <b>PARAMETERS</b>
|
||||
<b>database</b><i>_</i><b>type</b>
|
||||
Default output database type. On many UNIX sys-
|
||||
tems, the default database type is either <b>hash</b> or
|
||||
<b>dbm</b>.
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
|
||||
|
||||
2
|
||||
@@ -137,6 +137,16 @@ POSTMAP(1) POSTMAP(1)
|
||||
POSTMAP(1) POSTMAP(1)
|
||||
|
||||
|
||||
<b>CONFIGURATION</b> <b>PARAMETERS</b>
|
||||
<b>database</b><i>_</i><b>type</b>
|
||||
Default output database type. On many UNIX sys-
|
||||
tems, the default database type is either <b>hash</b> or
|
||||
<b>dbm</b>.
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
<b>AUTHOR(S)</b>
|
||||
Wietse Venema
|
||||
IBM T.J. Watson Research
|
||||
@@ -173,16 +183,6 @@ POSTMAP(1) POSTMAP(1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -550,7 +550,7 @@ specifies the response code for rejected requests (default:
|
||||
|
||||
<dt> <b>permit_auth_destination</b> <dd> Ignore the client hostname.
|
||||
Permit the request when the resolved destination address matches
|
||||
the <a href="basic.html#mydestination">$mydestination</a>, the
|
||||
<a href="basic.html#mydestination">$mydestination</a>, the
|
||||
machine IP addresses, or <a href="#relay_domains"> $relay_domains</a>.
|
||||
|
||||
<p>
|
||||
|
@@ -213,27 +213,31 @@ int deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
|
||||
* If this user includes (an alias of) herself in her own .forward file,
|
||||
* deliver to the user instead.
|
||||
*/
|
||||
if (lookup_status >= 0
|
||||
&& been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
|
||||
state.msg_attr.exp_from = state.msg_attr.local;
|
||||
if (S_ISREG(st.st_mode) == 0) {
|
||||
msg_warn("file %s is not a regular file", STR(path));
|
||||
} else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
|
||||
msg_warn("file %s has bad owner uid %d", STR(path), st.st_uid);
|
||||
} else if (st.st_mode & 002) {
|
||||
msg_warn("file %s is world writable", STR(path));
|
||||
} else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
|
||||
msg_warn("cannot open file %s: %m", STR(path));
|
||||
} else {
|
||||
close_on_exec(fd, CLOSE_ON_EXEC);
|
||||
addr_count = 0;
|
||||
fp = vstream_fdopen(fd, O_RDONLY);
|
||||
status = deliver_token_stream(state, usr_attr, fp, &addr_count);
|
||||
if (vstream_fclose(fp))
|
||||
msg_warn("close file %s: %m", STR(path));
|
||||
if (addr_count > 0)
|
||||
forward_found = YES;
|
||||
}
|
||||
if (lookup_status >= 0) {
|
||||
if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
|
||||
state.msg_attr.exp_from = state.msg_attr.local;
|
||||
if (S_ISREG(st.st_mode) == 0) {
|
||||
msg_warn("file %s is not a regular file", STR(path));
|
||||
} else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
|
||||
msg_warn("file %s has bad owner uid %d", STR(path), st.st_uid);
|
||||
} else if (st.st_mode & 002) {
|
||||
msg_warn("file %s is world writable", STR(path));
|
||||
} else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
|
||||
msg_warn("cannot open file %s: %m", STR(path));
|
||||
} else {
|
||||
close_on_exec(fd, CLOSE_ON_EXEC);
|
||||
addr_count = 0;
|
||||
fp = vstream_fdopen(fd, O_RDONLY);
|
||||
status = deliver_token_stream(state, usr_attr, fp, &addr_count);
|
||||
if (vstream_fclose(fp))
|
||||
msg_warn("close file %s: %m", STR(path));
|
||||
if (addr_count > 0) {
|
||||
forward_found = YES;
|
||||
been_here(state.dup_filter, "forward-done %s", STR(path));
|
||||
}
|
||||
}
|
||||
} else if (been_here_check(state.dup_filter, "forward-done %s", STR(path)) != 0)
|
||||
forward_found = YES; /* else we're recursive */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -177,9 +177,7 @@ int deliver_token_string(LOCAL_STATE state, USER_ATTR usr_attr,
|
||||
if (addr->type == TOK822_ADDR) {
|
||||
if (addr_count)
|
||||
(*addr_count)++;
|
||||
status = deliver_token(state, usr_attr, addr);
|
||||
if (status != 0)
|
||||
break;
|
||||
status |= deliver_token(state, usr_attr, addr);
|
||||
}
|
||||
}
|
||||
tok822_free_tree(tree);
|
||||
|
@@ -9,8 +9,8 @@ Postfix alias database maintenance
|
||||
.na
|
||||
.nf
|
||||
.fi
|
||||
\fBpostalias\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||
[\fIfile_type\fR:]\fIfile_name\fR ...
|
||||
\fBpostalias\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR]
|
||||
[\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||
.SH DESCRIPTION
|
||||
.ad
|
||||
.fi
|
||||
@@ -25,12 +25,20 @@ entire database, in order to avoid surprises in spectator
|
||||
programs.
|
||||
|
||||
Options:
|
||||
.IP \fB-N\fR
|
||||
Include the terminating null character that terminates lookup keys
|
||||
and values. By default, Postfix does whatever is the default for
|
||||
the host operating system.
|
||||
.IP "\fB-c \fIconfig_dir\fR"
|
||||
Read the \fBmain.cf\fR configuration file in the named directory.
|
||||
.IP \fB-i\fR
|
||||
Incremental mode. Read entries from standard input and do not
|
||||
truncate an existing database. By default, \fBpostalias\fR creates
|
||||
a new database from the entries in \fBfile_name\fR.
|
||||
.IP \fB-n\fR
|
||||
Don't include the terminating null character that terminates lookup
|
||||
keys and values. By default, Postfix does whatever is the default for
|
||||
the host operating system.
|
||||
.IP "\fB-q \fIkey\fR"
|
||||
Search the specified maps for \fIkey\fR and print the first value
|
||||
found on the standard output stream. The exit status is non-zero
|
||||
|
@@ -9,7 +9,7 @@ Postfix lookup table management
|
||||
.na
|
||||
.nf
|
||||
.fi
|
||||
\fBpostmap\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||
\fBpostmap\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||
[\fIfile_type\fR:]\fIfile_name\fR ...
|
||||
.SH DESCRIPTION
|
||||
.ad
|
||||
@@ -44,12 +44,20 @@ special characters such as `#' or whitespace. The \fIkey\fR is mapped
|
||||
to lowercase to make mapping lookups case insensitive.
|
||||
|
||||
Options:
|
||||
.IP \fB-N\fR
|
||||
Include the terminating null character that terminates lookup keys
|
||||
and values. By default, Postfix does whatever is the default for
|
||||
the host operating system.
|
||||
.IP "\fB-c \fIconfig_dir\fR"
|
||||
Read the \fBmain.cf\fR configuration file in the named directory.
|
||||
.IP \fB-i\fR
|
||||
Incremental mode. Read entries from standard input and do not
|
||||
truncate an existing database. By default, \fBpostmap\fR creates
|
||||
a new database from the entries in \fBfile_name\fR.
|
||||
.IP \fB-n\fR
|
||||
Don't include the terminating null character that terminates lookup
|
||||
keys and values. By default, Postfix does whatever is the default for
|
||||
the host operating system.
|
||||
.IP "\fB-q \fIkey\fR"
|
||||
Search the specified maps for \fIkey\fR and print the first value
|
||||
found on the standard output stream. The exit status is non-zero
|
||||
|
@@ -5,8 +5,8 @@
|
||||
/* Postfix alias database maintenance
|
||||
/* SYNOPSIS
|
||||
/* .fi
|
||||
/* \fBpostalias\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||
/* [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||
/* \fBpostalias\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR]
|
||||
/* [\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||
/* DESCRIPTION
|
||||
/* The \fBpostalias\fR command creates or queries one or more Postfix
|
||||
/* alias databases, or updates an existing one. The input and output
|
||||
@@ -19,12 +19,20 @@
|
||||
/* programs.
|
||||
/*
|
||||
/* Options:
|
||||
/* .IP \fB-N\fR
|
||||
/* Include the terminating null character that terminates lookup keys
|
||||
/* and values. By default, Postfix does whatever is the default for
|
||||
/* the host operating system.
|
||||
/* .IP "\fB-c \fIconfig_dir\fR"
|
||||
/* Read the \fBmain.cf\fR configuration file in the named directory.
|
||||
/* .IP \fB-i\fR
|
||||
/* Incremental mode. Read entries from standard input and do not
|
||||
/* truncate an existing database. By default, \fBpostalias\fR creates
|
||||
/* a new database from the entries in \fBfile_name\fR.
|
||||
/* .IP \fB-n\fR
|
||||
/* Don't include the terminating null character that terminates lookup
|
||||
/* keys and values. By default, Postfix does whatever is the default for
|
||||
/* the host operating system.
|
||||
/* .IP "\fB-q \fIkey\fR"
|
||||
/* Search the specified maps for \fIkey\fR and print the first value
|
||||
/* found on the standard output stream. The exit status is non-zero
|
||||
@@ -297,7 +305,7 @@ static int postalias_query(const char *map_type, const char *map_name,
|
||||
|
||||
static NORETURN usage(char *myname)
|
||||
{
|
||||
msg_fatal("usage: %s [-ivw] [-c config_dir] [-q key] [map_type:]file...",
|
||||
msg_fatal("usage: %s [-Ninvw] [-c config_dir] [-q key] [map_type:]file...",
|
||||
myname);
|
||||
}
|
||||
|
||||
@@ -346,11 +354,15 @@ int main(int argc, char **argv)
|
||||
/*
|
||||
* Parse JCL.
|
||||
*/
|
||||
while ((ch = GETOPT(argc, argv, "c:iq:vw")) > 0) {
|
||||
while ((ch = GETOPT(argc, argv, "Nc:inq:vw")) > 0) {
|
||||
switch (ch) {
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
case 'N':
|
||||
dict_flags |= DICT_FLAG_TRY1NULL;
|
||||
dict_flags &= ~DICT_FLAG_TRY0NULL;
|
||||
break;
|
||||
case 'c':
|
||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||
msg_fatal("out of memory");
|
||||
@@ -358,6 +370,10 @@ int main(int argc, char **argv)
|
||||
case 'i':
|
||||
open_flags &= ~O_TRUNC;
|
||||
break;
|
||||
case 'n':
|
||||
dict_flags |= DICT_FLAG_TRY0NULL;
|
||||
dict_flags &= ~DICT_FLAG_TRY1NULL;
|
||||
break;
|
||||
case 'q':
|
||||
query = optarg;
|
||||
break;
|
||||
|
@@ -638,6 +638,9 @@ int main(int argc, char **argv)
|
||||
struct stat st;
|
||||
int junk;
|
||||
|
||||
/*
|
||||
* Be consistent with file permissions.
|
||||
*/
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
|
@@ -5,7 +5,7 @@
|
||||
/* Postfix lookup table management
|
||||
/* SYNOPSIS
|
||||
/* .fi
|
||||
/* \fBpostmap\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||
/* \fBpostmap\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||
/* [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||
/* DESCRIPTION
|
||||
/* The \fBpostmap\fR command creates or queries one or more Postfix
|
||||
@@ -38,12 +38,20 @@
|
||||
/* to lowercase to make mapping lookups case insensitive.
|
||||
/*
|
||||
/* Options:
|
||||
/* .IP \fB-N\fR
|
||||
/* Include the terminating null character that terminates lookup keys
|
||||
/* and values. By default, Postfix does whatever is the default for
|
||||
/* the host operating system.
|
||||
/* .IP "\fB-c \fIconfig_dir\fR"
|
||||
/* Read the \fBmain.cf\fR configuration file in the named directory.
|
||||
/* .IP \fB-i\fR
|
||||
/* Incremental mode. Read entries from standard input and do not
|
||||
/* truncate an existing database. By default, \fBpostmap\fR creates
|
||||
/* a new database from the entries in \fBfile_name\fR.
|
||||
/* .IP \fB-n\fR
|
||||
/* Don't include the terminating null character that terminates lookup
|
||||
/* keys and values. By default, Postfix does whatever is the default for
|
||||
/* the host operating system.
|
||||
/* .IP "\fB-q \fIkey\fR"
|
||||
/* Search the specified maps for \fIkey\fR and print the first value
|
||||
/* found on the standard output stream. The exit status is non-zero
|
||||
@@ -251,7 +259,7 @@ static int postmap_query(const char *map_type, const char *map_name,
|
||||
|
||||
static NORETURN usage(char *myname)
|
||||
{
|
||||
msg_fatal("usage: %s [-ivw] [-c config_dir] [-q key] [map_type:]file...",
|
||||
msg_fatal("usage: %s [-Ninvw] [-c config_dir] [-q key] [map_type:]file...",
|
||||
myname);
|
||||
}
|
||||
|
||||
@@ -300,11 +308,15 @@ int main(int argc, char **argv)
|
||||
/*
|
||||
* Parse JCL.
|
||||
*/
|
||||
while ((ch = GETOPT(argc, argv, "c:iq:vw")) > 0) {
|
||||
while ((ch = GETOPT(argc, argv, "Nc:inq:vw")) > 0) {
|
||||
switch (ch) {
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
case 'N':
|
||||
dict_flags |= DICT_FLAG_TRY1NULL;
|
||||
dict_flags &= ~DICT_FLAG_TRY0NULL;
|
||||
break;
|
||||
case 'c':
|
||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||
msg_fatal("out of memory");
|
||||
@@ -312,6 +324,10 @@ int main(int argc, char **argv)
|
||||
case 'i':
|
||||
open_flags &= ~O_TRUNC;
|
||||
break;
|
||||
case 'n':
|
||||
dict_flags |= DICT_FLAG_TRY0NULL;
|
||||
dict_flags &= ~DICT_FLAG_TRY1NULL;
|
||||
break;
|
||||
case 'q':
|
||||
query = optarg;
|
||||
break;
|
||||
|
@@ -137,7 +137,7 @@ void qmgr_entry_done(QMGR_ENTRY *entry, int which)
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the recipient list and decrease in-core recipient count
|
||||
* Free the recipient list and decrease the in-core recipient count
|
||||
* accordingly.
|
||||
*/
|
||||
qmgr_recipient_count -= entry->rcpt_list.len;
|
||||
@@ -160,10 +160,11 @@ void qmgr_entry_done(QMGR_ENTRY *entry, int which)
|
||||
|
||||
/*
|
||||
* Update the in-core message reference count. When the in-core message
|
||||
* structure has no more references, dispose of the message. When the
|
||||
* in-core recipient count falls below some threshold and this message
|
||||
* has more recipients, read them from disk before concurrency starts to
|
||||
* drop.
|
||||
* structure has no more references, dispose of the message.
|
||||
*
|
||||
* When the in-core recipient count falls below some threshold and this
|
||||
* message has more recipients, read more recipients before concurrency
|
||||
* starts to drop.
|
||||
*/
|
||||
message->refcount--;
|
||||
if (message->refcount == 0)
|
||||
|
@@ -222,6 +222,17 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
* may appear before or after the message content, so we keep reading
|
||||
* from the queue file until we have enough recipients (rcpt_offset != 0)
|
||||
* and until we know where the message content starts (data_offset != 0).
|
||||
*
|
||||
* When reading recipients from queue file, stop reading when we reach a
|
||||
* per-message in-core recipient limit rather than a global in-core
|
||||
* recipient limit. Use the global recipient limit only in order to stop
|
||||
* opening queue files. The purpose is to achieve equal delay for
|
||||
* messages with recipient counts up to var_qmgr_rcpt_limit recipients.
|
||||
*
|
||||
* If we would read recipients up to a global recipient limit, the average
|
||||
* number of in-core recipients per message would asymptotically approach
|
||||
* (global recipient limit)/(active queue size limit), which gives equal
|
||||
* delay per recipient rather than equal delay per message.
|
||||
*/
|
||||
do {
|
||||
if ((curr_offset = vstream_ftell(message->fp)) < 0)
|
||||
@@ -241,10 +252,9 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
message->data_size, "queue %s", message->queue_name);
|
||||
}
|
||||
} else if (rec_type == REC_TYPE_RCPT) {
|
||||
#define TOTAL_RECIPIENT_COUNT (qmgr_recipient_count + message->rcpt_list.len)
|
||||
if (TOTAL_RECIPIENT_COUNT < var_qmgr_rcpt_limit) {
|
||||
if (message->rcpt_list.len < var_qmgr_rcpt_limit) {
|
||||
qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start);
|
||||
if (TOTAL_RECIPIENT_COUNT >= var_qmgr_rcpt_limit) {
|
||||
if (message->rcpt_list.len >= var_qmgr_rcpt_limit) {
|
||||
if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
|
||||
msg_fatal("vstream_ftell %s: %m",
|
||||
VSTREAM_PATH(message->fp));
|
||||
|
@@ -224,20 +224,39 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
escaped_name = vstring_alloc(20);
|
||||
filter_buf = vstring_alloc(30);
|
||||
|
||||
/* Any wildcards and escapes in the supplied address should be escaped. */
|
||||
if (strchr(name, '*') || strchr(name, '\\')) {
|
||||
/*
|
||||
* If any characters in the supplied address should be escaped per RFC
|
||||
* 2254, do so.
|
||||
*/
|
||||
|
||||
end = (char *) name + strlen((char *) name);
|
||||
sub = (char *) strpbrk((char *) name, "*()\\\0");
|
||||
if (sub && sub != end) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: found wildcard in %s", myname, name);
|
||||
for (sub = (char *) name; *sub != '\0'; sub++) {
|
||||
if (*sub == '*' || *sub == '\\') {
|
||||
vstring_strncat(escaped_name, "\\", 1);
|
||||
vstring_strncat(escaped_name, sub, 1);
|
||||
} else {
|
||||
msg_info("%s: found character(s) in %s that must be escaped", myname, name);
|
||||
for (sub = (char *) name; sub != end; sub++) {
|
||||
switch (*sub) {
|
||||
case '*':
|
||||
vstring_strcat(escaped_name, "\\2a");
|
||||
break;
|
||||
case '(':
|
||||
vstring_strcat(escaped_name, "\\28");
|
||||
break;
|
||||
case ')':
|
||||
vstring_strcat(escaped_name, "\\29");
|
||||
break;
|
||||
case '\\':
|
||||
vstring_strcat(escaped_name, "\\5c");
|
||||
break;
|
||||
case '\0':
|
||||
vstring_strcat(escaped_name, "\\00");
|
||||
break;
|
||||
default:
|
||||
vstring_strncat(escaped_name, sub, 1);
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: with wildcards escaped, it's %s", myname, vstring_str(escaped_name));
|
||||
msg_info("%s: after escaping, it's %s", myname, vstring_str(escaped_name));
|
||||
} else
|
||||
vstring_strcpy(escaped_name, (char *) name);
|
||||
|
||||
|
@@ -12,11 +12,19 @@
|
||||
/* int dummy;
|
||||
/* int unused_dict_flags;
|
||||
/* DESCRIPTION
|
||||
/* dict_mysql_open() opens the mysql databases with name dbname on
|
||||
/* each host in hostlist and registers under the given name with the
|
||||
/* dictionary manager. The result is a pointer to the installed dictionary,
|
||||
/* dict_mysql_open() creates a dictionary of type 'mysql'. This
|
||||
/* dictionary is an interface for the postfix key->value mappings
|
||||
/* to mysql. The result is a pointer to the installed dictionary,
|
||||
/* or a null pointer in case of problems.
|
||||
/*
|
||||
/* The mysql dictionary can manage multiple connections to different
|
||||
/* sql servers on different hosts. It assumes that the underlying data
|
||||
/* on each host is identical (mirrored) and maintains one connection
|
||||
/* at any given time. If any connection fails, any other available
|
||||
/* ones will be opened and used. The intent of this feature is to eliminate
|
||||
/* a single point of failure for mail systems that would otherwise rely
|
||||
/* on a single mysql server.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP name
|
||||
/* The path of the MySQL configuration file. The file encodes a number of
|
||||
@@ -70,8 +78,24 @@
|
||||
#include "argv.h"
|
||||
#include "vstring.h"
|
||||
|
||||
/* external declarations */
|
||||
extern int dict_errno;
|
||||
|
||||
/* need some structs to help organize things */
|
||||
typedef struct {
|
||||
MYSQL db;
|
||||
char *hostname;
|
||||
int stat; /* STATUNTRIED | STATFAIL | STATCUR */
|
||||
time_t ts; /* used for attempting reconnection
|
||||
* every so often if a host is down */
|
||||
} HOST;
|
||||
|
||||
typedef struct {
|
||||
int len_hosts; /* number of hosts */
|
||||
HOST *db_hosts; /* the hosts on which the databases
|
||||
* reside */
|
||||
} PLMYSQL;
|
||||
|
||||
typedef struct {
|
||||
char *username;
|
||||
char *password;
|
||||
@@ -90,114 +114,38 @@ typedef struct {
|
||||
MYSQL_NAME *name;
|
||||
} DICT_MYSQL;
|
||||
|
||||
/* mysqlname_parse - parse mysql configuration file */
|
||||
/* internal function declarations */
|
||||
static PLMYSQL *plmysql_init(char *hostnames[], int);
|
||||
static MYSQL_RES *plmysql_query(PLMYSQL *, const char *, char *, char *, char *);
|
||||
static void plmysql_dealloc(PLMYSQL *);
|
||||
static void plmysql_down_host(HOST *);
|
||||
static void plmysql_connect_single(HOST *, char *, char *, char *);
|
||||
static int plmysql_ready_reconn(HOST);
|
||||
static void dict_mysql_update(DICT *, const char *, const char *);
|
||||
static const char *dict_mysql_lookup(DICT *, const char *);
|
||||
DICT *dict_mysql_open(const char *, int, int);
|
||||
static void dict_mysql_close(DICT *);
|
||||
static MYSQL_NAME *mysqlname_parse(const char *);
|
||||
static HOST host_init(char *);
|
||||
|
||||
static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
||||
{
|
||||
int i;
|
||||
char *nameval;
|
||||
char *hosts;
|
||||
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||
ARGV *hosts_argv;
|
||||
|
||||
dict_load_file("mysql_options", mysqlcf_path);
|
||||
/* mysql username lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "user")) == NULL)
|
||||
name->username = mystrdup("");
|
||||
else
|
||||
name->username = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("dict_mysql_parse: set username to '%s'", name->username);
|
||||
/* password lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "password")) == NULL)
|
||||
name->password = mystrdup("");
|
||||
else
|
||||
name->password = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("dict_mysql_parse: set password to '%s'", name->password);
|
||||
|
||||
/* database name lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "dbname")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
|
||||
else
|
||||
name->dbname = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysql_name_parse: set database name to '%s'", name->dbname);
|
||||
|
||||
/* table lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "table")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
|
||||
else
|
||||
name->table = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysql_name_parse: set table name to '%s'", name->table);
|
||||
|
||||
/* select field lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "select_field")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
|
||||
else
|
||||
name->select_field = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysql_name_parse: set select_field to '%s'", name->select_field);
|
||||
|
||||
/* where field lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "where_field")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
|
||||
else
|
||||
name->where_field = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysql_name_parse: set where_field to '%s'", name->where_field);
|
||||
|
||||
/* additional conditions */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "additional_conditions")) == NULL)
|
||||
name->additional_conditions = mystrdup("");
|
||||
else
|
||||
name->additional_conditions = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysql_name_parse: set additional_conditions to '%s'", name->additional_conditions);
|
||||
|
||||
/* mysql server hosts */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "hosts")) == NULL)
|
||||
hosts = mystrdup("");
|
||||
else
|
||||
hosts = mystrdup(nameval);
|
||||
/* coo argv interface */
|
||||
hosts_argv = argv_split(hosts, " ");
|
||||
argv_terminate(hosts_argv);
|
||||
|
||||
if (hosts_argv->argc == 0) { /* no hosts specified,
|
||||
* default to 'localhost' */
|
||||
msg_info("mysql_name_parse: no hostnames specified, defaulting to 'localhost'");
|
||||
name->len_hosts = 1;
|
||||
name->hostnames = (char **) mymalloc(sizeof(char *));
|
||||
name->hostnames[0] = mystrdup("localhost");
|
||||
} else {
|
||||
name->len_hosts = hosts_argv->argc;
|
||||
name->hostnames = (char **) mymalloc((sizeof(char *)) * name->len_hosts);
|
||||
i = 0;
|
||||
for (i = 0; hosts_argv->argv[i] != NULL; i++) {
|
||||
name->hostnames[i] = mystrdup(hosts_argv->argv[i]);
|
||||
if (msg_verbose)
|
||||
msg_info("adding host '%s' to list of mysql server hosts", name->hostnames[i]);
|
||||
}
|
||||
}
|
||||
myfree(hosts);
|
||||
argv_free(hosts_argv);
|
||||
return name;
|
||||
}
|
||||
|
||||
/* dict_mysql_lookup - find database entry return 0 if no alias found */
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_lookup
|
||||
* find database entry return 0 if no alias found, set dict_errno
|
||||
* on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
|
||||
*********************************************************************/
|
||||
static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
||||
{
|
||||
MYSQL_RES *query_res;
|
||||
MYSQL_ROW row;
|
||||
int i,
|
||||
numrows;
|
||||
static VSTRING *result;
|
||||
static VSTRING *query = 0;
|
||||
char *name_escaped = 0;
|
||||
DICT_MYSQL *dict_mysql;
|
||||
PLMYSQL *pldb;
|
||||
static VSTRING *result;
|
||||
static VSTRING *query = 0;
|
||||
int i,
|
||||
numrows;
|
||||
char *name_escaped = 0;
|
||||
|
||||
dict_mysql = (DICT_MYSQL *) dict;
|
||||
pldb = dict_mysql->pldb;
|
||||
@@ -216,8 +164,12 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
||||
msg_info("dict_mysql_lookup using sql query: %s", vstring_str(query));
|
||||
/* free mem associated with preparing the query */
|
||||
myfree(name_escaped);
|
||||
/* do the query */
|
||||
if ((query_res = plmysql_query(pldb, vstring_str(query))) == NULL) {
|
||||
/* do the query - set dict_errno & cleanup if there's an error */
|
||||
if ((query_res = plmysql_query(pldb,
|
||||
vstring_str(query),
|
||||
dict_mysql->name->dbname,
|
||||
dict_mysql->name->username,
|
||||
dict_mysql->name->password)) == 0) {
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
vstring_free(query);
|
||||
return 0;
|
||||
@@ -247,7 +199,303 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
||||
return vstring_str(result);
|
||||
}
|
||||
|
||||
/* dict_mysql_close - unregister, disassociate from database */
|
||||
/*
|
||||
* plmysql_query - process a MySQL query. Return MYSQL_RES* on success.
|
||||
* On failure, log failure and try other db instances.
|
||||
* on failure of all db instances, return 0;
|
||||
* close unnecessary active connections
|
||||
*/
|
||||
|
||||
static MYSQL_RES *plmysql_query(PLMYSQL *PLDB,
|
||||
const char *query,
|
||||
char *dbname,
|
||||
char *username,
|
||||
char *password)
|
||||
{
|
||||
int i;
|
||||
HOST *host;
|
||||
MYSQL_RES *res = 0;
|
||||
|
||||
for (i = 0; i < PLDB->len_hosts; i++) {
|
||||
/* can't deal with typing or reading PLDB->db_hosts[i] over & over */
|
||||
host = &(PLDB->db_hosts[i]);
|
||||
if (msg_verbose > 1)
|
||||
msg_info("dict_mysql: trying host %s stat %d, last res %p", host->hostname, host->stat, res);
|
||||
|
||||
/* answer already found */
|
||||
if (res != 0 && host->stat == STATACTIVE) {
|
||||
msg_info("dict_mysql: closing unnessary connection to %s", host->hostname);
|
||||
mysql_close(&(host->db)); /* also frees memory, have to
|
||||
* reallocate it */
|
||||
host->db = *((MYSQL *) mymalloc(sizeof(MYSQL)));
|
||||
plmysql_down_host(host);
|
||||
}
|
||||
/* try to connect for the first time if we don't have a result yet */
|
||||
if (res == 0 && host->stat == STATUNTRIED) {
|
||||
msg_info("dict_mysql: attempting to connect to host %s", host->hostname);
|
||||
plmysql_connect_single(host, dbname, username, password);
|
||||
}
|
||||
|
||||
/*
|
||||
* try to reconnect if we don't have an answer and the host had a
|
||||
* prob in the past and it's time for it to reconnect
|
||||
*/
|
||||
if (res == 0 && host->stat == STATFAIL && (plmysql_ready_reconn(*host))) {
|
||||
msg_warn("dict_mysql: attempting to reconnect to host %s", host->hostname);
|
||||
plmysql_connect_single(host, dbname, username, password);
|
||||
}
|
||||
|
||||
/*
|
||||
* if we don't have a result and the current host is marked active,
|
||||
* try the query. If the query fails, mark the host STATFAIL
|
||||
*/
|
||||
if (res == 0 && host->stat == STATACTIVE) {
|
||||
if (!(mysql_query(&(host->db), query))) {
|
||||
if ((res = mysql_store_result(&(host->db))) == 0) {
|
||||
msg_warn("%s", mysql_error(&(host->db)));
|
||||
plmysql_down_host(host);
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("dict_mysql: successful query from host %s", host->hostname);
|
||||
}
|
||||
} else {
|
||||
msg_warn("%s", mysql_error(&(host->db)));
|
||||
plmysql_down_host(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* plmysql_connect_single -
|
||||
* used to reconnect to a single database when one is down or none is
|
||||
* connected yet. Log all errors and set the stat field of host accordingly
|
||||
*/
|
||||
static void plmysql_connect_single(HOST *host, char *dbname, char *username, char *password)
|
||||
{
|
||||
if (mysql_connect(&(host->db), host->hostname, username, password)) {
|
||||
if (mysql_select_db(&(host->db), dbname) == 0) {
|
||||
msg_info("dict_mysql: successful connection to host %s", host->hostname);
|
||||
host->stat = STATACTIVE;
|
||||
} else {
|
||||
plmysql_down_host(host);
|
||||
msg_warn("%s", mysql_error(&(host->db)));
|
||||
}
|
||||
} else {
|
||||
plmysql_down_host(host);
|
||||
msg_warn("%s", mysql_error(&(host->db)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* plmysql_down_host - mark a HOST down update ts if marked down
|
||||
* for the first time so that we'll know when to retry the connection
|
||||
*/
|
||||
static void plmysql_down_host(HOST *host)
|
||||
{
|
||||
if (host->stat != STATFAIL) {
|
||||
host->ts = time(&(host->ts));
|
||||
host->stat = STATFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* plmysql_ready_reconn -
|
||||
* given a downed HOST, return whether or not it should retry connection
|
||||
*/
|
||||
static int plmysql_ready_reconn(HOST host)
|
||||
{
|
||||
time_t t;
|
||||
long now;
|
||||
|
||||
now = (long) time(&t);
|
||||
if (msg_verbose > 1) {
|
||||
msg_info("dict_mysql: plmysql_ready_reconn(): now is %d", now);
|
||||
msg_info("dict_mysql: plmysql_ready_reconn(): ts is %d", (long) host.ts);
|
||||
msg_info("dict_mysql: plmysql_ready_reconn(): RETRY_CONN_INTV is %d", RETRY_CONN_INTV);
|
||||
if ((now - ((long) host.ts)) >= RETRY_CONN_INTV) {
|
||||
msg_info("dict_mysql: plymsql_ready_reconn(): returning TRUE");
|
||||
return 1;
|
||||
} else {
|
||||
msg_info("dict_mysql: plymsql_ready_reconn(): returning FALSE");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if ((now - ((long) host.ts)) >= RETRY_CONN_INTV)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_open
|
||||
* create association with database with appropriate values
|
||||
* parse the map's config file
|
||||
* allocate memory
|
||||
**********************************************************************/
|
||||
DICT *dict_mysql_open(const char *name, int unused_flags, int unused_dict_flags)
|
||||
{
|
||||
DICT_MYSQL *dict_mysql;
|
||||
int connections;
|
||||
|
||||
dict_mysql = (DICT_MYSQL *) mymalloc(sizeof(DICT_MYSQL));
|
||||
dict_mysql->dict.lookup = dict_mysql_lookup;
|
||||
dict_mysql->dict.update = dict_mysql_update;
|
||||
dict_mysql->dict.close = dict_mysql_close;
|
||||
dict_mysql->dict.fd = -1; /* there's no file descriptor
|
||||
* for locking */
|
||||
dict_mysql->name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||
dict_mysql->name = mysqlname_parse(name);
|
||||
dict_mysql->pldb = plmysql_init(dict_mysql->name->hostnames,
|
||||
dict_mysql->name->len_hosts);
|
||||
if (dict_mysql->pldb == NULL)
|
||||
msg_fatal("couldn't intialize pldb!\n");
|
||||
dict_register(name, (DICT *) dict_mysql);
|
||||
return &dict_mysql->dict;
|
||||
}
|
||||
|
||||
/* mysqlname_parse - parse mysql configuration file */
|
||||
static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
||||
{
|
||||
int i;
|
||||
char *nameval;
|
||||
char *hosts;
|
||||
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||
ARGV *hosts_argv;
|
||||
|
||||
dict_load_file("mysql_options", mysqlcf_path);
|
||||
/* mysql username lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "user")) == NULL)
|
||||
name->username = mystrdup("");
|
||||
else
|
||||
name->username = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set username to '%s'", name->username);
|
||||
/* password lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "password")) == NULL)
|
||||
name->password = mystrdup("");
|
||||
else
|
||||
name->password = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set password to '%s'", name->password);
|
||||
|
||||
/* database name lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "dbname")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
|
||||
else
|
||||
name->dbname = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set database name to '%s'", name->dbname);
|
||||
|
||||
/* table lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "table")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
|
||||
else
|
||||
name->table = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set table name to '%s'", name->table);
|
||||
|
||||
/* select field lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "select_field")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
|
||||
else
|
||||
name->select_field = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set select_field to '%s'", name->select_field);
|
||||
|
||||
/* where field lookup */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "where_field")) == NULL)
|
||||
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
|
||||
else
|
||||
name->where_field = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set where_field to '%s'", name->where_field);
|
||||
|
||||
/* additional conditions */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "additional_conditions")) == NULL)
|
||||
name->additional_conditions = mystrdup("");
|
||||
else
|
||||
name->additional_conditions = mystrdup(nameval);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): set additional_conditions to '%s'", name->additional_conditions);
|
||||
|
||||
/* mysql server hosts */
|
||||
if ((nameval = (char *) dict_lookup("mysql_options", "hosts")) == NULL)
|
||||
hosts = mystrdup("");
|
||||
else
|
||||
hosts = mystrdup(nameval);
|
||||
/* coo argv interface */
|
||||
hosts_argv = argv_split(hosts, " ");
|
||||
argv_terminate(hosts_argv);
|
||||
|
||||
if (hosts_argv->argc == 0) { /* no hosts specified,
|
||||
* default to 'localhost' */
|
||||
msg_info("mysqlname_parse(): no hostnames specified, defaulting to 'localhost'");
|
||||
name->len_hosts = 1;
|
||||
name->hostnames = (char **) mymalloc(sizeof(char *));
|
||||
name->hostnames[0] = mystrdup("localhost");
|
||||
} else {
|
||||
name->len_hosts = hosts_argv->argc;
|
||||
name->hostnames = (char **) mymalloc((sizeof(char *)) * name->len_hosts);
|
||||
i = 0;
|
||||
for (i = 0; hosts_argv->argv[i] != NULL; i++) {
|
||||
name->hostnames[i] = mystrdup(hosts_argv->argv[i]);
|
||||
if (msg_verbose)
|
||||
msg_info("mysqlname_parse(): adding host '%s' to list of mysql server hosts",
|
||||
name->hostnames[i]);
|
||||
}
|
||||
}
|
||||
myfree(hosts);
|
||||
argv_free(hosts_argv);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* plmysql_init - initalize a MYSQL database.
|
||||
* Return NULL on failure, or a PLMYSQL * on success.
|
||||
*/
|
||||
static PLMYSQL *plmysql_init(char *hostnames[],
|
||||
int len_hosts)
|
||||
{
|
||||
PLMYSQL *PLDB;
|
||||
MYSQL *dbs;
|
||||
int i;
|
||||
HOST host;
|
||||
|
||||
if ((PLDB = (PLMYSQL *) mymalloc(sizeof(PLMYSQL))) == NULL) {
|
||||
msg_fatal("mymalloc of pldb failed");
|
||||
}
|
||||
PLDB->len_hosts = len_hosts;
|
||||
if ((PLDB->db_hosts = (HOST *) mymalloc(sizeof(HOST) * len_hosts)) == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < len_hosts; i++) {
|
||||
PLDB->db_hosts[i] = host_init(hostnames[i]);
|
||||
}
|
||||
return PLDB;
|
||||
}
|
||||
|
||||
|
||||
/* host_init - initialize HOST structure */
|
||||
static HOST host_init(char *hostname)
|
||||
{
|
||||
int stat;
|
||||
MYSQL db;
|
||||
time_t ts;
|
||||
HOST host;
|
||||
|
||||
host.stat = STATUNTRIED;
|
||||
host.hostname = hostname;
|
||||
host.db = db;
|
||||
host.ts = ts;
|
||||
return host;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_close
|
||||
* unregister, disassociate from database, freeing appropriate memory
|
||||
**********************************************************************/
|
||||
static void dict_mysql_close(DICT *dict)
|
||||
{
|
||||
int i;
|
||||
@@ -267,87 +515,8 @@ static void dict_mysql_close(DICT *dict)
|
||||
myfree((char *) dict_mysql->name);
|
||||
}
|
||||
|
||||
/* dict_mysql_update - add or update table entry */
|
||||
static void dict_mysql_update(DICT *dict, const char *unused_name, const char *unused_value)
|
||||
{
|
||||
DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
|
||||
|
||||
msg_fatal("dict_mysql_update: attempt to update mysql database");
|
||||
}
|
||||
|
||||
/* dict_mysql_open - create association with database */
|
||||
DICT *dict_mysql_open(const char *name, int unused_flags, int unused_dict_flags)
|
||||
{
|
||||
DICT_MYSQL *dict_mysql;
|
||||
int connections;
|
||||
|
||||
dict_mysql = (DICT_MYSQL *) mymalloc(sizeof(DICT_MYSQL));
|
||||
dict_mysql->dict.lookup = dict_mysql_lookup;
|
||||
dict_mysql->dict.update = dict_mysql_update;
|
||||
dict_mysql->dict.close = dict_mysql_close;
|
||||
dict_mysql->dict.fd = -1; /* there's no file descriptor
|
||||
* for locking */
|
||||
dict_mysql->name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||
dict_mysql->name = mysqlname_parse(name);
|
||||
dict_mysql->pldb = plmysql_init(dict_mysql->name->dbname,
|
||||
dict_mysql->name->hostnames,
|
||||
dict_mysql->name->len_hosts);
|
||||
if (dict_mysql->pldb == NULL)
|
||||
msg_fatal("couldn't intialize pldb!\n");
|
||||
connections = plmysql_connect(dict_mysql->pldb, dict_mysql->name->username,
|
||||
dict_mysql->name->password);
|
||||
if (connections == 0)
|
||||
/* the mysql lookup mechanism will try to reconnect anyway ... */
|
||||
msg_warn("couldn't connect pldb to any database instances");
|
||||
else
|
||||
msg_info("pldb connected to %d database instances", connections);
|
||||
dict_register(name, (DICT *) dict_mysql);
|
||||
return &dict_mysql->dict;
|
||||
}
|
||||
|
||||
/* host_init - initialize HOST structure */
|
||||
static HOST host_init(char *hostname)
|
||||
{
|
||||
int stat;
|
||||
MYSQL db;
|
||||
time_t ts;
|
||||
HOST host;
|
||||
|
||||
host.stat = STATUNTRIED;
|
||||
host.hostname = hostname;
|
||||
host.db = db;
|
||||
host.ts = ts;
|
||||
return host;
|
||||
}
|
||||
|
||||
/*
|
||||
* plmysql_init - initalize a MYSQL database.
|
||||
* Return NULL on failure, or a PLMYSQL * on success.
|
||||
*/
|
||||
PLMYSQL *plmysql_init(char *dbname,
|
||||
char *hostnames[],
|
||||
int len_hosts)
|
||||
{
|
||||
PLMYSQL *PLDB;
|
||||
MYSQL *dbs;
|
||||
int i;
|
||||
HOST host;
|
||||
|
||||
if ((PLDB = (PLMYSQL *) mymalloc(sizeof(PLMYSQL))) == NULL) {
|
||||
msg_fatal("mymalloc of pldb failed");
|
||||
}
|
||||
PLDB->dbname = dbname;
|
||||
PLDB->len_hosts = len_hosts;
|
||||
if ((PLDB->db_hosts = (HOST *) mymalloc(sizeof(HOST) * len_hosts)) == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < len_hosts; i++) {
|
||||
PLDB->db_hosts[i] = host_init(hostnames[i]);
|
||||
}
|
||||
return PLDB;
|
||||
}
|
||||
|
||||
/* plmysql_dealloc - free memory associated with PLMYSQL close databases */
|
||||
void plmysql_dealloc(PLMYSQL *PLDB)
|
||||
static void plmysql_dealloc(PLMYSQL *PLDB)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -359,96 +528,16 @@ void plmysql_dealloc(PLMYSQL *PLDB)
|
||||
myfree((char *) (PLDB));
|
||||
}
|
||||
|
||||
/* plmysql_down_host - down a HOST * */
|
||||
inline void plmysql_down_host(HOST *host)
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_update - add or update table entry
|
||||
*
|
||||
*********************************************************************/
|
||||
static void dict_mysql_update(DICT *dict, const char *unused_name, const char *unused_value)
|
||||
{
|
||||
if (host->stat != STATFAIL)
|
||||
host->ts = time(&(host->ts));
|
||||
host->stat = STATFAIL;
|
||||
}
|
||||
DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
|
||||
|
||||
/* plmysql_connect_single -
|
||||
* used to reconnect to a single database when one is down and as a helper for
|
||||
* plmysql_connect
|
||||
*/
|
||||
int plmysql_connect_single(PLMYSQL *PLDB, int host)
|
||||
{
|
||||
if ((mysql_connect(&(PLDB->db_hosts[host].db), PLDB->db_hosts[host].hostname,
|
||||
PLDB->username, PLDB->password))) {
|
||||
if (mysql_select_db(&(PLDB->db_hosts[host].db), PLDB->dbname) == 0) {
|
||||
PLDB->db_hosts[host].stat = STATACTIVE;
|
||||
return 1;
|
||||
} else {
|
||||
plmysql_down_host(&(PLDB->db_hosts[host]));
|
||||
msg_warn("%s", mysql_error(&PLDB->db_hosts[host].db));
|
||||
}
|
||||
} else {
|
||||
plmysql_down_host(&(PLDB->db_hosts[host]));
|
||||
msg_warn("%s", mysql_error(&PLDB->db_hosts[host].db));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* plmysql_connect -
|
||||
* given a PLMYSQL struct PLDB *, connect it and select db.
|
||||
* return the number of databases successfully connected (0 for failure)
|
||||
*/
|
||||
int plmysql_connect(PLMYSQL *PLDB, char *username, char *password)
|
||||
{
|
||||
int i,
|
||||
res;
|
||||
|
||||
res = 0;
|
||||
|
||||
PLDB->username = username;
|
||||
PLDB->password = password;
|
||||
|
||||
for (i = 0; i < PLDB->len_hosts; i++) {
|
||||
res = res + plmysql_connect_single(PLDB, i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* plmysql_ready_reconn -
|
||||
given a downed HOST, return whether or not it should retry connection
|
||||
*/
|
||||
int plmysql_ready_reconn(HOST host)
|
||||
{
|
||||
time_t t;
|
||||
long now;
|
||||
|
||||
now = (long) time(&t);
|
||||
if ((now - ((long) host.ts)) >= RETRY_CONN_INTV)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* plmysql_query - process a MySQL query. Return 0 on success.
|
||||
* On failure, log failure and try other db instances.
|
||||
*/
|
||||
|
||||
MYSQL_RES *plmysql_query(PLMYSQL *PLDB, const char *query)
|
||||
{
|
||||
int i;
|
||||
MYSQL_RES *res;
|
||||
|
||||
for (i = 0; i < PLDB->len_hosts; i++) {
|
||||
if ((PLDB->db_hosts[i].stat != STATACTIVE) &&
|
||||
(plmysql_ready_reconn(PLDB->db_hosts[i]))) {
|
||||
msg_warn("attempting to reconnect to host");
|
||||
plmysql_connect_single(PLDB, i);
|
||||
continue;
|
||||
}
|
||||
if ((!(mysql_query(&(PLDB->db_hosts[i].db), query))) && \
|
||||
(res = mysql_store_result(&(PLDB->db_hosts[i].db)))) {
|
||||
return res;
|
||||
}
|
||||
msg_warn("%s", mysql_error(&PLDB->db_hosts[i].db));
|
||||
plmysql_down_host(&(PLDB->db_hosts[i]));
|
||||
}
|
||||
return NULL;
|
||||
msg_fatal("dict_mysql_update: attempt to update mysql database");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -6,41 +6,9 @@
|
||||
#define STATACTIVE 0
|
||||
#define STATFAIL 1
|
||||
#define STATUNTRIED 2
|
||||
#define RETRY_CONN_INTV 300 /* 5 minutes */
|
||||
#define RETRY_CONN_INTV 60 /* 1 minute */
|
||||
|
||||
extern DICT *dict_mysql_open(const char *name, int unused_flags, int dict_flags);
|
||||
|
||||
typedef struct {
|
||||
char *hostname;
|
||||
int stat; /* STATUNTRIED | STATFAIL | STATCUR */
|
||||
time_t ts; /* used for attempting reconnection
|
||||
* every so often if a host is down */
|
||||
MYSQL db;
|
||||
} HOST;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *username; /* login for database */
|
||||
char *password; /* password for database */
|
||||
char *dbname; /* the name of the database on all
|
||||
* the servers */
|
||||
HOST *db_hosts; /* the hosts on which the databases
|
||||
* reside */
|
||||
int len_hosts; /* number of hosts */
|
||||
} PLMYSQL;
|
||||
|
||||
extern PLMYSQL *plmysql_init(char *dbname, char *hostnames[], int len_hosts);
|
||||
|
||||
extern int plmysql_connect(PLMYSQL *PLDB, char *username, char *password);
|
||||
|
||||
MYSQL_RES *plmysql_query(PLMYSQL *PLDB, const char *query);
|
||||
|
||||
void plmysql_dealloc(PLMYSQL *PLDB);
|
||||
|
||||
inline void plmysql_down_host(HOST *host);
|
||||
|
||||
int plmysql_connect_single(PLMYSQL *PLDB, int host);
|
||||
|
||||
int plmysql_ready_reconn(HOST host);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user