Files
bind9/lib/isc/include/isc/socket.h
David Lawrence 87cafc5e70 Megacommit of many files.
Mostly, several functions that take pointers as arguments, almost
always char * pointers, had those pointers qualified with "const".
Those that returned pointers to previously const-qualified arguments
had their return values qualified as const.  Some structure members
were qualified as const to retain that attribute from the variables
from which they were assigned.

The macro DE_CONST was added to isc/util.h to deal with a handful of very
special places where something is qualified as const but really needs to have
its const qualifier removed.

Also cleaned up a few places where variable names clashed with reserved
identifiers.  (Which mostly works fine, but strictly speaking is undefined
by the standard.)

Minor other ISC style cleanups.
2000-06-01 17:20:56 +00:00

664 lines
16 KiB
C

/*
* Copyright (C) 1998, 1999, 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#ifndef ISC_SOCKET_H
#define ISC_SOCKET_H 1
/*****
***** Module Info
*****/
/*
* Sockets
*
* Provides TCP and UDP sockets for network I/O. The sockets are event
* sources in the task system.
*
* When I/O completes, a completion event for the socket is posted to the
* event queue of the task which requested the I/O.
*
* MP:
* The module ensures appropriate synchronization of data structures it
* creates and manipulates.
*
* Clients of this module must not be holding a socket's task's lock when
* making a call that affects that socket. Failure to follow this rule
* can result in deadlock.
*
* The caller must ensure that isc_socketmgr_destroy() is called only
* once for a given manager.
*
* Reliability:
* No anticipated impact.
*
* Resources:
* <TBS>
*
* Security:
* No anticipated impact.
*
* Standards:
* None.
*/
/***
*** Imports
***/
#include <isc/lang.h>
#include <isc/types.h>
#include <isc/event.h>
#include <isc/eventclass.h>
#include <isc/time.h>
#include <isc/region.h>
#include <isc/sockaddr.h>
ISC_LANG_BEGINDECLS
/***
*** Constants
***/
/*
* Maximum number of buffers in a scatter/gather read/write. The operating
* system in use must support at least this number (plus one on some.)
*/
#define ISC_SOCKET_MAXSCATTERGATHER 8
/***
*** Types
***/
struct isc_socketevent {
ISC_EVENT_COMMON(isc_socketevent_t);
isc_result_t result; /* OK, EOF, whatever else */
unsigned int minimum; /* minimum i/o for event */
unsigned int n; /* bytes read or written */
unsigned int offset; /* offset into buffer list */
isc_region_t region; /* for single-buffer i/o */
isc_bufferlist_t bufferlist; /* list of buffers */
isc_sockaddr_t address; /* source address */
isc_time_t timestamp; /* timestamp of packet recv */
struct in6_pktinfo pktinfo; /* ipv6 pktinfo */
isc_uint32_t attributes; /* see below */
};
typedef struct isc_socket_newconnev isc_socket_newconnev_t;
struct isc_socket_newconnev {
ISC_EVENT_COMMON(isc_socket_newconnev_t);
isc_socket_t * newsocket;
isc_result_t result; /* OK, EOF, whatever else */
isc_sockaddr_t address; /* source address */
};
typedef struct isc_socket_connev isc_socket_connev_t;
struct isc_socket_connev {
ISC_EVENT_COMMON(isc_socket_connev_t);
isc_result_t result; /* OK, EOF, whatever else */
};
/*
* _ATTACHED: Internal use only.
* _FATALERROR: The socket result code is "sticky" -- that is, any
* further i/o activity of the same type (read or write)
* will return the same code; retrying is pointless.
* _TRUNC: Packet was truncated on receive.
* _CTRUNC: Packet control information was truncated. This can
* indicate that the packet is not complete, even though
* all the data is valid.
* _TIMESTAMP: The timestamp member is valid.
* _PKTINFO: The pktinfo member is valid.
*/
#define ISC_SOCKEVENTATTR_ATTACHED 0x80000000U /* internal */
#define ISC_SOCKEVENTATTR_FATALERROR 0x40000000U /* sock is dead */
#define ISC_SOCKEVENTATTR_TRUNC 0x00800000U /* public */
#define ISC_SOCKEVENTATTR_CTRUNC 0x00400000U /* public */
#define ISC_SOCKEVENTATTR_TIMESTAMP 0x00200000U /* public */
#define ISC_SOCKEVENTATTR_PKTINFO 0x00100000U /* public */
#define ISC_SOCKEVENT_ANYEVENT (0)
#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)
#define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3)
#define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4)
#define ISC_SOCKEVENT_RECVMARK (ISC_EVENTCLASS_SOCKET + 5)
#define ISC_SOCKEVENT_SENDMARK (ISC_EVENTCLASS_SOCKET + 6)
/*
* Internal events.
*/
#define ISC_SOCKEVENT_INTR (ISC_EVENTCLASS_SOCKET + 256)
#define ISC_SOCKEVENT_INTW (ISC_EVENTCLASS_SOCKET + 257)
typedef enum {
isc_sockettype_udp = 1,
isc_sockettype_tcp = 2
} isc_sockettype_t;
/*
* How a socket should be shutdown in isc_socket_shutdown() calls.
*/
#define ISC_SOCKSHUT_RECV 0x00000001 /* close read side */
#define ISC_SOCKSHUT_SEND 0x00000002 /* close write side */
#define ISC_SOCKSHUT_ALL 0x00000003 /* close them all */
/*
* What I/O events to cancel in isc_socket_cancel() calls.
*/
#define ISC_SOCKCANCEL_RECV 0x00000001 /* cancel recv */
#define ISC_SOCKCANCEL_SEND 0x00000002 /* cancel send */
#define ISC_SOCKCANCEL_ACCEPT 0x00000004 /* cancel accept */
#define ISC_SOCKCANCEL_CONNECT 0x00000008 /* cancel connect */
#define ISC_SOCKCANCEL_ALL 0x0000000f /* cancel everything */
/***
*** Socket and Socket Manager Functions
***
*** Note: all Ensures conditions apply only if the result is success for
*** those functions which return an isc_result.
***/
isc_result_t
isc_socket_create(isc_socketmgr_t *manager,
int pf,
isc_sockettype_t type,
isc_socket_t **socketp);
/*
* Create a new 'type' socket managed by 'manager'.
*
* Note:
*
* 'pf' is the desired protocol family, e.g. PF_INET or PF_INET6.
*
* Requires:
*
* 'manager' is a valid manager
*
* 'socketp' is a valid pointer, and *socketp == NULL
*
* Ensures:
*
* '*socketp' is attached to the newly created socket
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_NORESOURCES
* ISC_R_UNEXPECTED
*/
void
isc_socket_cancel(isc_socket_t *sock, isc_task_t *task,
unsigned int how);
/*
* Cancel pending I/O of the type specified by "how".
*
* Note: if "task" is NULL, then the cancel applies to all tasks using the
* socket.
*
* Requires:
*
* "socket" is a valid socket
*
* "task" is NULL or a valid task
*
* "how" is a bitmask describing the type of cancelation to perform.
* The type ISC_SOCKCANCEL_ALL will cancel all pending I/O on this
* socket.
*
* ISC_SOCKCANCEL_RECV:
* Cancel pending isc_socket_recv() calls.
*
* ISC_SOCKCANCEL_SEND:
* Cancel pending isc_socket_send() and isc_socket_sendto() calls.
*
* ISC_SOCKCANCEL_ACCEPT:
* Cancel pending isc_socket_accept() calls.
*
* ISC_SOCKCANCEL_CONNECT:
* Cancel pending isc_socket_connect() call.
*/
void
isc_socket_shutdown(isc_socket_t *sock, unsigned int how);
/*
* Shutdown 'socket' according to 'how'.
*
* Requires:
*
* 'socket' is a valid socket.
*
* 'task' is NULL or is a valid task.
*
* If 'how' is 'ISC_SOCKSHUT_RECV' or 'ISC_SOCKSHUT_ALL' then
*
* The read queue must be empty.
*
* No further read requests may be made.
*
* If 'how' is 'ISC_SOCKSHUT_SEND' or 'ISC_SOCKSHUT_ALL' then
*
* The write queue must be empty.
*
* No further write requests may be made.
*/
void
isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp);
/*
* Attach *socketp to socket.
*
* Requires:
*
* 'socket' is a valid socket.
*
* 'socketp' points to a NULL socket.
*
* Ensures:
*
* *socketp is attached to socket.
*/
void
isc_socket_detach(isc_socket_t **socketp);
/*
* Detach *socketp from its socket.
*
* Requires:
*
* 'socketp' points to a valid socket.
*
* If '*socketp' is the last reference to the socket,
* then:
*
* There must be no pending I/O requests.
*
* Ensures:
*
* *socketp is NULL.
*
* If '*socketp' is the last reference to the socket,
* then:
*
* The socket will be shutdown (both reading and writing)
* for all tasks.
*
* All resources used by the socket have been freed
*/
isc_result_t
isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *addressp);
/*
* Bind 'socket' to '*addressp'.
*
* Requires:
*
* 'socket' is a valid socket
*
* 'addressp' points to a valid isc_sockaddr.
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOPERM
* ISC_R_ADDRNOTAVAIL
* ISC_R_ADDRINUSE
* ISC_R_BOUND
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_listen(isc_socket_t *sock, unsigned int backlog);
/*
* Set listen mode on the socket. After this call, the only function that
* can be used (other than attach and detach) is isc_socket_accept().
*
* Notes:
*
* 'backlog' is as in the UNIX system call listen() and may be
* ignored by non-UNIX implementations.
*
* If 'backlog' is zero, a reasonable system default is used, usually
* SOMAXCONN.
*
* Requires:
*
* 'socket' is a valid, bound TCP socket.
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_accept(isc_socket_t *sock,
isc_task_t *task, isc_taskaction_t action, const void *arg);
/*
* Queue accept event. When a new connection is received, the task will
* get an ISC_SOCKEVENT_NEWCONN event with the sender set to the listen
* socket. The new socket structure is sent inside the isc_socket_newconnev_t
* event type, and is attached to the task 'task'.
*
* REQUIRES:
* 'socket' is a valid TCP socket that isc_socket_listen() was called
* on.
*
* 'task' is a valid task
*
* 'action' is a valid action
*
* RETURNS:
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addressp,
isc_task_t *task, isc_taskaction_t action,
const void *arg);
/*
* Connect 'socket' to peer with address *saddr. When the connection
* succeeds, or when an error occurs, a CONNECT event with action 'action'
* and arg 'arg' will be posted to the event queue for 'task'.
*
* Requires:
*
* 'socket' is a valid TCP socket
*
* 'addressp' points to a valid isc_sockaddr
*
* 'task' is a valid task
*
* 'action' is a valid action
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*
* Posted event's result code:
*
* ISC_R_SUCCESS
* ISC_R_TIMEDOUT
* ISC_R_CONNREFUSED
* ISC_R_NETUNREACH
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp);
/*
* Get the name of the peer connected to 'socket'.
*
* Requires:
*
* 'socket' is a valid TCP socket.
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_TOOSMALL
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp);
/*
* Get the name of 'socket'.
*
* Requires:
*
* 'socket' is a valid socket.
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_TOOSMALL
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_recv(isc_socket_t *sock, isc_region_t *region,
unsigned int minimum,
isc_task_t *task, isc_taskaction_t action, const void *arg);
isc_result_t
isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
unsigned int minimum,
isc_task_t *task, isc_taskaction_t action, const void *arg);
/*
* Receive from 'socket', storing the results in region.
*
* Notes:
*
* Let 'length' refer to the length of 'region' or to the sum of all
* available regions in the list of buffers '*buflist'.
*
* If 'minimum' is non-zero and at least that many bytes are read,
* the completion event will be posted to the task 'task.' If minimum
* is zero, the exact number of bytes requested in the region must
* be read for an event to be posted. This only makes sense for TCP
* connections, and is always set to 1 byte for UDP.
*
* The read will complete when the desired number of bytes have been
* read, if end-of-input occurs, or if an error occurs. A read done
* event with the given 'action' and 'arg' will be posted to the
* event queue of 'task'.
*
* The caller may not modify 'region', the buffers which are passed
* into this function, or any data they refer to until the completion
* event is received.
*
* For isc_socket_recvv():
* On successful completion, '*buflist' will be empty, and the list of
* all buffers will be returned in the done event's 'bufferlist'
* member. On error return, '*buflist' will be unchanged.
*
* Requires:
*
* 'socket' is a valid, bound socket.
*
* For isc_socket_recv():
* 'region' is a valid region
*
* For isc_socket_recvv():
* 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
*
* 'task' is a valid task
*
* action != NULL and is a valid action
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*
* Event results:
*
* ISC_R_SUCCESS
* ISC_R_UNEXPECTED
* XXX needs other net-type errors
*/
isc_result_t
isc_socket_send(isc_socket_t *sock, isc_region_t *region,
isc_task_t *task, isc_taskaction_t action, const void *arg);
isc_result_t
isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
isc_task_t *task, isc_taskaction_t action, const void *arg,
isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
isc_result_t
isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *task, isc_taskaction_t action, const void *arg);
isc_result_t
isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
isc_task_t *task, isc_taskaction_t action, const void *arg,
isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
/*
* Send the contents of 'region' to the socket's peer.
*
* Notes:
*
* Shutting down the requestor's task *may* result in any
* still pending writes being dropped or completed, depending on the
* underlying OS implementation.
*
* If 'action' is NULL, then no completion event will be posted.
*
* The caller may not modify 'region', the buffers which are passed
* into this function, or any data they refer to until the completion
* event is received.
*
* For isc_socket_sendv() and isc_socket_sendtov():
* On successful completion, '*buflist' will be empty, and the list of
* all buffers will be returned in the done event's 'bufferlist'
* member. On error return, '*buflist' will be unchanged.
*
* Requires:
*
* 'socket' is a valid, bound socket.
*
* For isc_socket_send():
* 'region' is a valid region
*
* For isc_socket_sendv() and isc_socket_sendtov():
* 'buflist' is non-NULL, and '*buflist' contain at least one buffer.
*
* 'task' is a valid task
*
* action == NULL or is a valid action
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*
* Event results:
*
* ISC_R_SUCCESS
* ISC_R_UNEXPECTED
* XXX needs other net-type errors
*/
isc_result_t
isc_socket_recvmark(isc_socket_t *sock, isc_task_t *task,
isc_taskaction_t action, const void *arg);
isc_result_t
isc_socket_sendmark(isc_socket_t *sock, isc_task_t *task,
isc_taskaction_t action, const void *arg);
/*
* Insert a recv/send marker for the socket.
*
* This marker is processed when all I/O requests in the proper queue
* have been processed.
*
* Requires:
*
* 'socket' is a valid, bound socket.
*
* 'task' is a valid task, 'action' is a valid action.
*
* Notes:
*
* If the queue is empty, the event will be posted immediately to the
* task.
*
* On return, the event's 'result' member will sometimes contain useful
* information. If the mark was processed after a fatal error, it will
* contain the same error that the last isc_socket_recv(), _send(),
* or sendto() returned, depending on the mark type.
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*/
isc_result_t
isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp);
/*
* Create a socket manager.
*
* Notes:
*
* All memory will be allocated in memory context 'mctx'.
*
* Requires:
*
* 'mctx' is a valid memory context.
*
* 'managerp' points to a NULL isc_socketmgr_t.
*
* Ensures:
*
* '*managerp' is a valid isc_socketmgr_t.
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*/
void
isc_socketmgr_destroy(isc_socketmgr_t **managerp);
/*
* Destroy a socket manager.
*
* Notes:
*
* This routine blocks until there are no sockets left in the manager,
* so if the caller holds any socket references using the manager, it
* must detach them before calling isc_socketmgr_destroy() or it will
* block forever.
*
* Requires:
*
* '*managerp' is a valid isc_socketmgr_t.
*
* All sockets managed by this manager are fully detached.
*
* Ensures:
*
* *managerp == NULL
*
* All resources used by the manager have been freed.
*/
isc_sockettype_t
isc_socket_gettype(isc_socket_t *sock);
/*
* Returns the socket type for "sock."
*
* Requires:
*
* "sock" is a valid socket.
*/
isc_boolean_t
isc_socket_isbound(isc_socket_t *sock);
ISC_LANG_ENDDECLS
#endif /* ISC_SOCKET_H */