Bugfix: \username was broken. Frank Dziuba was the first
to notice.
+19990321
+
+ Workaround: from now on, Postfix on Solaris uses stream
+ pipes instead of UNIX-domain sockets. Despite workarounds,
+ the latter were causing more trouble than anything else on
+ all systems combined.
+
+19990322
+
+ Portability: the makedefs would mis-identify IRIX 6.5.x as
+ IRIX 5.x. Fix by Brian Truelsen of Maersk Mc-Kinney Moller
+ Institute for Production Technology, Denmark.
+
+ Feature: reject_unknown_recipient_domain restriction for
+ recipient addresses. For the sake of symmetry, we now also
+ have reject_unknown_sender_domain. This means the old
+ reject_unknown_address restriction is being phased out.
+ Suggested by Rask Ingemann Lambertsen [XXX affiliation to
+ be determined].
+
+ Feature: unknown sender/recipient domain restrictions now
+ distinguish between soft errors (always: 450) and hard
+ errors (configurable with the unknown_address_reject_code
+ parameter, default: 450; use 550 at your own risk).
+
+ Feature: no HELO junk mail restrictions means that no syntax
+ check will be done on HELO/EHLO hostname arguments.
+
+ Bugfix: the initial Solaris workaround for UNIX-domain
+ sockets could cause the queue manager to block if Postfix
+ ran into a delivery agent process limit. After another code
+ rewrite that problem is eliminated. Thanks to Chris
+ Cappuccio, Empire Net, for assistance with testing.
+
Future:
Planned: must be able to list the same hash table in
-Incompatible changes with postfix-alpha-19990317:
-=================================================
+Major changes with snapshot-19990322:
+=====================================
+
+- The UNIX-domain socket workaround for Solaris was fixed
+after one day of review. More testing is welcome.
+
+- reject_unknown_{sender,recipient}_domain restrictions that
+distinguish between hard (always 450) and soft (configurable,
+default 450) lookup errors.
+
+Incompatible changes with postfix-19990317:
+===========================================
- You MUST install the new version of /etc/postfix/postfix-script.
MUST specify the R flag in order to generate a Return-Path: message
header (as needed by, for example, cyrus).
-Major changes since postfix-beta-19990122-pl01:
-===============================================
+Major changes with postfix-19990317:
+====================================
A detailed record of changes is given in the HISTORY file.
#define DEF_NON_FQDN_CODE 504
extern int var_non_fqdn_code;
+#define REJECT_UNKNOWN_SENDDOM "reject_unknown_sender_domain"
+#define REJECT_UNKNOWN_RCPTDOM "reject_unknown_recipient_domain"
#define REJECT_UNKNOWN_ADDRESS "reject_unknown_address"
#define VAR_UNK_ADDR_CODE "unknown_address_reject_code"
#define DEF_UNK_ADDR_CODE 450
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-19990321"
+#define DEF_MAIL_VERSION "Snapshot-19990322"
extern char *var_mail_version;
/* LICENSE
<dt> Example:
-<dd> <b>smtpd_sender_restrictions = reject_unknown_address</b>
+<dd> <b>smtpd_sender_restrictions = reject_unknown_sender_domain</b>
<p>
<dl compact>
-<a name="reject_unknown_address">
+<a name="reject_unknown_sender_domain">
-<dt> <b>reject_unknown_address</b> <dd> Reject the request when
-the sender mail address has no DNS A or MX record. The
+<dt> <b>reject_unknown_sender_domain</b> <dd> Reject the request
+when the sender mail address has no DNS A or MX record. The
<b>unknown_address_reject_code </b> parameter specifies the response
-code for rejected requests (default: <b>450</b>).
+code for rejected requests (default: <b>450</b>). The response
+is always <b>450</b> in case of a temporary DNS error.
<p>
<p>
+<a name="reject_unknown_recipient_domain">
+
+<dt> <b>reject_unknown_recipient_domain</b> <dd> Reject the request
+when the recipient mail address has no DNS A or MX record. The
+<b>unknown_address_reject_code </b> parameter specifies the response
+code for rejected requests (default: <b>450</b>). The response
+is always <b>450</b> in case of a temporary DNS error.
+
+<p>
+
<a name="reject_non_fqdn_recipient">
<dt> <b>reject_non_fqdn_recipient</b> <dd> Reject the request when
<p>
-<dt> <b><a href="#reject_unknown_address">reject_unknown_address</a></b>
+<dt> <b><a href="#reject_unknown_sender_domain">reject_unknown_sender_domain</a></b>
<dt> <b><a href="#reject_non_fqdn_sender">reject_non_fqdn_sender</a></b>
CCARGS="$CCARGS -DPATH_DB_H='<db/db.h>'"
fi
;;
- IRIX*.5*) SYSTYPE=IRIX5
+ IRIX*.5.*) SYSTYPE=IRIX5
# Use the native compiler by default
: ${CC=cc}
RANLIB=echo
;;
- IRIX*.6*) SYSTYPE=IRIX6
+ IRIX*.6.*) SYSTYPE=IRIX6
# Use the native compiler by default, and allow nested comments.
: ${CC="cc -woff 1009,1116,1412"}
RANLIB=echo
#include <iostuff.h>
#include <stringops.h>
#include <sane_accept.h>
-#ifndef NO_SELECT_COLLISION
#include <myflock.h>
#include <safe_open.h>
-#endif
#include <listen.h>
/* Global library. */
static char **multi_server_argv;
static void (*multi_server_accept) (int, char *);
static void (*multi_server_onexit) (void);
-
-#ifndef NO_SELECT_COLLISION
static VSTREAM *multi_server_lock;
-#endif
-
/* multi_server_exit - normal termination */
static NORETURN multi_server_exit(void)
{
VSTREAM *stream = (VSTREAM *) context;
-#ifndef NO_SELECT_COLLISION
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0)
msg_fatal("select unlock: %m");
-#endif
/*
* Do not bother the application when the client disconnected.
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");
time_left = event_cancel_timer(multi_server_timeout, (char *) 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");
MAIL_SERVER_LOOP_FN loop = 0;
int key;
char *transport = 0;
-
-#ifndef NO_SELECT_COLLISION
char *lock_path;
VSTRING *why;
-
-#endif
int alone = 0;
/*
* Illustrated volume 2 page 532. We avoid select() collisions with an
* external lock file.
*/
-#ifndef NO_SELECT_COLLISION
if (stream == 0 && !alone) {
lock_path = concatenate(DEF_PID_DIR, "/", transport,
".", service_name, (char *) 0);
myfree(lock_path);
vstring_free(why);
}
-#endif
/*
* Run pre-jail initialization.
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
delay = loop ? loop() : -1;
-#ifndef NO_SELECT_COLLISION
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), MYFLOCK_EXCLUSIVE) < 0)
msg_fatal("select lock: %m");
-#endif
event_loop(delay);
}
multi_server_exit();
#include <iostuff.h>
#include <stringops.h>
#include <sane_accept.h>
-#ifndef NO_SELECT_COLLISION
#include <myflock.h>
#include <safe_open.h>
-#endif
#include <listen.h>
/* Global library. */
static char **single_server_argv;
static void (*single_server_accept) (int, char *);
static void (*single_server_onexit) (void);
-
-#ifndef NO_SELECT_COLLISION
static VSTREAM *single_server_lock;
-#endif
-
/* single_server_exit - normal termination */
static NORETURN single_server_exit(void)
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");
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");
MAIL_SERVER_LOOP_FN loop = 0;
int key;
char *transport = 0;
-
-#ifndef NO_SELECT_COLLISION
char *lock_path;
VSTRING *why;
-
-#endif
int alone = 0;
/*
* Illustrated volume 2 page 532. We avoid select() collisions with an
* external lock file.
*/
-#ifndef NO_SELECT_COLLISION
if (stream == 0 && !alone) {
lock_path = concatenate(DEF_PID_DIR, "/", transport,
".", service_name, (char *) 0);
myfree(lock_path);
vstring_free(why);
}
-#endif
/*
* Run pre-jail initialization.
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
while (var_use_limit == 0 || use_count < var_use_limit) {
delay = loop ? loop() : -1;
-#ifndef NO_SELECT_COLLISION
if (single_server_lock != 0
&& myflock(vstream_fileno(single_server_lock), MYFLOCK_EXCLUSIVE) < 0)
msg_fatal("select lock: %m");
-#endif
event_loop(delay);
}
single_server_exit();
#include <iostuff.h>
#include <stringops.h>
#include <sane_accept.h>
-#ifndef NO_SELECT_COLLISION
#include <myflock.h>
#include <safe_open.h>
-#endif
#include <listen.h>
/* Global library. */
static char **trigger_server_argv;
static void (*trigger_server_accept) (int, char *);
static void (*trigger_server_onexit) (void);
-
-#ifndef NO_SELECT_COLLISION
static VSTREAM *trigger_server_lock;
-#endif
-
/* trigger_server_exit - normal termination */
static NORETURN trigger_server_exit(void)
char *myname = "trigger_server_accept_fifo";
int listen_fd = (int) context;
-#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);
time_left = event_cancel_timer(trigger_server_timeout, (char *) 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");
char buf[TRIGGER_BUF_SIZE];
int len;
char *transport = 0;
-
-#ifndef NO_SELECT_COLLISION
char *lock_path;
VSTRING *why;
-
-#endif
int alone = 0;
/*
* Illustrated volume 2 page 532. We avoid select() collisions with an
* external lock file.
*/
-#ifndef NO_SELECT_COLLISION
if (stream == 0 && !alone) {
lock_path = concatenate(DEF_PID_DIR, "/", transport,
".", service_name, (char *) 0);
myfree(lock_path);
vstring_free(why);
}
-#endif
/*
* Run pre-jail initialization.
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
while (var_use_limit == 0 || use_count < var_use_limit) {
delay = loop ? loop() : -1;
-#ifndef NO_SELECT_COLLISION
if (trigger_server_lock != 0
&& myflock(vstream_fileno(trigger_server_lock), MYFLOCK_EXCLUSIVE) < 0)
msg_fatal("select lock: %m");
-#endif
event_loop(delay);
}
trigger_server_exit();
*/
char *smtpd_path;
+/* collapse_args - put arguments together again */
+
+static void collapse_args(int argc, SMTPD_TOKEN *argv)
+{
+ int i;
+
+ for (i = 2; i < argc; i++) {
+ vstring_strcat(argv[1].vstrval, " ");
+ vstring_strcat(argv[1].vstrval, argv[i].strval);
+ }
+ argv[1].strval = vstring_str(argv[1].vstrval);
+}
+
/* helo_cmd - process HELO command */
static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
{
char *err;
- if (argc != 2) {
+ if (argc < 2) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Syntax: HELO hostname");
return (-1);
smtpd_chat_reply(state, "503 Duplicate HELO/EHLO");
return (-1);
}
+ collapse_args(argc, argv);
if (SMTPD_STAND_ALONE(state) == 0
&& (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
smtpd_chat_reply(state, "%s", err);
{
char *err;
- if (argc != 2) {
+ if (argc < 2) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Syntax: EHLO hostname");
return (-1);
smtpd_chat_reply(state, "503 Error: duplicate HELO/EHLO");
return (-1);
}
+ collapse_args(argc, argv);
if (SMTPD_STAND_ALONE(state) == 0
&& (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
smtpd_chat_reply(state, "%s", err);
static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
{
- VSTRING *buf;
char *err = 0;
- int i;
/*
* The SMTP standard (RFC 821) disallows unquoted special characters in
smtpd_chat_reply(state, "501 Syntax: VRFY address");
return (-1);
}
-
- /*
- * Yuck. All input is tokenized. Now put it back together again.
- */
- buf = vstring_alloc(100);
- for (i = 1; i < argc; i++) {
- vstring_strcat(buf, " ");
- vstring_strcat(buf, argv[i].strval);
- }
+ collapse_args(argc, argv);
if (SMTPD_STAND_ALONE(state) == 0)
- err = smtpd_check_rcpt(state, vstring_str(buf));
- vstring_free(buf);
+ err = smtpd_check_rcpt(state, argv[1].strval);
/*
* End untokenize.
/* Reject the request when the HELO/EHLO hostname has no A or MX record.
/* The \fIunknown_hostname_reject_code\fR configuration
/* parameter specifies the reject status code (default: 450).
-/* .IP reject_unknown_address
+/* .IP reject_unknown_sender_domain
/* Reject the request when the resolved sender address has no
/* DNS A or MX record.
/* The \fIunknown_address_reject_code\fR configuration parameter
/* specifies the reject status code (default: 450).
+/* .IP reject_unknown_recipient_domain
+/* Reject the request when the resolved recipient address has no
+/* DNS A or MX record.
+/* The \fIunknown_address_reject_code\fR configuration parameter
+/* specifies the reject status code (default: 450).
/* .IP check_relay_domains
/* Allow the request when either the client hostname or the resolved
/* recipient domain matches the \fIrelay_domains\fR configuration
if (dns_status != DNS_OK)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Domain not found",
- var_unk_addr_code, name));
+ dns_status == DNS_NOTFOUND ?
+ var_unk_addr_code : 450, name));
return (SMTPD_CHECK_DUNNO);
}
*status = reject_unknown_address(state, state->sender);
return (1);
}
+ if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
+ *status = reject_unknown_address(state, state->sender);
+ return (1);
+ }
if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
if (*state->sender)
*status = reject_non_fqdn_address(state, state->sender);
status = permit_mx_backup(state, recipient);
} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
status = check_relay_domains(state, recipient);
+ } else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
+ status = reject_unknown_address(state, recipient);
} else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
status = reject_non_fqdn_address(state, recipient);
} else if (generic_checks(state, name, &cpp, &status, recipient) == 0) {
client_restrictions reject_maps_rbl
client spike.porcupine.org 168.100.189.2
client foo 127.0.0.2
+#
+# unknown sender/recipient domain
+#
+unknown_address_reject_code 550
+recipient_restrictions reject_unknown_recipient_domain,reject_unknown_sender_domain
+mail wietse@porcupine.org
+rcpt wietse@porcupine.org
+rcpt wietse@no.recipient.domain
+mail wietse@no.sender.domain
+rcpt wietse@porcupine.org
>>> client foo 127.0.0.2
./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+>>> #
+>>> # unknown sender/recipient domain
+>>> #
+>>> unknown_address_reject_code 550
+OK
+>>> recipient_restrictions reject_unknown_recipient_domain,reject_unknown_sender_domain
+OK
+>>> mail wietse@porcupine.org
+OK
+>>> rcpt wietse@porcupine.org
+OK
+>>> rcpt wietse@no.recipient.domain
+./smtpd_check: reject: RCPT from foo[127.0.0.2]: 550 <no.recipient.domain>: Domain not found
+550 <no.recipient.domain>: Domain not found
+>>> mail wietse@no.sender.domain
+OK
+>>> rcpt wietse@porcupine.org
+./smtpd_check: reject: RCPT from foo[127.0.0.2]: 550 <no.sender.domain>: Domain not found
+550 <no.sender.domain>: Domain not found
timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
dict_unix.h dict_pcre.h
-TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c
+TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
+ stream_test.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
-Wunused
fifo_rdwr_bug fifo_trigger fsspace fullname inet_addr_host \
inet_addr_local mac_parse make_dirs msg_syslog \
mystrtok peer_name sigdelay translit valid_hostname vstream_popen \
- vstring vstring_vstream doze select_bug
+ vstring vstring_vstream doze select_bug stream_test
LIB_DIR = ../lib
INC_DIR = ../include
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
@make Makefile
+stream_test: stream_test.c $(LIB)
+ $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
+
tests: valid_hostname_test
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
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
stream_listen.o: msg.h
stream_listen.o: listen.h
stream_listen.o: iostuff.h
+stream_test.o: stream_test.c
+stream_test.o: sys_defs.h
+stream_test.o: stream_test.c
+stream_test.o: iostuff.h
+stream_test.o: msg.h
+stream_test.o: msg_vstream.h
+stream_test.o: vstream.h
+stream_test.o: vbuf.h
+stream_test.o: listen.h
+stream_test.o: connect.h
stream_trigger.o: stream_trigger.c
stream_trigger.o: sys_defs.h
stream_trigger.o: msg.h
/* System library. */
#include <sys_defs.h>
+
+#ifdef STREAM_CONNECTIONS
+
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <stropts.h>
+
+#endif
/* Utility library. */
{
#ifdef STREAM_CONNECTIONS
char *myname = "stream_connect";
- struct stat st;
- int fd;
- int flags;
+ int pair[2];
+ int fifo;
/*
* 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)
+ if ((fifo = open(path, O_WRONLY | O_NONBLOCK, 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.
+ * Create a pipe, and send one pipe end to the server.
*/
- if (fstat(fd, &st) < 0)
- msg_fatal("%s: fstat: %m", myname);
- if (S_ISREG(st.st_mode)) {
- close(fd);
- errno = ECONNREFUSED;
- return (-1);
- }
+ if (pipe(pair) < 0)
+ msg_fatal("%s: pipe: %m", myname);
+ if (ioctl(fifo, I_SENDFD, pair[1]) < 0)
+ msg_fatal("%s: send file descriptor: %m", myname);
+ close(pair[1]);
/*
* This is for {unix,inet}_connect() compatibility.
*/
if (block_mode == NON_BLOCKING)
- non_blocking(fd, NON_BLOCKING);
+ non_blocking(pair[0], NON_BLOCKING);
/*
- * No trouble detected, so far.
+ * Cleanup.
*/
- return (fd);
+ close(fifo);
+
+ /*
+ * Keep the other end of the pipe.
+ */
+ return (pair[0]);
#else
msg_fatal("stream connections are not implemented");
#endif
}
-
/* .IP backlog
/* This argument exists for compatibility and is ignored.
/* .IP block_mode
-/* This argument exists for compatibility and is ignored.
-/* blocking mode.
+/* Either NON_BLOCKING or BLOCKING. This does not affect the
+/* mode of accepted connections.
/* .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
/* stream_listen - create stream listener */
-int stream_listen(const char *path, int unused_backlog,
-int unused_block_mode)
+int stream_listen(const char *path, int unused_backlog, int 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.
+ * We can't specify a listen backlog, however, sending file descriptors
+ * across a FIFO gives us a backlog buffer of 460 on Solaris 2.4/SPARC.
*/
- 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]);
+ return (fifo_listen(path, 0666, block_mode));
#else
msg_fatal("stream connections are not implemented");
#endif
return (-1);
return (fdinfo.fd);
#else
- msg_fatal("stream connections are not implemented");
+ msg_fatal("stream connections are not implemented");
#endif
}
#include "msg.h"
#include "msg_vstream.h"
#include "listen.h"
+#include "connect.h"
#define FIFO "/tmp/test-fifo"
main(int argc, char **argv)
{
- struct strrecvfd fdinfo;
int server_fd;
int client_fd;
+ int fd;
int print_fstats = 0;
int count = 1;
int ch;
break;
}
}
- server_fd = fifo_listen(FIFO, 0600, NON_BLOCKING);
+ server_fd = stream_listen(FIFO, 0, 0);
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");
+ msg_info("connect attempt %d", i);
+ if ((client_fd = stream_connect(FIFO, 0, 0)) < 0)
+ msg_fatal("open %s as client: %m", FIFO);
+ if (readable(server_fd))
+ msg_info("server fd is readable after client open");
+ if (close(client_fd) < 0)
+ msg_fatal("close client fd: %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)
+ if (!readable(server_fd)) {
+ msg_info("wait for server fd to become readable");
+ read_wait(server_fd, -1);
+ }
+ if ((fd = stream_accept(server_fd)) < 0)
msg_fatal("receive fd: %m");
if (print_fstats)
- print_fstat(fdinfo.fd);
- if (close(fdinfo.fd) < 0)
+ print_fstat(fd);
+ if (close(fd) < 0)
msg_fatal("close received fd: %m");
}
+ if (close(server_fd) < 0)
+ msg_fatal("close server fd");
}