socket.c revision 440be4c866f6935ac069db79a414304507a664c2
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * Copyright (C) 1998, 1999 Internet Software Consortium.
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * Permission to use, copy, modify, and distribute this software for any
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * purpose with or without fee is hereby granted, provided that the above
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * copyright notice and this permission notice appear in all copies.
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * Some systems define the socket length argument as an int, some as size_t,
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * some as socklen_t. This is here so it can be easily changed if needed.
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews#define ISC_SOCKADDR_LEN_T unsigned int
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * Define what the possible "soft" errors can be. These are non-fatal returns
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * of various network related functions, like recv() and so on.
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * For some reason, BSDI (and perhaps others) will sometimes return <0
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * from recv() but will have errno==0. This is broken, but we have to
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * work around it here.
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews#define XTRACE(l, a) do { \
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews if ((l) & trace_level) { \
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews#define XENTER(l, a) do { \
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews#define XEXIT(l, a) do { \
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews#define VALID_SOCKET(t) ((t) != NULL && (t)->magic == SOCKET_MAGIC)
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * IPv6 control information. If the socket is an IPv6 socket we want
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * to collect the destination address and interface so the client can
3b83676e079a799f97ad8b76c057e6ecb0426b1dMark Andrews * set them on outgoing packets.
#ifdef ISC_PLATFORM_HAVEIPV6
#ifndef USE_CMSG
#define PKTINFO_SPACE 0
#ifdef SO_TIMESTAMP
#ifndef USE_CMSG
#define TIMESTAMP_SPACE 0
#ifdef USE_CMSG
struct isc_socket {
unsigned int magic;
unsigned int references;
int fd;
#ifdef ISC_NET_RECVOVERFLOW
#ifdef USE_CMSG
struct isc_socketmgr {
unsigned int magic;
int maxfd;
#ifdef ISC_NET_RECVOVERFLOW
isc_socket_t **);
size_t *);
size_t *);
int cc;
if (cc < 0)
int msg;
int cc;
if (cc < 0) {
return (SELECT_POKE_NOTHING);
return (SELECT_POKE_NOTHING);
return (msg);
static isc_result_t
int ret;
int flags;
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
#ifdef USE_CMSG
#ifdef ISC_PLATFORM_HAVEIPV6
#ifdef SO_TIMESTAMP
(void)sock;
#ifdef ISC_NET_BSD44MSGHDR
#ifdef MSG_TRUNC
#ifdef MSG_CTRUNC
#ifndef USE_CMSG
#ifdef SO_TIMESTAMP
#ifdef ISC_PLATFORM_HAVEIPV6
#ifdef ISC_PLATFORM_HAVEIPV6
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(USE_CMSG)
unsigned int iovcount;
#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;
#if defined(ISC_SOCKET_DEBUG)
if (cc < 0) {
return (DOIO_SOFT);
return (DOIO_HARD); \
return (DOIO_SOFT); \
return (DOIO_HARD);
return (DOIO_SUCCESS);
return (DOIO_EOF);
#ifdef ISC_NET_RECVOVERFLOW
cc--;
actual_count = 0;
return (DOIO_SOFT);
return (DOIO_SUCCESS);
int cc;
if (cc < 0) {
return (DOIO_SOFT);
return (DOIO_HARD); \
return (DOIO_SOFT); \
return (DOIO_HARD);
return (DOIO_HARD);
if (cc == 0)
return (DOIO_SOFT);
return (DOIO_SUCCESS);
static isc_result_t
return (ISC_R_NOMEMORY);
goto err1;
return (ISC_R_SUCCESS);
return (ret);
#if defined(USE_CMSG)
return (ret);
switch (type) {
case isc_sockettype_udp:
case isc_sockettype_tcp:
switch (errno) {
case EMFILE:
case ENFILE:
case ENOBUFS:
return (ISC_R_NORESOURCES);
return (ISC_R_UNEXPECTED);
return (ISC_R_UNEXPECTED);
#if defined(USE_CMSG)
#if defined(SO_TIMESTAMP)
#if defined(ISC_PLATFORM_HAVEIPV6)
return (ISC_R_SUCCESS);
if (kill_socket)
int fd;
(void)me;
if (fd < 0) {
(void)me;
goto next;
goto next;
case DOIO_SOFT:
goto poke;
case DOIO_EOF:
goto poke;
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
case DOIO_HARD:
next:
poke:
(void)me;
goto next;
goto next;
case DOIO_SOFT:
goto poke;
case DOIO_HARD:
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
next:
poke:
static isc_threadresult_t
int ctlfd;
int cc;
int msg;
int maxfd;
while (!done) {
#ifdef ISC_SOCKET_DEBUG
for (i = 0 ; i < FD_SETSIZE ; i++) {
int printit;
printit = 0;
if (cc < 0) {
} while (cc < 0);
if (msg >= 0) {
msg));
sock));
for (i = 0 ; i < maxfd ; i++) {
close(i);
goto check_write;
if (!unlock_sock) {
if (unlock_sock)
return ((isc_threadresult_t)0);
return (ISC_R_NOMEMORY);
return (ISC_R_UNEXPECTED);
return (ISC_R_UNEXPECTED);
return (ISC_R_UNEXPECTED);
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
for (i = 0 ; i < FD_SETSIZE ; i++)
close(i);
unsigned int minimum,
unsigned int iocount;
return (ISC_R_NOMEMORY);
if (minimum == 0)
if (!was_empty)
goto queue;
return (ISC_R_SUCCESS);
case DOIO_SOFT:
goto queue;
case DOIO_EOF:
return (ISC_R_SUCCESS);
case DOIO_HARD:
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
return (ISC_R_SUCCESS);
if (was_empty)
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
if (minimum == 0)
dev->n = 0;
if (!was_empty)
goto queue;
return (ISC_R_SUCCESS);
case DOIO_SOFT:
goto queue;
case DOIO_EOF:
return (ISC_R_SUCCESS);
case DOIO_HARD:
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
return (ISC_R_SUCCESS);
if (was_empty)
return (ISC_R_SUCCESS);
NULL));
return (ISC_R_NOMEMORY);
if (!was_empty)
goto queue;
return (ISC_R_SUCCESS);
case DOIO_SOFT:
goto queue;
case DOIO_HARD:
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
return (ISC_R_SUCCESS);
if (was_empty)
return (ISC_R_SUCCESS);
NULL));
unsigned int iocount;
return (ISC_R_NOMEMORY);
if (!was_empty)
goto queue;
return (ISC_R_SUCCESS);
case DOIO_SOFT:
goto queue;
case DOIO_HARD:
case DOIO_UNEXPECTED:
case DOIO_SUCCESS:
return (ISC_R_SUCCESS);
if (was_empty)
return (ISC_R_SUCCESS);
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);
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
if (backlog == 0)
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
return (ret);
return (ISC_R_SUCCESS);
int cc;
sizeof (*dev));
return (ISC_R_NOMEMORY);
if (cc < 0) {
goto queue;
switch (errno) {
case ECONNREFUSED:
goto err_exit;
case ENETUNREACH:
goto err_exit;
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
if (cc == 0) {
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
int cc;
(void)me;
if (errno != 0) {
switch (errno) {
case ETIMEDOUT:
case ECONNREFUSED:
case ENETUNREACH:
return (ISC_R_SUCCESS);
return (ISC_R_UNEXPECTED);
return (ISC_R_SUCCESS);
if (how == 0)
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);