/*++ /* NAME /* sane_accept 3 /* SUMMARY /* sanitize accept() error returns /* SYNOPSIS /* #include /* /* int sane_accept(sock, buf, len) /* int sock; /* struct sockaddr *buf; /* SOCKADDR_SIZE *len; /* DESCRIPTION /* sane_accept() implements the accept(2) socket call, and maps /* known harmless error results to EAGAIN. /* /* If the buf and len arguments are not null, then additional /* workarounds may be enabled that depend on the socket type. /* BUGS /* Bizarre systems may have other harmless error results. Such /* systems encourage programers to ignore error results, and /* penalizes programmers who code defensively. /* 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 #include /* Utility library. */ #include "msg.h" #include "sane_accept.h" /* sane_accept - sanitize accept() error returns */ int sane_accept(int sock, struct sockaddr * sa, SOCKADDR_SIZE *len) { static int accept_ok_errors[] = { EAGAIN, ECONNREFUSED, ECONNRESET, EHOSTDOWN, EHOSTUNREACH, EINTR, ENETDOWN, ENETUNREACH, ENOTCONN, EWOULDBLOCK, ENOBUFS, /* HPUX11 */ ECONNABORTED, 0, }; int count; int err; int fd; /* * XXX Solaris 2.4 accept() returns EPIPE when a UNIX-domain client has * disconnected in the mean time. From then on, UNIX-domain sockets are * hosed beyond recovery. There is no point treating this as a beneficial * error result because the program would go into a tight loop. * * XXX LINUX < 2.1 accept() wakes up before the three-way handshake is * complete, so it can fail with ECONNRESET and other "false alarm" * indications. * * XXX FreeBSD 4.2-STABLE accept() returns ECONNABORTED when a UNIX-domain * client has disconnected in the mean time. The data that was sent with * connect() write() close() is lost, even though the write() and close() * reported successful completion. This was fixed shortly before FreeBSD * 4.3. * * XXX HP-UX 11 returns ENOBUFS when the client has disconnected in the mean * time. */ if ((fd = accept(sock, sa, len)) < 0) { for (count = 0; (err = accept_ok_errors[count]) != 0; count++) { if (errno == err) { errno = EAGAIN; break; } } } /* * XXX Solaris select() produces false read events, so that read() blocks * forever on a blocking socket, and fails with EAGAIN on a non-blocking * socket. Turning on keepalives will fix a blocking socket provided that * the kernel's keepalive timer expires before the Postfix watchdog * timer. */ #if defined(BROKEN_READ_SELECT_ON_TCP_SOCKET) && defined(SO_KEEPALIVE) else if (sa != 0 && sa->sa_family == AF_INET) { int on = 1; (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)); } #endif return (fd); }