mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-05 09:05:40 +00:00
599 lines
14 KiB
C
599 lines
14 KiB
C
/*
|
|
* Copyright (C) 1998, 1999 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/boolean.h>
|
|
#include <isc/result.h>
|
|
#include <isc/event.h>
|
|
#include <isc/eventclass.h>
|
|
#include <isc/task.h>
|
|
#include <isc/region.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/sockaddr.h>
|
|
|
|
ISC_LANG_BEGINDECLS
|
|
|
|
/***
|
|
*** Types
|
|
***/
|
|
|
|
typedef struct isc_socket isc_socket_t;
|
|
typedef struct isc_socketmgr isc_socketmgr_t;
|
|
|
|
typedef struct isc_socketevent {
|
|
isc_event_t common; /* Sender is the socket. */
|
|
isc_result_t result; /* OK, EOF, whatever else */
|
|
unsigned int n; /* bytes read or written */
|
|
isc_region_t region; /* the region info */
|
|
isc_sockaddr_t address; /* source address */
|
|
unsigned int addrlength; /* length of address */
|
|
} isc_socketevent_t;
|
|
|
|
typedef struct isc_socket_newconnev {
|
|
isc_event_t common;
|
|
isc_socket_t * newsocket;
|
|
isc_result_t result; /* OK, EOF, whatever else */
|
|
isc_sockaddr_t address; /* source address */
|
|
unsigned int addrlength; /* length of address */
|
|
} isc_socket_newconnev_t;
|
|
|
|
typedef struct isc_socket_connev {
|
|
isc_event_t common;
|
|
isc_result_t result; /* OK, EOF, whatever else */
|
|
} isc_socket_connev_t;
|
|
|
|
#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_INTRECV (ISC_EVENTCLASS_SOCKET + 257)
|
|
#define ISC_SOCKEVENT_INTSEND (ISC_EVENTCLASS_SOCKET + 258)
|
|
#define ISC_SOCKEVENT_INTACCEPT (ISC_EVENTCLASS_SOCKET + 259)
|
|
#define ISC_SOCKEVENT_INTCONN (ISC_EVENTCLASS_SOCKET + 260)
|
|
|
|
typedef enum {
|
|
isc_socket_udp,
|
|
isc_socket_tcp
|
|
} 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,
|
|
isc_sockettype_t type,
|
|
isc_socket_t **socketp);
|
|
/*
|
|
* Create a new 'type' socket managed by 'manager'.
|
|
*
|
|
* 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.
|
|
*
|
|
* Notes:
|
|
*
|
|
* Detaching the last reference may cause any still-pending I/O to be
|
|
* cancelled.
|
|
*
|
|
* Requires:
|
|
*
|
|
* 'socketp' points to a valid socket.
|
|
*
|
|
* 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,
|
|
int length);
|
|
/*
|
|
* Bind 'socket' to '*addressp'.
|
|
*
|
|
* Requires:
|
|
*
|
|
* 'socket' is a valid socket
|
|
*
|
|
* 'addressp' points to a valid isc_sockaddr.
|
|
*
|
|
* 'length' is approprate for the isc_sockaddr type.
|
|
*
|
|
* 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 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, 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() has been
|
|
* 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,
|
|
int length, isc_task_t *task, isc_taskaction_t action,
|
|
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
|
|
*
|
|
* 'length' is approprate for the isc_sockaddr type
|
|
*
|
|
* '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,
|
|
int *lengthp);
|
|
/*
|
|
* Get the name of the peer connected to 'socket'.
|
|
*
|
|
* Requires:
|
|
*
|
|
* 'socket' is a valid TCP socket.
|
|
*
|
|
* 'addressp' points to '*lengthp' bytes.
|
|
*
|
|
* Returns:
|
|
*
|
|
* ISC_R_SUCCESS
|
|
* ISC_R_TOOSMALL
|
|
* ISC_R_UNEXPECTED
|
|
*/
|
|
|
|
isc_result_t
|
|
isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp,
|
|
int *lengthp);
|
|
/*
|
|
* Get the name of 'socket'.
|
|
*
|
|
* Requires:
|
|
*
|
|
* 'socket' is a valid socket.
|
|
*
|
|
* 'addressp' points to '*lengthp' bytes.
|
|
*
|
|
* Returns:
|
|
*
|
|
* ISC_R_SUCCESS
|
|
* ISC_R_TOOSMALL
|
|
* ISC_R_UNEXPECTED
|
|
*/
|
|
|
|
isc_result_t
|
|
isc_socket_recv(isc_socket_t *sock, isc_region_t *region,
|
|
isc_boolean_t partial,
|
|
isc_task_t *task, isc_taskaction_t action, void *arg);
|
|
/*
|
|
* Receive from 'socket', storing the results in region.
|
|
*
|
|
* Notes:
|
|
*
|
|
* Let 'length' refer to the length of 'region'.
|
|
*
|
|
* If 'partial' is true, then at most 'length' bytes will be read.
|
|
* Otherwise the read will not complete until exactly 'length' bytes
|
|
* have been read.
|
|
*
|
|
* 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'.
|
|
*
|
|
* Partial reads are always turned on for UDP.
|
|
*
|
|
* The caller may neither read from nor write to 'region' until it
|
|
* has received the read completion event.
|
|
*
|
|
* Requires:
|
|
*
|
|
* 'socket' is a valid socket
|
|
*
|
|
* 'region' is a valid region
|
|
*
|
|
* '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, void *arg);
|
|
isc_result_t
|
|
isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
|
|
isc_task_t *task, isc_taskaction_t action, void *arg,
|
|
isc_sockaddr_t *address, unsigned int addrlength);
|
|
/*
|
|
* 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.
|
|
*
|
|
* If 'action' is NULL, then no completion event will be posted.
|
|
*
|
|
* The caller may neither read from nor write to 'region' until it
|
|
* has received the write completion event, or all references to the
|
|
* socket have been detached.
|
|
*
|
|
* Requires:
|
|
*
|
|
* 'socket' is a valid socket
|
|
*
|
|
* 'region' is a valid region
|
|
*
|
|
* 'task' is a valid task
|
|
*
|
|
* action == NULL or is a valid action
|
|
*
|
|
* Returns:
|
|
*
|
|
* 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, void *arg);
|
|
isc_result_t
|
|
isc_socket_sendmark(isc_socket_t *sock,
|
|
isc_task_t *task, isc_taskaction_t action, 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:
|
|
*
|
|
* 'sock' to be a valid 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_LANG_ENDDECLS
|
|
|
|
#endif /* ISC_SOCKET_H */
|