recipients to a master.cf entry called "cyrus", allowing
you to have both UNIX and non-UNIX mailboxes side by side.
+19990319
+
+ Workaround: on 4.4 BSD derivatives, fstat() can return
+ EBADF on an open file descriptor. Now, that was a surprise.
+ This caused std{out,err} from cron commands to not be
+ delivered.
+
+ Bugfix: "local -v" stopped working.
+
+ Workaround: more watchdog timers for postfix-unfriendly
+ systems. By now every Postfix daemon has one. Call it life
+ insurance.
+
+ Robustness: increased the maximal time to receive or deliver
+ mail from $ipc_timeout (default: 3600 seconds) to the more
+ generous $daemon_timeout (default: 18000 seconds). We don't
+ want false alarms.
+
+ Portability: IRIX 5.2 does not have usleep().
+
+19990320
+
+ Bugfix: \username was broken. Frank Dziuba was the first
+ to notice.
+
Future:
Planned: must be able to list the same hash table in
make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../pcre-2.04' \
'AUXLIBS=../../pcre-2.04/libpcre.a'
+[note: earlier pcre versions have problems -- Wietse]
+
One possible use is to add a line to main.cf:
smtpd_recipient_restrictions = pcre:/opt/postfix/etc/smtprecipient
mail_trigger.o: mail_proto.h
mail_trigger.o: ../include/vstream.h
mail_trigger.o: ../include/vbuf.h
+mail_version.o: mail_version.c
maps.o: maps.c
maps.o: ../include/sys_defs.h
maps.o: ../include/argv.h
int fd;
path = mail_pathname(class, name);
- if ((fd = unix_connect(path, block_mode, 0)) < 0) {
+ if ((fd = LOCAL_CONNECT(path, block_mode, 0)) < 0) {
if (msg_verbose)
msg_info("connect to subsystem %s: %m", path);
stream = 0;
/* int var_soft_bounce;
/* time_t var_starttime;
/* int var_ownreq_special;
-/*
-/* char *var_ldap_server_host;
-/* char *var_ldap_search_base;
-/* int var_ldap_timeout;
+/* int var_daemon_timeout;
/*
/* void mail_params_init()
/* DESCRIPTION
int var_soft_bounce;
time_t var_starttime;
int var_ownreq_special;
-
-#ifdef HAS_LDAP
-
-char *var_ldap_server_host;
-char *var_ldap_search_base;
-int var_ldap_timeout;
-
-#endif
+int var_daemon_timeout;
/* check_myhostname - lookup hostname and validate */
VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0,
VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
-#ifdef HAS_LDAP
- VAR_LDAP_SERVER, DEF_LDAP_SERVER, &var_ldap_server_host, 0, 0,
- VAR_LDAP_SEARCH, DEF_LDAP_SEARCH, &var_ldap_search_base, 0, 0,
-#endif
VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1,
0,
};
VAR_MESSAGE_LIMIT, DEF_MESSAGE_LIMIT, &var_message_limit, 0, 0,
VAR_IPC_IDLE, DEF_IPC_IDLE, &var_ipc_idle_limit, 1, 0,
VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0,
-#ifdef HAS_LDAP
- VAR_LDAP_TIMEOUT, DEF_LDAP_TIMEOUT, &var_ldap_timeout, 1, 0,
-#endif
VAR_TRIGGER_TIMEOUT, DEF_TRIGGER_TIMEOUT, &var_trigger_timeout, 1, 0,
VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0,
VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0,
VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0,
+ VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0,
0,
};
static CONFIG_BOOL_TABLE bool_defaults[] = {
#define DEF_PERCENT_HACK 1
extern bool var_percent_hack;
- /*
- * LDAP lookups. Preliminary code, interface subject to change.
- */
-#define VAR_LDAP_SERVER "ldap_server_host"
-#define DEF_LDAP_SERVER ""
-extern char *var_ldap_server;
-
-#define VAR_LDAP_SEARCH "ldap_search_base"
-#define DEF_LDAP_SEARCH ""
-extern char *var_ldap_search;
-
-#define VAR_LDAP_TIMEOUT "ldap_lookup_timeout"
-#define DEF_LDAP_TIMEOUT 10
-extern int var_ldap_timeout;
-
/*
* Local delivery: alias databases.
*/
#define DEF_FLOCK_STALE 500
extern int var_flock_stale;
+ /*
+ * How long a daemon command may take to receive or deliver a message etc.
+ * before we assume it is wegded (should never happen).
+ */
+#define VAR_DAEMON_TIMEOUT "daemon_timeout"
+#define DEF_DAEMON_TIMEOUT 18000
+extern int var_daemon_timeout;
+
/*
* How long an intra-mail command may take before we assume the mail system
* is in deadlock (should never happen).
} else if (S_ISFIFO(st.st_mode)) {
status = fifo_trigger(path, req_buf, req_len, var_trigger_timeout);
if (status < 0 && S_ISSOCK(st.st_mode))
- status = unix_trigger(path, req_buf, req_len, var_trigger_timeout);
+ status = LOCAL_TRIGGER(path, req_buf, req_len, var_trigger_timeout);
} else if (S_ISSOCK(st.st_mode)) {
- status = unix_trigger(path, req_buf, req_len, var_trigger_timeout);
+ status = LOCAL_TRIGGER(path, req_buf, req_len, var_trigger_timeout);
} else {
msg_warn("%s is not a socket or a fifo", path);
status = -1;
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Beta-19990317"
+#define DEF_MAIL_VERSION "Snapshot-19990321"
extern char *var_mail_version;
/* LICENSE
alias.o: ../include/been_here.h
alias.o: ../include/tok822.h
alias.o: ../include/resolve_clnt.h
+alias.o: ../include/deliver_request.h
+alias.o: ../include/recipient_list.h
biff_notify.o: biff_notify.c
biff_notify.o: ../include/sys_defs.h
biff_notify.o: ../include/msg.h
command.o: local.h
command.o: ../include/tok822.h
command.o: ../include/resolve_clnt.h
+command.o: ../include/deliver_request.h
+command.o: ../include/recipient_list.h
deliver_attr.o: deliver_attr.c
deliver_attr.o: ../include/sys_defs.h
deliver_attr.o: ../include/msg.h
deliver_attr.o: ../include/been_here.h
deliver_attr.o: ../include/tok822.h
deliver_attr.o: ../include/resolve_clnt.h
+deliver_attr.o: ../include/deliver_request.h
+deliver_attr.o: ../include/recipient_list.h
delivered.o: delivered.c
delivered.o: ../include/sys_defs.h
delivered.o: ../include/msg.h
delivered.o: ../include/been_here.h
delivered.o: ../include/tok822.h
delivered.o: ../include/resolve_clnt.h
+delivered.o: ../include/deliver_request.h
+delivered.o: ../include/recipient_list.h
dotforward.o: dotforward.c
dotforward.o: ../include/sys_defs.h
dotforward.o: ../include/msg.h
dotforward.o: local.h
dotforward.o: ../include/tok822.h
dotforward.o: ../include/resolve_clnt.h
+dotforward.o: ../include/deliver_request.h
+dotforward.o: ../include/recipient_list.h
feature.o: feature.c
feature.o: ../include/sys_defs.h
feature.o: ../include/msg.h
feature.o: ../include/been_here.h
feature.o: ../include/tok822.h
feature.o: ../include/resolve_clnt.h
+feature.o: ../include/deliver_request.h
+feature.o: ../include/recipient_list.h
file.o: file.c
file.o: ../include/sys_defs.h
file.o: ../include/msg.h
file.o: local.h
file.o: ../include/tok822.h
file.o: ../include/resolve_clnt.h
+file.o: ../include/deliver_request.h
+file.o: ../include/recipient_list.h
forward.o: forward.c
forward.o: ../include/sys_defs.h
forward.o: ../include/msg.h
forward.o: ../include/been_here.h
forward.o: ../include/tok822.h
forward.o: ../include/resolve_clnt.h
+forward.o: ../include/deliver_request.h
+forward.o: ../include/recipient_list.h
include.o: include.c
include.o: ../include/sys_defs.h
include.o: ../include/msg.h
include.o: ../include/vstring.h
include.o: ../include/tok822.h
include.o: ../include/resolve_clnt.h
+include.o: ../include/deliver_request.h
+include.o: ../include/recipient_list.h
indirect.o: indirect.c
indirect.o: ../include/sys_defs.h
indirect.o: ../include/msg.h
indirect.o: ../include/vstring.h
indirect.o: ../include/tok822.h
indirect.o: ../include/resolve_clnt.h
+indirect.o: ../include/deliver_request.h
+indirect.o: ../include/recipient_list.h
local.o: local.c
local.o: ../include/sys_defs.h
local.o: ../include/msg.h
mailbox.o: ../include/mypwd.h
mailbox.o: ../include/been_here.h
mailbox.o: ../include/mail_params.h
+mailbox.o: ../include/mail_proto.h
+mailbox.o: ../include/iostuff.h
mailbox.o: local.h
mailbox.o: ../include/tok822.h
mailbox.o: ../include/resolve_clnt.h
+mailbox.o: ../include/deliver_request.h
+mailbox.o: ../include/recipient_list.h
mailbox.o: biff_notify.h
maildir.o: maildir.c
maildir.o: ../include/sys_defs.h
maildir.o: ../include/been_here.h
maildir.o: ../include/tok822.h
maildir.o: ../include/resolve_clnt.h
+maildir.o: ../include/deliver_request.h
+maildir.o: ../include/recipient_list.h
recipient.o: recipient.c
recipient.o: ../include/sys_defs.h
recipient.o: ../include/msg.h
recipient.o: ../include/been_here.h
recipient.o: ../include/tok822.h
recipient.o: ../include/resolve_clnt.h
+recipient.o: ../include/deliver_request.h
+recipient.o: ../include/recipient_list.h
resolve.o: resolve.c
resolve.o: ../include/sys_defs.h
resolve.o: ../include/msg.h
resolve.o: ../include/mail_params.h
resolve.o: local.h
resolve.o: ../include/been_here.h
+resolve.o: ../include/deliver_request.h
+resolve.o: ../include/recipient_list.h
token.o: token.c
token.o: ../include/sys_defs.h
token.o: ../include/msg.h
token.o: ../include/mail_params.h
token.o: local.h
token.o: ../include/been_here.h
+token.o: ../include/deliver_request.h
+token.o: ../include/recipient_list.h
unknown.o: unknown.c
unknown.o: ../include/sys_defs.h
unknown.o: ../include/msg.h
unknown.o: ../include/mymalloc.h
unknown.o: ../include/been_here.h
unknown.o: ../include/mail_params.h
+unknown.o: ../include/mail_proto.h
+unknown.o: ../include/vstream.h
+unknown.o: ../include/vbuf.h
+unknown.o: ../include/iostuff.h
unknown.o: ../include/bounce.h
unknown.o: local.h
unknown.o: ../include/htable.h
-unknown.o: ../include/vstream.h
-unknown.o: ../include/vbuf.h
unknown.o: ../include/vstring.h
unknown.o: ../include/tok822.h
unknown.o: ../include/resolve_clnt.h
+unknown.o: ../include/deliver_request.h
+unknown.o: ../include/recipient_list.h
#define MSG_LOG_STATE(m, s) \
msg_info("%s[%d]: local %s recip %s exten %s deliver %s", m, \
- s.level, s.msg_attr.local, s.msg_attr.recipient, \
+ s.level, \
+ s.msg_attr.local ? s.msg_attr.local : "" , \
+ s.msg_attr.recipient ? s.msg_attr.recipient : "", \
s.msg_attr.extension ? s.msg_attr.extension : "", \
s.msg_attr.delivered ? s.msg_attr.delivered : "")
* \user is special: it means don't do any alias or forward expansion.
*/
if (state.msg_attr.recipient[0] == '\\') {
- state.msg_attr.recipient++;
+ state.msg_attr.recipient++, state.msg_attr.local++;
if (*var_rcpt_delim)
state.msg_attr.extension =
split_addr(state.msg_attr.local, *var_rcpt_delim);
single_server.o: ../include/sane_accept.h
single_server.o: ../include/myflock.h
single_server.o: ../include/safe_open.h
+single_server.o: ../include/listen.h
single_server.o: ../include/mail_params.h
single_server.o: ../include/mail_task.h
single_server.o: ../include/debug_process.h
trigger_server.o: ../include/sane_accept.h
trigger_server.o: ../include/myflock.h
trigger_server.o: ../include/safe_open.h
+trigger_server.o: ../include/listen.h
trigger_server.o: ../include/mail_params.h
trigger_server.o: ../include/mail_task.h
trigger_server.o: ../include/debug_process.h
#include "master.h"
+/* master_watchdog - something got stuck */
+
+static NORETURN master_watchdog(int unused_sig)
+{
+
+ /*
+ * This runs as a signal handler. We should not do anything that could
+ * involve memory managent, but exiting without explanation would be
+ * worse.
+ */
+ msg_fatal("watchdog timer");
+}
+
int main(int argc, char **argv)
{
static VSTREAM *lock_fp;
* multiple things at the same time, it really is all a single thread, so
* that there are no concurrency conflicts within the master process.
*/
+ signal(SIGALRM, master_watchdog);
for (;;) {
+ alarm(1000); /* same as trigger servers */
event_loop(-1);
if (master_gotsighup) {
msg_info("reload configuration");
switch (serv->type) {
/*
- * UNIX-domain listener endpoints always come as singlets.
+ * UNIX-domain or stream listener endpoints always come as singlets.
*/
case MASTER_SERV_TYPE_UNIX:
set_eugid(var_owner_uid, var_owner_gid);
serv->listen_fd[0] =
- unix_listen(serv->name, serv->max_proc > var_proc_limit ?
- serv->max_proc : var_proc_limit, NON_BLOCKING);
+ LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
+ serv->max_proc : var_proc_limit, NON_BLOCKING);
close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
set_eugid(getuid(), getgid());
break;
status = inet_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
break;
case MASTER_SERV_TYPE_UNIX:
- status = unix_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
+ status = LOCAL_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
break;
case MASTER_SERV_TYPE_FIFO:
status = fifo_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
#include <myflock.h>
#include <safe_open.h>
#endif
+#include <listen.h>
/* Global library. */
static void (*multi_server_service) (VSTREAM *, char *, char **);
static char *multi_server_name;
static char **multi_server_argv;
+static void (*multi_server_accept) (int, char *);
static void (*multi_server_onexit) (void);
#ifndef NO_SELECT_COLLISION
exit(0);
}
+/* multi_server_watchdog - something got stuck */
+
+static NORETURN multi_server_watchdog(int unused_sig)
+{
+
+ /*
+ * This runs as a signal handler. We should not do anything that could
+ * involve memory managent, but exiting without explanation would be
+ * worse.
+ */
+ msg_fatal("watchdog timer");
+}
+
/* multi_server_abort - terminate after abnormal master exit */
static void multi_server_abort(int unused_event, char *unused_context)
event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
}
-/* multi_server_accept - accept client connection request */
+/* multi_server_wakeup - wake up application */
+
+static void multi_server_wakeup(int fd)
+{
+ VSTREAM *stream;
+
+ if (msg_verbose)
+ msg_info("connection established fd %d", fd);
+ non_blocking(fd, BLOCKING);
+ close_on_exec(fd, CLOSE_ON_EXEC);
+ client_count++;
+ stream = vstream_fdopen(fd, O_RDWR);
+ timed_ipc_setup(stream);
+ event_enable_read(fd, multi_server_execute, (char *) stream);
+}
+
+/* multi_server_accept_local - accept client connection request */
-static void multi_server_accept(int unused_event, char *context)
+static void multi_server_accept_local(int unused_event, char *context)
{
int listen_fd = (int) context;
int time_left = -1;
int fd;
- VSTREAM *stream;
+ /*
+ * Some buggy systems cause Postfix to lock up.
+ */
+ signal(SIGALRM, multi_server_watchdog);
+ alarm(var_daemon_timeout);
+
+ /*
+ * Be prepared for accept() to fail because some other process already
+ * got the connection (the number of processes competing for clients is
+ * kept small, so this is not a "thundering herd" problem). If the
+ * accept() succeeds, be sure to disable non-blocking I/O, in order to
+ * minimize confusion.
+ */
+ if (client_count == 0 && var_idle_limit > 0)
+ time_left = event_cancel_timer(multi_server_timeout, (char *) 0);
+
+ fd = LOCAL_ACCEPT(listen_fd);
#ifndef NO_SELECT_COLLISION
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0)
msg_fatal("select unlock: %m");
#endif
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("accept connection: %m");
+ if (time_left >= 0)
+ event_request_timer(multi_server_timeout, (char *) 0, time_left);
+ return;
+ }
+ multi_server_wakeup(fd);
+}
+
+/* multi_server_accept_inet - accept client connection request */
+
+static void multi_server_accept_inet(int unused_event, char *context)
+{
+ int listen_fd = (int) context;
+ int time_left = -1;
+ int fd;
+ VSTREAM *stream;
+
+ /*
+ * Some buggy systems cause Postfix to lock up.
+ */
+ signal(SIGALRM, multi_server_watchdog);
+ alarm(var_daemon_timeout);
/*
* Be prepared for accept() to fail because some other process already
*/
if (client_count == 0 && var_idle_limit > 0)
time_left = event_cancel_timer(multi_server_timeout, (char *) 0);
- if ((fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) < 0) {
+
+ fd = inet_accept(listen_fd);
+#ifndef NO_SELECT_COLLISION
+ if (multi_server_lock != 0
+ && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0)
+ msg_fatal("select unlock: %m");
+#endif
+ if (fd < 0) {
if (errno != EAGAIN)
msg_fatal("accept connection: %m");
if (time_left >= 0)
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
- if (msg_verbose)
- msg_info("connection established fd %d", fd);
- non_blocking(fd, BLOCKING);
- close_on_exec(fd, CLOSE_ON_EXEC);
- client_count++;
- stream = vstream_fdopen(fd, O_RDWR);
- timed_ipc_setup(stream);
- event_enable_read(fd, multi_server_execute, (char *) stream);
+ multi_server_wakeup(fd);
}
/* multi_server_main - the real main program */
if (stream == 0) {
if (transport == 0)
msg_fatal("no transport type specified");
- if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0
- && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0)
+ if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
+ multi_server_accept = multi_server_accept_inet;
+ else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
+ multi_server_accept = multi_server_accept_local;
+ else
msg_fatal("unsupported transport type: %s", transport);
}
#include <myflock.h>
#include <safe_open.h>
#endif
+#include <listen.h>
/* Global library. */
static void (*single_server_service) (VSTREAM *, char *, char **);
static char *single_server_name;
static char **single_server_argv;
+static void (*single_server_accept) (int, char *);
static void (*single_server_onexit) (void);
#ifndef NO_SELECT_COLLISION
exit(0);
}
+/* single_server_watchdog - something got stuck */
+
+static NORETURN single_server_watchdog(int unused_sig)
+{
+
+ /*
+ * This runs as a signal handler. We should not do anything that could
+ * involve memory managent, but exiting without explanation would be
+ * worse.
+ */
+ msg_fatal("watchdog timer");
+}
+
/* single_server_abort - terminate after abnormal master exit */
static void single_server_abort(int unused_event, char *unused_context)
single_server_exit();
}
-/* single_server_accept - accept client connection request */
+/* single_server_wakeup - wake up application */
-static void single_server_accept(int unused_event, char *context)
+static void single_server_wakeup(int fd)
{
- int listen_fd = (int) context;
VSTREAM *stream;
- int time_left = -1;
- int fd;
-
-#ifndef NO_SELECT_COLLISION
- if (single_server_lock != 0
- && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0)
- msg_fatal("select unlock: %m");
-#endif
-
- /*
- * Be prepared for accept() to fail because some other process already
- * got the connection. We use select() + accept(), instead of simply
- * blocking in accept(), because we must be able to detect that the
- * master process has gone away unexpectedly.
- */
- if (var_idle_limit > 0)
- time_left = event_cancel_timer(single_server_timeout, (char *) 0);
-
- if ((fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) < 0) {
- if (errno != EAGAIN)
- msg_fatal("accept connection: %m");
- if (time_left >= 0)
- event_request_timer(single_server_timeout, (char *) 0, time_left);
- return;
- }
/*
* If the accept() succeeds, be sure to disable non-blocking I/O, because
event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
}
+/* single_server_accept_local - accept client connection request */
+
+static void single_server_accept_local(int unused_event, char *context)
+{
+ int listen_fd = (int) context;
+ int time_left = -1;
+ int fd;
+
+ /*
+ * Some buggy systems cause Postfix to lock up.
+ */
+ signal(SIGALRM, single_server_watchdog);
+ alarm(var_daemon_timeout);
+
+ /*
+ * Be prepared for accept() to fail because some other process already
+ * got the connection. We use select() + accept(), instead of simply
+ * blocking in accept(), because we must be able to detect that the
+ * master process has gone away unexpectedly.
+ */
+ if (var_idle_limit > 0)
+ time_left = event_cancel_timer(single_server_timeout, (char *) 0);
+
+ fd = LOCAL_ACCEPT(listen_fd);
+#ifndef NO_SELECT_COLLISION
+ if (single_server_lock != 0
+ && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0)
+ msg_fatal("select unlock: %m");
+#endif
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("accept connection: %m");
+ if (time_left >= 0)
+ event_request_timer(single_server_timeout, (char *) 0, time_left);
+ return;
+ }
+ single_server_wakeup(fd);
+}
+
+/* single_server_accept_inet - accept client connection request */
+
+static void single_server_accept_inet(int unused_event, char *context)
+{
+ int listen_fd = (int) context;
+ int time_left = -1;
+ int fd;
+
+ /*
+ * Some buggy systems cause Postfix to lock up.
+ */
+ signal(SIGALRM, single_server_watchdog);
+ alarm(var_daemon_timeout);
+
+ /*
+ * Be prepared for accept() to fail because some other process already
+ * got the connection. We use select() + accept(), instead of simply
+ * blocking in accept(), because we must be able to detect that the
+ * master process has gone away unexpectedly.
+ */
+ if (var_idle_limit > 0)
+ time_left = event_cancel_timer(single_server_timeout, (char *) 0);
+
+ fd = inet_accept(listen_fd);
+#ifndef NO_SELECT_COLLISION
+ if (single_server_lock != 0
+ && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0)
+ msg_fatal("select unlock: %m");
+#endif
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("accept connection: %m");
+ if (time_left >= 0)
+ event_request_timer(single_server_timeout, (char *) 0, time_left);
+ return;
+ }
+ single_server_wakeup(fd);
+}
+
/* single_server_main - the real main program */
NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
if (stream == 0) {
if (transport == 0)
msg_fatal("no transport type specified");
- if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0
- && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0)
+ if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
+ single_server_accept = single_server_accept_inet;
+ else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
+ single_server_accept = single_server_accept_local;
+ else
msg_fatal("unsupported transport type: %s", transport);
}
#include <myflock.h>
#include <safe_open.h>
#endif
+#include <listen.h>
/* Global library. */
use_count++;
}
-/* trigger_server_accept_fifo - accept socket client request */
+/* trigger_server_accept_fifo - accept fifo client request */
static void trigger_server_accept_fifo(int unused_event, char *context)
{
trigger_server_wakeup(listen_fd);
}
-/* trigger_server_accept_socket - accept socket client request */
+/* trigger_server_accept_local - accept socket client request */
-static void trigger_server_accept_socket(int unused_event, char *context)
+static void trigger_server_accept_local(int unused_event, char *context)
{
- char *myname = "trigger_server_accept_socket";
+ char *myname = "trigger_server_accept_local";
int listen_fd = (int) context;
int time_left = 0;
int fd;
-#ifndef NO_SELECT_COLLISION
- if (trigger_server_lock != 0
- && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0)
- msg_fatal("select unlock: %m");
-#endif
if (msg_verbose)
msg_info("%s: trigger arrived", myname);
/*
* Some buggy systems cause Postfix to lock up.
*/
+ signal(SIGALRM, trigger_server_watchdog);
alarm(1000);
/*
*/
if (var_idle_limit > 0)
time_left = event_cancel_timer(trigger_server_timeout, (char *) 0);
- if ((fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) < 0) {
+
+ fd = LOCAL_ACCEPT(listen_fd);
+#ifndef NO_SELECT_COLLISION
+ if (trigger_server_lock != 0
+ && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0)
+ msg_fatal("select unlock: %m");
+#endif
+ if (fd < 0) {
if (errno != EAGAIN)
msg_fatal("accept connection: %m");
if (time_left >= 0)
* problems, witness the workarounds in the fifo_listen() routine.
* Therefore we support both FIFOs and UNIX-domain sockets, so that the
* user can choose whatever works best.
+ *
+ * Well, I give up. Solaris UNIX-domain sockets still don't work properly,
+ * so it will have to limp along with a streams-specific alternative.
*/
if (stream == 0) {
if (transport == 0)
msg_fatal("no transport type specified");
- if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
- trigger_server_accept = trigger_server_accept_socket;
if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
- trigger_server_accept = trigger_server_accept_socket;
+ trigger_server_accept = trigger_server_accept_local;
else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
trigger_server_accept = trigger_server_accept_fifo;
else
@make -f Makefile.in Makefile
# do not edit below this line - it is generated by 'make depend'
-cleanup_extra.o: cleanup_extra.c
pickup.o: pickup.c
pickup.o: ../include/sys_defs.h
pickup.o: ../include/msg.h
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/* lock mail folder and execute command
/* SYNOPSIS
/* .fi
-/* \fBpostlock\fR [\fB-c \fIconfig_dir\fB] [\fB-v\fR]
+/* \fBpostlock\fR [\fB-c \fIconfig_dir\fB] [\fB-v\fR]
/* \fIfile command...\fR
/* DESCRIPTION
/* The \fBpostlock\fR command locks \fIfile\fR for exclusive
/*
/* Options:
/* .IP "\fB-c \fIconfig_dir\fR"
-/* Read configuration information from \fBmain.cf\fR in the named
+/* Read configuration information from \fBmain.cf\fR in the named
/* configuration directory.
/* .IP \fB-v\fR
-/* Enable verbose mode for debugging purposes. Multiple \fB-v\fR
+/* Enable verbose mode for debugging purposes. Multiple \fB-v\fR
/* options make the software increasingly verbose.
/* .PP
/* Arguments:
/* .IP \fIfile\fR
/* A mailbox file. The user should have read/write permission.
/* .IP \fIcommand...\fR
-/* The command to execute while \fIfile\fR is locked for exclusive
+/* The command to execute while \fIfile\fR is locked for exclusive
/* access. The command is executed directly, i.e. without
/* interpretation by a shell command interpreter.
/* DIAGNOSTICS
/* and for default values.
/* .SH "Locking controls"
/* .ad
-/* .fi
+/* .fi
/* .IP \fBdeliver_lock_attempts\fR
/* Limit the number of attempts to acquire an exclusive lock.
/* .IP \fBdeliver_lock_delay\fR
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/* Specifies the logging tag, that is, the identifying name that
/* appears at the beginning of each logging record.
/* .IP \fB-v\fR
-/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
+/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
/* options make the software increasingly verbose.
/* SEE ALSO
/* syslogd(8) syslog daemon.
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
/*
* Guard against broken systems.
*/
- event_request_timer(qmgr_deliver_abort, (char *) entry, var_ipc_timeout);
+ event_request_timer(qmgr_deliver_abort, (char *) entry, var_daemon_timeout);
}
/*
* Guard against broken systems.
*/
- event_request_timer(qmgr_transport_abort, (char *) alloc, var_ipc_timeout);
+ event_request_timer(qmgr_transport_abort, (char *) alloc,
+ var_daemon_timeout);
}
/* qmgr_transport_create - create transport instance */
/*
* To minimize confusion, make sure that the standard file descriptors
- * are open before opening anything else.
+ * are open before opening anything else. XXX Work around for 44BSD where
+ * fstat can return EBADF on an open file descriptor.
*/
for (fd = 0; fd < 3; fd++)
- if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+ if (fstat(fd, &st) == -1
+ && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
msg_fatal("open /dev/null: %m");
/*
smtp-source.o: smtp-source.c
smtp-source.o: ../include/sys_defs.h
smtp-source.o: ../include/msg.h
-smtp-source.o: ../include/vstring.h
-smtp-source.o: ../include/vbuf.h
+smtp-source.o: ../include/msg_vstream.h
smtp-source.o: ../include/vstream.h
+smtp-source.o: ../include/vbuf.h
+smtp-source.o: ../include/vstring.h
smtp-source.o: ../include/vstring_vstream.h
smtp-source.o: ../include/get_hostname.h
smtp-source.o: ../include/split_at.h
translit.c trimblanks.c unix_connect.c unix_listen.c unix_trigger.c \
unsafe.c username.c valid_hostname.c vbuf.c vbuf_print.c \
vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \
- write_buf.c write_wait.c dict_unix.c dict_pcre.c
+ write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \
+ stream_connect.c stream_trigger.c
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
dict_env.o dict_ht.o dict_ldap.o dict_ni.o dict_nis.o \
translit.o trimblanks.o unix_connect.o unix_listen.o unix_trigger.o \
unsafe.o username.o valid_hostname.o vbuf.o vbuf_print.o \
vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \
- write_buf.o write_wait.o dict_unix.o dict_pcre.o
+ write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \
+ stream_connect.o stream_trigger.o
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_ni.h dict_nis.h \
dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \
inet_listen.o: inet_util.h
inet_listen.o: iostuff.h
inet_listen.o: listen.h
+inet_listen.o: sane_accept.h
inet_trigger.o: inet_trigger.c
inet_trigger.o: sys_defs.h
inet_trigger.o: msg.h
select_bug.o: vstream.h
select_bug.o: vbuf.h
select_bug.o: msg_vstream.h
+sendfd_test.o: sendfd_test.c
+sendfd_test.o: sys_defs.h
+sendfd_test.o: sendfd_test.c
+sendfd_test.o: iostuff.h
+sendfd_test.o: msg.h
+sendfd_test.o: msg_vstream.h
+sendfd_test.o: vstream.h
+sendfd_test.o: vbuf.h
+sendfd_test.o: listen.h
set_eugid.o: set_eugid.c
set_eugid.o: sys_defs.h
set_eugid.o: msg.h
stat_as.o: msg.h
stat_as.o: set_eugid.h
stat_as.o: stat_as.h
+stream_connect.o: stream_connect.c
+stream_connect.o: sys_defs.h
+stream_connect.o: msg.h
+stream_connect.o: connect.h
+stream_connect.o: iostuff.h
+stream_listen.o: stream_listen.c
+stream_listen.o: sys_defs.h
+stream_listen.o: msg.h
+stream_listen.o: listen.h
+stream_listen.o: iostuff.h
+stream_trigger.o: stream_trigger.c
+stream_trigger.o: sys_defs.h
+stream_trigger.o: msg.h
+stream_trigger.o: connect.h
+stream_trigger.o: iostuff.h
+stream_trigger.o: trigger.h
sys_compat.o: sys_compat.c
sys_compat.o: sys_defs.h
timed_connect.o: timed_connect.c
unix_listen.o: msg.h
unix_listen.o: iostuff.h
unix_listen.o: listen.h
+unix_listen.o: sane_accept.h
unix_trigger.o: unix_trigger.c
unix_trigger.o: sys_defs.h
unix_trigger.o: msg.h
*/
extern int unix_connect(const char *, int, int);
extern int inet_connect(const char *, int, int);
+extern int stream_connect(const char *, int, int);
/* LICENSE
/* .ad
/* const char *addr;
/* int backlog;
/* int block_mode;
+/*
+/* int inet_accept(fd)
+/* int fd;
/* DESCRIPTION
/* The \fBinet_listen\fR routine starts a listener in the INET domain
/* on the specified address, with the specified backlog, and returns
/* the resulting file descriptor.
/*
+/* inet_accept() accepts a connection and sanitizes error results.
+/*
/* Arguments:
/* .IP addr
/* The communication endpoint to listen on. The syntax is "host:port".
/* .IP block_mode
/* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for
/* blocking mode.
+/* .IP fd
+/* File descriptor returned by inet_listen().
/* DIAGNOSTICS
-/* Fatal errors: all errors are fatal.
+/* Fatal errors: inet_listen() aborts upon any system call failure.
+/* inet_accept() leaves all error handling up to the caller.
/* LICENSE
/* .ad
/* .fi
#include "inet_util.h"
#include "iostuff.h"
#include "listen.h"
+#include "sane_accept.h"
/* Application-specific stuff. */
msg_fatal("listen: %m");
return (sock);
}
+
+/* inet_accept - accept connection */
+
+int inet_accept(int fd)
+{
+ return (sane_accept(fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0));
+}
extern int unix_listen(const char *, int, int);
extern int inet_listen(const char *, int, int);
extern int fifo_listen(const char *, int, int);
+extern int stream_listen(const char *, int, int);
+
+extern int inet_accept(int);
+extern int unix_accept(int);
+extern int stream_accept(int);
/* LICENSE
/* .ad
/* int sane_accept(sock, buf, len)
/* int sock;
/* struct sockaddr *buf;
-/* int len;
+/* SOCKADDR_SIZE *len;
/* DESCRIPTION
/* sane_accept() implements the accept(2) socket call, and maps
/* known harmless error results to EAGAIN.
--- /dev/null
+#include "sys_defs.h"
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include "iostuff.h"
+
+#include "msg.h"
+#include "msg_vstream.h"
+#include "listen.h"
+
+#define FIFO "/tmp/test-fifo"
+
+static const char *progname;
+
+static print_fstat(int fd)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ msg_fatal("fstat: %m");
+ vstream_printf("fd %d\n", fd);
+ vstream_printf("dev %d\n", st.st_dev);
+ vstream_printf("ino %d\n", st.st_ino);
+ vstream_fflush(VSTREAM_OUT);
+}
+
+static NORETURN usage(void)
+{
+ msg_fatal("usage: %s [-p] [-n count] [-v]", progname);
+}
+
+main(int argc, char **argv)
+{
+ struct strrecvfd fdinfo;
+ int server_fd;
+ int client_fd;
+ int print_fstats = 0;
+ int count = 1;
+ int ch;
+ int i;
+
+ progname = argv[0];
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+
+ /*
+ * Parse JCL.
+ */
+ while ((ch = GETOPT(argc, argv, "pn:v")) > 0) {
+ switch (ch) {
+ default:
+ usage();
+ case 'p':
+ print_fstats = 1;
+ break;
+ case 'n':
+ if ((count = atoi(optarg)) < 1)
+ usage();
+ break;
+ case 'v':
+ msg_verbose++;
+ break;
+ }
+ }
+ server_fd = fifo_listen(FIFO, 0600, NON_BLOCKING);
+ if (readable(server_fd))
+ msg_fatal("server fd is readable after create");
+
+ /*
+ * Connect in client.
+ */
+ if ((client_fd = open(FIFO, O_RDWR, NON_BLOCKING)) < 0)
+ msg_fatal("open %s as client: %m", FIFO);
+ if (readable(server_fd))
+ msg_warn("server fd is readable after client open");
+ if (print_fstats)
+ print_fstat(0);
+ if (ioctl(client_fd, I_RECVFD, &fdinfo) < 0)
+ msg_fatal("receive fd: %m");
+ for (i = 0; i < count; i++) {
+ msg_info("send attempt %d", i);
+ while (!writable(client_fd))
+ msg_info("wait for client fd to become writable");
+ if (ioctl(client_fd, I_SENDFD, 0) < 0)
+ msg_fatal("send fd to server: %m");
+ }
+ if (close(client_fd) < 0)
+ msg_fatal("close client fd: %m");
+
+ /*
+ * Accept in server.
+ */
+ for (i = 0; i < count; i++) {
+ msg_info("receive attempt %d", i);
+ while (!readable(server_fd))
+ msg_info("wait for server fd to become writable");
+ if (ioctl(server_fd, I_RECVFD, &fdinfo) < 0)
+ msg_fatal("receive fd: %m");
+ if (print_fstats)
+ print_fstat(fdinfo.fd);
+ if (close(fdinfo.fd) < 0)
+ msg_fatal("close received fd: %m");
+ }
+}
--- /dev/null
+/*++
+/* NAME
+/* stream_connect 3
+/* SUMMARY
+/* connect to stream listener
+/* SYNOPSIS
+/* #include <connect.h>
+/*
+/* int stream_connect(path, block_mode, timeout)
+/* const char *path;
+/* int block_mode;
+/* int timeout;
+/* DESCRIPTION
+/* stream_connect() connects to a stream listener for the specified
+/* pathname, and returns the resulting file descriptor.
+/*
+/* Arguments:
+/* .IP path
+/* Null-terminated string with listener endpoint name.
+/* .IP block_mode
+/* Either NON_BLOCKING for a non-blocking stream, or BLOCKING for
+/* blocking mode. However, a stream connection succeeds or fails
+/* immediately.
+/* .IP timeout
+/* This argument is ignored; it is present for compatibility with
+/* other interfaces. Stream connections succeed or fail immediately.
+/* DIAGNOSTICS
+/* The result is -1 in case the connection could not be made.
+/* Fatal errors: other system call failures.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <connect.h>
+
+/* stream_connect - connect to stream listener */
+
+int stream_connect(const char *path, int block_mode, int unused_timeout)
+{
+#ifdef STREAM_CONNECTIONS
+ char *myname = "stream_connect";
+ struct stat st;
+ int fd;
+ int flags;
+
+ /*
+ * The requested file system object must exist, otherwise we can't reach
+ * the server.
+ */
+ if (block_mode == NON_BLOCKING)
+ flags = O_RDWR | O_NONBLOCK;
+ else
+ flags = O_RDWR;
+ if ((fd = open(path, flags, 0)) < 0)
+ return (-1);
+
+ /*
+ * XXX Horror. If the open() result is a regular file, no server was
+ * listening. In this case we simulate what would have happened with
+ * UNIX-domain sockets.
+ */
+ if (fstat(fd, &st) < 0)
+ msg_fatal("%s: fstat: %m", myname);
+ if (S_ISREG(st.st_mode)) {
+ close(fd);
+ errno = ECONNREFUSED;
+ return (-1);
+ }
+
+ /*
+ * This is for {unix,inet}_connect() compatibility.
+ */
+ if (block_mode == NON_BLOCKING)
+ non_blocking(fd, NON_BLOCKING);
+
+ /*
+ * No trouble detected, so far.
+ */
+ return (fd);
+#else
+ msg_fatal("stream connections are not implemented");
+#endif
+}
+
--- /dev/null
+/*++
+/* NAME
+/* stream_listen 3
+/* SUMMARY
+/* start stream listener
+/* SYNOPSIS
+/* #include <listen.h>
+/*
+/* int stream_listen(path, backlog, block_mode)
+/* const char *path;
+/* int backlog;
+/* int block_mode;
+/*
+/* int stream_accept(fd)
+/* int fd;
+/* DESCRIPTION
+/* This module implements a substitute local IPC for systems that do
+/* not have properly-working UNIX-domain sockets.
+/*
+/* stream_listen() creates a listener endpoint with the specified
+/* permissions, and returns a file descriptor to be used for accepting
+/* connections.
+/*
+/* stream_accept() accepts a connection.
+/*
+/* Arguments:
+/* .IP path
+/* Null-terminated string with connection destination.
+/* .IP backlog
+/* This argument exists for compatibility and is ignored.
+/* .IP block_mode
+/* This argument exists for compatibility and is ignored.
+/* blocking mode.
+/* .IP fd
+/* File descriptor returned by stream_listen().
+/* DIAGNOSTICS
+/* Fatal errors: stream_listen() aborts upon any system call failure.
+/* stream_accept() leaves all error handling up to the caller.
+/* BUGS
+/* This implementation leaks one file descriptor. This is fixed when
+/* endpoints become objects rather than file descriptors.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System interfaces. */
+
+#include <sys_defs.h>
+
+#ifdef STREAM_CONNECTIONS
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stropts.h>
+#include <fcntl.h>
+
+#endif
+
+/* Utility library. */
+
+#include "msg.h"
+#include "listen.h"
+
+/* stream_listen - create stream listener */
+
+int stream_listen(const char *path, int unused_backlog,
+int unused_block_mode)
+{
+#ifdef STREAM_CONNECTIONS
+ char *myname = "stream_listen";
+ static int pair[2];
+ int fd;
+
+ /*
+ * Initialize: create the specified endpoint with the right permissions.
+ */
+#define PERMS 0666
+ if (unlink(path) && errno != ENOENT)
+ msg_fatal("%s: remove %s: %m", myname, path);
+ if ((fd = open(path, PERMS, O_CREAT | O_TRUNC | O_WRONLY)) < 0)
+ msg_fatal("%s: create file %s: %m", myname, path);
+ if (fchmod(fd, PERMS) < 0)
+ msg_fatal("%s: chmod 0%o: %m", myname, PERMS);
+ if (close(fd) < 0)
+ msg_fatal("%s: close file %s: %m", myname, path);
+
+ /*
+ * Associate one pipe end with the file just created. See: Richard
+ * Stevens, Advanced Programming in the UNIX Environment Ch. 15.5.1
+ *
+ * On Solaris 2.4/SPARC, this gives us a "listen queue" of some 460
+ * connections.
+ */
+ if (pipe(pair) < 0)
+ msg_fatal("%s: create pipe: %m", myname);
+ if (ioctl(pair[1], I_PUSH, "connld") < 0)
+ msg_fatal("%s: push connld module: %m", myname);
+ if (fattach(pair[1], path) < 0)
+ msg_fatal("%s: fattach %s: %m", myname, path);
+
+ /*
+ * Return one end, and leak the other. This will be fixed when all
+ * endpoints are objects instead of bare file descriptors.
+ */
+ return (pair[0]);
+#else
+ msg_fatal("stream connections are not implemented");
+#endif
+}
+
+/* stream_accept - accept stream connection */
+
+int stream_accept(int fd)
+{
+#ifdef STREAM_CONNECTIONS
+ struct strrecvfd fdinfo;
+
+ /*
+ * This will return EAGAIN on a non-blocking stream when someone else
+ * snatched the connection from us.
+ */
+ if (ioctl(fd, I_RECVFD, &fdinfo) < 0)
+ return (-1);
+ return (fdinfo.fd);
+#else
+ msg_fatal("stream connections are not implemented");
+#endif
+}
--- /dev/null
+/*++
+/* NAME
+/* stream_trigger 3
+/* SUMMARY
+/* wakeup stream server
+/* SYNOPSIS
+/* #include <trigger.h>
+/*
+/* int stream_trigger(service, buf, len, timeout)
+/* const char *service;
+/* const char *buf;
+/* int len;
+/* int timeout;
+/* DESCRIPTION
+/* stream_trigger() wakes up the named stream server by making
+/* a brief connection to it and writing the named buffer.
+/*
+/* Arguments:
+/* .IP service
+/* Name of the communication endpoint.
+/* .IP buf
+/* Address of data to be written.
+/* .IP len
+/* Amount of data to be written.
+/* .IP timeout
+/* Deadline in seconds. Specify a value <= 0 to disable
+/* the time limit.
+/* DIAGNOSTICS
+/* The result is zero in case of success, -1 in case of problems.
+/* SEE ALSO
+/* stream_connect(3), stream client
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <unistd.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <connect.h>
+#include <iostuff.h>
+#include <trigger.h>
+
+/* stream_trigger - wakeup stream server */
+
+int stream_trigger(const char *service, const char *buf, int len, int timeout)
+{
+ char *myname = "stream_trigger";
+ int fd;
+
+ if (msg_verbose > 1)
+ msg_info("%s: service %s", myname, service);
+
+ /*
+ * Connect...
+ */
+ if ((fd = stream_connect(service, BLOCKING, timeout)) < 0) {
+ if (msg_verbose)
+ msg_warn("%s: connect to %s: %m", myname, service);
+ return (-1);
+ }
+
+ /*
+ * Write the request...
+ */
+ if (write_buf(fd, buf, len, timeout) < 0)
+ if (msg_verbose)
+ msg_warn("%s: write to %s: %m", myname, service);
+
+ /*
+ * Disconnect.
+ */
+ if (close(fd) < 0)
+ if (msg_verbose)
+ msg_warn("%s: close %s: %m", myname, service);
+ return (0);
+}
#define DBM_NO_TRAILING_NULL
#define USE_STATVFS
#define STATVFS_IN_SYS_STATVFS_H
-#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT /* Solaris 2.5.1, reportedly */
+#define STREAM_CONNECTIONS /* connld module */
+#define LOCAL_LISTEN stream_listen
+#define LOCAL_ACCEPT stream_accept
+#define LOCAL_CONNECT stream_connect
+#define LOCAL_TRIGGER stream_trigger
#endif
#ifdef UW7 /* UnixWare 7 */
#define STATVFS_IN_SYS_STATVFS_H
#endif
+#if defined(IRIX5)
+#define usleep doze
+#endif
+
#ifdef LINUX2
#define SUPPORTED
#include <sys/types.h>
#define SOCKOPT_SIZE int
#endif
+#ifndef LOCAL_LISTEN
+#define LOCAL_LISTEN unix_listen
+#define LOCAL_ACCEPT unix_accept
+#define LOCAL_CONNECT unix_connect
+#define LOCAL_TRIGGER unix_trigger
+#endif
+
#if !defined (HAVE_SYS_NDIR_H) && !defined (HAVE_SYS_DIR_H) \
&& !defined (HAVE_NDIR_H)
#define HAVE_DIRENT_H
extern int unix_trigger(const char *, const char *, int, int);
extern int inet_trigger(const char *, const char *, int, int);
extern int fifo_trigger(const char *, const char *, int, int);
+extern int stream_trigger(const char *, const char *, int, int);
/* LICENSE
/* .ad
/* const char *addr;
/* int backlog;
/* int block_mode;
+/*
+/* int unix_accept(fd)
+/* int fd;
/* DESCRIPTION
/* The \fBunix_listen\fR() routine starts a listener in the UNIX domain
/* on the specified address, with the specified backlog, and returns
/* the resulting file descriptor.
/*
+/* unix_accept() accepts a connection and sanitizes error results.
+/*
/* Arguments:
/* .IP addr
/* Null-terminated string with connection destination.
/* .IP block_mode
/* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for
/* blocking mode.
+/* .IP fd
+/* File descriptor returned by unix_listen().
/* DIAGNOSTICS
-/* Fatal errors: all errors are fatal.
+/* Fatal errors: unix_listen() aborts upon any system call failure.
+/* unix_accept() leaves all error handling up to the caller.
/* LICENSE
/* .ad
/* .fi
#include "msg.h"
#include "iostuff.h"
#include "listen.h"
+#include "sane_accept.h"
/* unix_listen - create UNIX-domain listener */
msg_fatal("listen: %m");
return (sock);
}
+
+/* unix_accept - accept connection */
+
+int unix_accept(int fd)
+{
+ return (sane_accept(fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0));
+}
switch (select(fd + 1, (fd_set *) 0, &write_fds, &except_fds, &tv)) {
case -1:
if (errno != EINTR)
- msg_fatal("select");
+ msg_fatal("select: %m");
continue;
default:
return (FD_ISSET(fd, &write_fds));