socket.c revision 1bb3831e13a65afd87078c88e0285d23b1e0bcdf
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
ddccd5811feff696ba460dabfb666ce61040f545Andreas Gustafsson * Copyright (C) 1998-2003 Internet Software Consortium.
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and/or distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
ddccd5811feff696ba460dabfb666ce61040f545Andreas Gustafsson * copyright notice and this permission notice appear in all copies.
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * PERFORMANCE OF THIS SOFTWARE.
ddccd5811feff696ba460dabfb666ce61040f545Andreas Gustafsson/* $Id: socket.c,v 1.350 2012/01/27 01:21:41 marka Exp $ */
ddccd5811feff696ba460dabfb666ce61040f545Andreas Gustafsson/* See task.c about the following definition: */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* ISC_PLATFORM_USETHREADS */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#endif /* BIND9 */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* USE_WATCHER_THREAD */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Choose the most preferable multiplex method.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeintypedef struct {
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* ISC_PLATFORM_HAVEKQUEUE */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* USE_KQUEUE */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* !USE_WATCHER_THREAD */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Maximum number of allowable open sockets. This is also the maximum
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * allowable socket file descriptor.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Care should be taken before modifying this value for select():
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * The API standard doesn't ensure select() accept more than (the system default
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * of) FD_SETSIZE descriptors, and the default size should in fact be fine in
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * the vast majority of cases. This constant should therefore be increased only
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * when absolutely necessary and possible, i.e., the server is exhausting all
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * available file descriptors (up to FD_SETSIZE) and the select() function
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * and FD_xxx macros support larger values than FD_SETSIZE (which may not
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * always by true, but we keep using some of them to ensure as much
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * portability as possible). Note also that overall server performance
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * may be rather worsened with a larger value of this constant due to
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * inherent scalability problems of select().
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * As a special note, this value shouldn't have to be touched if
30eec077db2bdcb6f2a0dc388a3cdde2ede75ec1Mark Andrews * this is a build for an authoritative only DNS server.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* USE_KQUEUE... */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#endif /* ISC_SOCKET_MAXSOCKETS */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Mac OS X needs a special definition to support larger values in select().
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * We always define this because a larger value can be specified run-time.
#ifdef __APPLE__
#define _DARWIN_UNLIMITED_SELECT
#ifdef ISC_SOCKET_USE_POLLWATCH
#ifndef ISC_SOCKET_POLLWATCH_TIMEOUT
#ifdef ISC_PLATFORM_USETHREADS
#ifndef ISC_SOCKET_MAXEVENTS
#ifndef ISC_SOCKADDR_LEN_T
#define ISC_SOCKADDR_LEN_T unsigned int
(e) == EWOULDBLOCK || \
(e) == EINTR || \
* DLVL(20) -- Socket creation/destruction.
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
#ifndef USE_CMSG
#ifdef SO_TIMESTAMP
#ifndef USE_CMSG
struct isc__socket {
unsigned int references;
int fd;
int pf;
void * tag;
#ifdef ISC_NET_RECVOVERFLOW
char *recvcmsgbuf;
char *sendcmsgbuf;
void *fdwatcharg;
int fdwatchflags;
struct isc__socketmgr {
#ifdef USE_KQUEUE
int kqueue_fd;
int nevents;
#ifdef USE_EPOLL
int epoll_fd;
int nevents;
#ifdef USE_DEVPOLL
int devpoll_fd;
int nevents;
#ifdef USE_SELECT
int fd_bufsize;
unsigned int maxsocks;
#ifdef ISC_PLATFORM_USETHREADS
int *fdstate;
#ifdef USE_DEVPOLL
#ifdef USE_SELECT
int maxfd;
#ifdef USE_WATCHER_THREAD
unsigned int refs;
int maxudp;
#ifdef USE_SHARED_MANAGER
#ifdef ISC_NET_RECVOVERFLOW
isc__socket_t **);
#ifdef USE_WATCHER_THREAD
#ifdef BIND9
#define ISC_SOCKETFUNC_SCOPE
#define ISC_SOCKETFUNC_SCOPE static
ISC_SOCKETFUNC_SCOPE void
ISC_SOCKETFUNC_SCOPE void
unsigned int maxsocks);
ISC_SOCKETFUNC_SCOPE void
ISC_SOCKETFUNC_SCOPE void
unsigned int options);
const void *arg);
ISC_SOCKETFUNC_SCOPE void
ISC_SOCKETFUNC_SCOPE void
ISC_SOCKETFUNC_SCOPE void
#ifndef BIND9
} socketmethods = {
#ifndef BIND9
(void *)isc__socket_isbound
STATID_OPEN = 0,
defined(USE_WATCHER_THREAD)
const char *fmt, ...)
const char *fmt, ...)
strbuf);
static inline isc_result_t
#ifdef USE_KQUEUE
return (result);
return (result);
return (result);
return (result);
static inline isc_result_t
#ifdef USE_KQUEUE
return (result);
return (result);
return (result);
return (result);
#ifdef USE_WATCHER_THREAD
int cc;
#ifdef ENOSR
if (cc < 0) {
strbuf);
int cc;
if (cc < 0) {
strbuf);
else if (fd >= 0)
static isc_result_t
int ret;
int flags;
#ifdef USE_FIONBIO_IOCTL
#ifdef USE_FIONBIO_IOCTL
strbuf);
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
#ifdef USE_CMSG
static inline ISC_SOCKADDR_LEN_T
#ifdef CMSG_LEN
static inline ISC_SOCKADDR_LEN_T
#ifdef CMSG_SPACE
#ifdef USE_CMSG
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
#ifdef SO_TIMESTAMP
#ifdef ISC_NET_BSD44MSGHDR
#ifdef MSG_TRUNC
#ifdef MSG_CTRUNC
#ifndef USE_CMSG
#ifdef SO_TIMESTAMP
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
sizeof(struct in6_pktinfo));
goto next;
#ifdef SO_TIMESTAMP
goto next;
next:
unsigned int iovcount;
write_count = 0;
iovcount = 0;
goto config;
+ skip_count);
skip_count = 0;
iovcount++;
#ifdef ISC_NET_BSD44MSGHDR
#if defined(IPV6_USE_MIN_MTU)
#if defined(IPV6_USE_MIN_MTU)
unsigned int iovcount;
#ifdef BROKEN_RECVMSG
#ifdef ISC_PLATFORM_HAVESYSUNH
#ifdef ISC_NET_RECVOVERFLOW
maxiov--;
read_count = 0;
goto config;
iovcount = 0;
iovcount++;
#ifdef ISC_NET_RECVOVERFLOW
iovcount++;
#ifdef ISC_NET_BSD44MSGHDR
#if defined(USE_CMSG)
static isc_socketevent_t *
sizeof(*ev));
return (NULL);
ev->n = 0;
return (ev);
#if defined(ISC_SOCKET_DEBUG)
#ifdef ISC_NET_BSD44MSGHDR
int cc;
int recv_errno;
#if defined(ISC_SOCKET_DEBUG)
#if defined(ISC_SOCKET_DEBUG)
if (cc < 0) {
return (DOIO_SOFT);
return (DOIO_HARD); \
return (DOIO_SOFT); \
return (DOIO_HARD); \
#ifdef EPROTO
return (DOIO_HARD);
case isc_sockettype_tcp:
case isc_sockettype_unix:
if (cc == 0)
return (DOIO_EOF);
case isc_sockettype_udp:
case isc_sockettype_fdwatch:
INSIST(0);
return (DOIO_SOFT);
return (DOIO_SOFT);
#ifdef ISC_NET_RECVOVERFLOW
cc--;
actual_count = 0;
return (DOIO_SOFT);
return (DOIO_SUCCESS);
int cc;
int attempts = 0;
int send_errno;
if (cc < 0) {
goto resend;
return (DOIO_SOFT);
return (DOIO_HARD); \
return (DOIO_SOFT); \
return (DOIO_HARD); \
#ifdef EHOSTDOWN
return (DOIO_HARD);
if (cc == 0) {
return (DOIO_SOFT);
return (DOIO_SUCCESS);
#ifdef USE_SELECT
#ifdef ISC_PLATFORM_USETHREADS
int fd;
#ifdef USE_WATCHER_THREAD
static isc_result_t
return (ISC_R_NOMEMORY);
cmsgbuflen = 0;
goto error;
cmsgbuflen = 0;
#if defined(IPV6_USE_MIN_MTU)
goto error;
goto error;
return (ISC_R_SUCCESS);
return (result);
#ifdef SO_BSDCOMPAT
clear_bsdcompat(void) {
#ifdef __linux__
char *endp;
long int major;
long int minor;
static isc_result_t
int tries = 0;
#if defined(SO_RCVBUF)
int size;
case isc_sockettype_udp:
case isc_sockettype_tcp:
case isc_sockettype_unix:
case isc_sockettype_fdwatch:
INSIST(0);
goto again;
#ifdef F_DUPFD
return (ISC_R_NORESOURCES);
switch (errno) {
case EMFILE:
case ENFILE:
case ENOBUFS:
return (ISC_R_NORESOURCES);
case EPROTONOSUPPORT:
case EPFNOSUPPORT:
case EAFNOSUPPORT:
case EINVAL:
return (ISC_R_FAMILYNOSUPPORT);
strbuf);
return (ISC_R_UNEXPECTED);
goto setup_done;
return (result);
#ifdef SO_BSDCOMPAT
strbuf);
#ifdef SO_NOSIGPIPE
strbuf);
#if defined(USE_CMSG)
#if defined(SO_TIMESTAMP)
strbuf);
#if defined(ISC_PLATFORM_HAVEIPV6)
#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
#ifdef IPV6_RECVPKTINFO
strbuf);
strbuf);
strbuf);
#if defined(IPV6_MTU)
sizeof(action));
#if defined(IP_DONTFRAG)
int off = 0;
#if defined(SO_RCVBUF)
strbuf);
return (ISC_R_SUCCESS);
static isc_result_t
int lockid;
return (result);
case isc_sockettype_udp:
case isc_sockettype_tcp:
case isc_sockettype_unix:
INSIST(0);
return (result);
#ifdef USE_DEVPOLL
#ifdef USE_SELECT
return (ISC_R_SUCCESS);
sock0));
#ifdef BIND9
#ifdef USE_DEVPOLL
#ifdef USE_SELECT
return (result);
int lockid;
return (result);
#ifdef USE_SELECT
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
ISC_SOCKETFUNC_SCOPE void
ISC_SOCKETFUNC_SCOPE void
if (kill_socket)
#ifdef BIND9
int fd;
return (ISC_R_SUCCESS);
int fd;
(void *)&addrlen);
#ifdef F_DUPFD
if (fd < 0) {
goto soft_error;
switch (errno) {
case ENFILE:
case EMFILE:
err);
goto soft_error;
case ENOBUFS:
case ENOMEM:
case ECONNRESET:
case ECONNABORTED:
case EHOSTUNREACH:
case EHOSTDOWN:
case ENETUNREACH:
case ENETDOWN:
case ECONNREFUSED:
#ifdef EPROTO
case EPROTO:
#ifdef ENONET
case ENONET:
goto soft_error;
strbuf);
if (addrlen == 0U) {
goto soft_error;
goto soft_error;
goto soft_error;
#ifdef USE_SELECT
case DOIO_SOFT:
goto poke;
case DOIO_EOF:
goto poke;
case DOIO_SUCCESS:
case DOIO_HARD:
poke:
case DOIO_SOFT:
goto poke;
case DOIO_HARD:
case DOIO_SUCCESS:
poke:
int more_data;
if (more_data)
int more_data;
if (more_data)
if (readable) {
goto check_write;
if (writeable) {
goto unlock_fd;
if (!unlock_sock) {
if (unlock_sock)
if (unwatch_read)
if (unwatch_write)
#ifdef USE_KQUEUE
static isc_boolean_t
#ifdef USE_WATCHER_THREAD
nevents);
for (i = 0; i < nevents; i++) {
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
if (have_ctlevent)
return (done);
static isc_boolean_t
#ifdef USE_WATCHER_THREAD
nevents);
for (i = 0; i < nevents; i++) {
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
if (have_ctlevent)
return (done);
static isc_boolean_t
#ifdef USE_WATCHER_THREAD
nevents);
for (i = 0; i < nevents; i++) {
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
if (have_ctlevent)
return (done);
for (i = 0; i < maxfd; i++) {
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
static isc_threadresult_t
int cc;
#ifdef USE_KQUEUE
int maxfd;
int ctlfd;
#ifdef ISC_SOCKET_USE_POLLWATCH
#if defined (USE_SELECT)
while (!done) {
#ifdef USE_KQUEUE
#ifndef ISC_SOCKET_USE_POLLWATCH
if (cc == 0) {
} else if (cc > 0) {
} while (cc < 0);
return ((isc_threadresult_t)0);
#ifdef BIND9
ISC_SOCKETFUNC_SCOPE void
ISC_SOCKETFUNC_SCOPE void
static isc_result_t
#ifdef USE_KQUEUE
return (ISC_R_NOMEMORY);
strbuf);
return (result);
#ifdef USE_WATCHER_THREAD
return (result);
return (ISC_R_NOMEMORY);
strbuf);
return (result);
#ifdef USE_WATCHER_THREAD
return (result);
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
strbuf);
return (result);
#ifdef USE_WATCHER_THREAD
return (result);
sizeof(fd_mask);
return (ISC_R_NOMEMORY);
#ifdef USE_WATCHER_THREAD
return (ISC_R_SUCCESS);
#ifdef USE_WATCHER_THREAD
#ifdef USE_KQUEUE
unsigned int maxsocks)
#ifdef USE_WATCHER_THREAD
#ifdef USE_SHARED_MANAGER
return (ISC_R_EXISTS);
return (ISC_R_SUCCESS);
if (maxsocks == 0)
return (ISC_R_NOMEMORY);
goto free_manager;
goto free_manager;
goto free_manager;
goto cleanup_lock;
for (i = 0; i < FDLOCK_COUNT; i++) {
goto cleanup_lock;
#ifdef USE_WATCHER_THREAD
goto cleanup_lock;
strbuf);
goto cleanup_condition;
#ifdef USE_SHARED_MANAGER
goto cleanup;
#ifdef USE_WATCHER_THREAD
goto cleanup;
#ifdef USE_SHARED_MANAGER
return (ISC_R_SUCCESS);
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
for (i = 0; i < FDLOCK_COUNT; i++)
return (result);
#ifdef BIND9
return (ISC_R_SUCCESS);
ISC_SOCKETFUNC_SCOPE void
#ifdef USE_SHARED_MANAGER
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
#ifdef USE_WATCHER_THREAD
(void)close(i);
for (i = 0; i < FDLOCK_COUNT; i++)
#ifdef USE_SHARED_MANAGER
static isc_result_t
unsigned int flags)
int io_state;
switch (io_state) {
case DOIO_SOFT:
if (!have_lock) {
case DOIO_EOF:
case DOIO_HARD:
case DOIO_SUCCESS:
if (have_lock)
return (result);
unsigned int iocount;
return (ISC_R_NOMEMORY);
if (minimum == 0)
return (ISC_R_NOMEMORY);
event->n = 0;
if (minimum == 0)
static isc_result_t
unsigned int flags)
int io_state;
switch (io_state) {
case DOIO_SOFT:
if (!have_lock) {
case DOIO_HARD:
case DOIO_SUCCESS:
if (have_lock)
return (result);
NULL));
return (ISC_R_NOMEMORY);
NULL));
unsigned int iocount;
return (ISC_R_NOMEMORY);
event->n = 0;
ISC_SOCKETFUNC_SCOPE void
#ifdef ISC_PLATFORM_HAVESYSUNH
#ifndef S_ISSOCK
#ifndef S_ISFIFO
#ifndef S_ISFIFO
#ifndef S_ISSOCK
if (active) {
switch (errno) {
goto cleanup;
goto cleanup;
switch (errno) {
case ECONNREFUSED:
case ECONNRESET:
strbuf);
close(s);
#ifdef ISC_PLATFORM_HAVESYSUNH
#ifdef NEED_SECURE_DIRECTORY
char *slash;
#ifdef NEED_SECURE_DIRECTORY
strbuf);
return (result);
return (ISC_R_NOTIMPLEMENTED);
unsigned int options) {
return (ISC_R_FAMILYMISMATCH);
#ifdef AF_UNIX
goto bind_socket;
sizeof(on)) < 0) {
#ifdef AF_UNIX
switch (errno) {
case EACCES:
return (ISC_R_NOPERM);
case EADDRNOTAVAIL:
return (ISC_R_ADDRNOTAVAIL);
case EADDRINUSE:
return (ISC_R_ADDRINUSE);
case EINVAL:
return (ISC_R_BOUND);
strbuf);
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
strbuf);
return (ISC_R_FAILURE);
return (ISC_R_SUCCESS);
return (ISC_R_NOTIMPLEMENTED);
if (backlog == 0)
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
return (result);
return (ISC_R_SHUTTINGDOWN);
if (do_poke)
return (ISC_R_SUCCESS);
int cc;
return (ISC_R_MULTICAST);
sizeof(*dev));
return (ISC_R_NOMEMORY);
if (cc < 0) {
cc = 0;
goto success;
goto queue;
switch (errno) {
#ifdef EHOSTDOWN
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
if (cc == 0) {
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
int cc;
if (errno != 0) {
switch (errno) {
#ifdef EHOSTDOWN
sizeof(peerbuf));
return (result);
goto out;
strbuf);
goto out;
out:
return (result);
ISC_SOCKETFUNC_SCOPE void
if (how == 0)
ev_link);
return (val);
ISC_SOCKETFUNC_SCOPE void
#if defined(IPV6_V6ONLY)
#ifdef IPV6_V6ONLY
(void *)&onoff, sizeof(int)) < 0) {
strbuf);
#ifndef USE_WATCHER_THREAD
#ifdef USE_KQUEUE
#ifdef USE_EPOLL
int timeout;
#ifdef USE_DEVPOLL
#ifdef USE_SHARED_MANAGER
#ifdef USE_KQUEUE
tsp);
#ifdef USE_SHARED_MANAGER
return (ISC_R_NOTFOUND);
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
#ifdef BIND9
ISC_SOCKETFUNC_SCOPE const char *
#ifdef USE_SOCKETIMPREGISTER
ISC_SOCKETFUNC_SCOPE void
#ifdef USE_SHARED_MANAGER
sizeof(peerbuf));