summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2009-11-03 18:06:17 +0100
committerStefan Metzmacher <metze@samba.org>2009-11-03 18:26:30 +0100
commit97a32035bec03b76b67cb7088a7be1b7b3b9ac48 (patch)
tree21c6a858b2c7791f190fa4446e311b9299cc7651
parenteb39f6694055267302580bbf6afa988c82c55fed (diff)
downloadsamba-97a32035bec03b76b67cb7088a7be1b7b3b9ac48.tar.gz
samba-97a32035bec03b76b67cb7088a7be1b7b3b9ac48.tar.bz2
samba-97a32035bec03b76b67cb7088a7be1b7b3b9ac48.zip
tsocket: rewrite tsocket_guide.txt to reflect the current APIs
metze
-rw-r--r--lib/tsocket/tsocket_guide.txt880
1 files changed, 413 insertions, 467 deletions
diff --git a/lib/tsocket/tsocket_guide.txt b/lib/tsocket/tsocket_guide.txt
index a02fa373fa..ed903c6027 100644
--- a/lib/tsocket/tsocket_guide.txt
+++ b/lib/tsocket/tsocket_guide.txt
@@ -2,32 +2,23 @@
Basic design of the tsocket abstraction
=======================================
-The tsocket layer is designed to match more or less
-the bsd socket layer, but it hides the filedescriptor
-within a opaque 'tsocket_context' structure to make virtual
-sockets possible. The virtual sockets can be encrypted tunnels
-(like TLS, SASL or GSSAPI) or named pipes over smb.
-
-The tsocket layer is a bit like an abstract class, which defines
-common methods to work with sockets in a non blocking fashion.
+The tsocket abstraction is splitted into two
+different kinds of communitation interfaces.
-The whole library is based on the talloc(3) and 'tevent' libraries.
+There's the "tstream_context" interface with abstracts
+the communication through a bidirectional
+byte stream between two endpoints.
-The 'tsocket_address' structure is the 2nd abstracted class
-which represends the address of a socket endpoint.
+And there's the "tdgram_context" interface
+with abstracts datagram based communication between any
+number of endpoints.
-Each different type of socket has its own constructor.
+Both interfaces share the "tsocket_address" abstraction
+for endpoint addresses.
-Typically the constructor for a tsocket_context is attached to
-the tsocket_address of the source endpoint. That means
-the tsocket_address_create_socket() function takes the
-tsocket_address of the local endpoint and creates a tsocket_context
-for the communication.
-
-For some usecases it's possible to wrap an existing socket into a
-tsocket_context, e.g. to wrap an existing pipe(2) into
-tsocket_context, so that you can use the same functions to
-communicate over the pipe.
+The whole library is based on the talloc(3) and 'tevent' libraries
+and provides "tevent_req" based "foo_send()"/"foo_recv()" functions pairs
+for all abstracted methods that need to be async.
The tsocket_address abstraction
===============================
@@ -51,453 +42,408 @@ via additional methods of the specific tsocket_address implementation.
struct tsocket_address *tsocket_address_copy(const struct tsocket_address *addr,
TALLOC_CTX *mem_ctx);
-There's a function to create a tsocket_context based on the given local
-socket endpoint. The return value is 0 on success and -1 on failure
-with errno holding the specific error. Specific details are descripted in later
-sections. Note not all specific implementation have to implement all socket
-types.
-
- enum tsocket_type {
- TSOCKET_TYPE_STREAM = 1,
- TSOCKET_TYPE_DGRAM,
- TSOCKET_TYPE_MESSAGE
- };
-
- int tsocket_address_create_socket(const struct tsocket_address *addr,
- enum tsocket_type type,
- TALLOC_CTX *mem_ctx,
- struct tsocket_context **sock);
-
-The tsocket_context abstraction
+The tdgram_context abstraction
+==============================
+
+The tdgram_context is like an abstract class for datagram
+based sockets. The interface provides async 'tevent_req' based
+functions on top functionality is similar to the
+recvfrom(2)/sendto(2)/close(2) syscalls.
+
+The tdgram_recvfrom_send() method can be called to ask for the
+next available datagram on the abstracted tdgram_context.
+It returns a 'tevent_req' handle, where the caller can register
+a callback with tevent_req_set_callback(). The callback is triggered
+when a datagram is available or an error happened.
+
+The callback is then supposed to get the result by calling
+tdgram_recvfrom_recv() on the 'tevent_req'. It returns -1
+and sets *perrno to the actual 'errno' on failure.
+Otherwise it returns the length of the datagram
+(0 is never returned!). *buf will contain the buffer of the
+datagram and *src the abstracted tsocket_address of the sender
+of the received datagram.
+
+The caller can only have one outstanding tdgram_recvfrom_send()
+at a time otherwise the caller will get *perrno = EBUSY.
+
+struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+The tdgram_sendto_send() method can be called to send a
+datagram (specified by a buf/len) to a destination endpoint
+(specified by dst). It's not allowed for len to be 0.
+It returns a 'tevent_req' handle, where the caller can register a
+callback with tevent_req_set_callback(). The callback is triggered
+when the specific implementation (thinks it)
+has delivered the datagram to the "wire".
+
+The callback is then supposed to get the result by calling
+tdgram_sendto_recv() on the 'tevent_req'. It returns -1
+and sets *perrno to the actual 'errno' on failure.
+Otherwise it returns the length of the datagram
+(0 is never returned!).
+
+The caller can only have one outstanding tdgram_sendto_send()
+at a time otherwise the caller will get *perrno = EBUSY.
+
+struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst);
+ssize_t tdgram_sendto_recv(struct tevent_req *req,
+ int *perrno);
+
+The tdgram_disconnect_send() method should be used to normally
+shutdown/close the abstracted socket.
+
+The caller should make sure there're no outstanding tdgram_recvfrom_send()
+and tdgram_sendto_send() calls otherwise the caller will get *perrno = EBUSY.
+
+Note: you can always use talloc_free(tdgram) to cleanup the resources
+of the tdgram_context on a fatal error.
+
+struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+int tdgram_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+The tstream_context abstraction
===============================
-The tsocket_context is like an abstract class and represents
-a socket similar to bsd style sockets. The methods are more
-or less equal to the bsd socket api, while the filedescriptor
-is replaced by tsocket_context and sockaddr, socklen_t pairs
-are replaced by tsocket_address. The 'bind' operation happens
-in the specific constructor as the constructor is typically based
-on tsocket_address of local socket endpoint.
-
-All operations are by design non blocking and can return error
-values like EAGAIN, EINPROGRESS, EWOULDBLOCK or EINTR which
-indicate that the caller should retry the operation later.
-Also read the "The glue to tevent" section.
-
-The socket can of types:
- - TSOCKET_TYPE_STREAM is the equivalent to SOCK_STREAM in the bsd socket api.
- - TSOCKET_TYPE_DGRAM is the equivalent to SOCK_DGRAM in the bsd socket api.
- - TSOCKET_TYPE_MESSAGE operates on a connected socket and is therefore
- like TSOCKET_TYPE_STREAM, but the consumer needs to first read all
- data of a message, which was generated by one message 'write' on the sender,
- before the consumer gets data of the next message. This matches a bit
- like message mode pipes on windows. The concept is to transfer ordered
- messages between to endpoints.
-
-There's a function to connect to a remote endpoint. The behavior
-and error codes match the connect(2) function of the bsd socket api.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- int tsocket_connect(struct tsocket_context *sock,
- const struct tsocket_address *remote_addr);
-
-There's a function to listen for incoming connections. The behavior
-and error codes match the listen(2) function of the bsd socket api.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- int tsocket_listen(struct tsocket_context *sock,
- int queue_size);
-
-There's a function to accept incoming connections. The behavior
-and error codes match the accept(2) function of the bsd socket api.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- int tsocket_accept(struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- struct tsocket_context **new_sock);
-
-There's a function to ask how many bytes are in input buffer
-of the connection. For sockets of type TSOCKET_TYPE_DGRAM or
-TSOCKET_TYPE_MESSAGE the size of the next available dgram/message
-is returned. A return value of -1 indicates a socket error
-and errno will hold the specific error code. If no data
-is available 0 is returned, but retry error codes like
-EINTR can also be returned.
-
- ssize_t tsocket_pending(struct tsocket_context *sock);
-
-There's a function to read data from the socket. The behavior
-and error codes match the readv(3) function, also take a look
-at the recv(2) function of the bsd socket api.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- int tsocket_readv(struct tsocket_context *sock,
- const struct iovec *vector, size_t count);
-
-There's a function to write data from the socket. The behavior
-and error codes match the writev(3) function, also take a look
-at the send(2) function of the bsd socket api.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- int tsocket_writev(struct tsocket_context *sock,
- const struct iovec *vector, size_t count);
-
-There's a function to read a datagram from a remote endpoint.
-The behavior and error codes match the recvfrom(2) function of
-the bsd socket api. As TSOCKET_TYPE_DGRAM sockets can also be
-used in connected mode src_addr can be NULL, if the caller don't
-want to get the source address. Maybe the specific tsocket_context
-implementation speficied some further details.
-
- ssize_t tsocket_recvfrom(struct tsocket_context *sock,
- uint8_t *data, size_t len,
- TALLOC_CTX *addr_ctx,
- struct tsocket_address **src_addr);
-
-There's a function to send a datagram to a remote endpoint the socket.
-The behavior and error codes match the recvfrom(2) function of the
-bsd socket api. As TSOCKET_TYPE_DGRAM sockets can also be used in
-connected mode dest_addr must be NULL in connected mode and a valid
-tsocket_address otherwise. Maybe the specific tsocket_context
-implementation speficied some further details.
-
- ssize_t tsocket_sendto(struct tsocket_context *sock,
- const uint8_t *data, size_t len,
- const struct tsocket_address *dest_addr);
-
-There's a function to get the current status of the socket.
-The behavior and error codes match the getsockopt(2) function
-of the bsd socket api, with SOL_SOCKET and SO_ERROR as arguments.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- int tsocket_get_status(const struct tsocket_context *sock);
-
-There's a function to get tsocket_address of the local endpoint.
-The behavior and error codes match the getsockname(2) function
-of the bsd socket api. Maybe the specific tsocket_context
-implementation speficied some further details.
-
- int tsocket_get_local_address(const struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- struct tsocket_address **local_addr);
-
-There's a function to get tsocket_address of the remote endpoint
-of a connected socket. The behavior and error codes match the
-getpeername(2) function of the bsd socket api. Maybe the specific
-tsocket_context implementation speficied some further details.
-
- int tsocket_get_remote_address(const struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- struct tsocket_address **remote_addr,
- const char *location);
-
-There's a function to ask for specific options of the socket.
-The behavior and error codes match the getsockopt(2) function
-of the bsd socket api. The option and value are represented as string
-values, where the 'value' parameter can be NULL is the caller don't want to
-get the value. The supported options and values are up to the specific
-tsocket_context implementation.
-
- int tsocket_get_option(const struct tsocket_context *sock,
- const char *option,
- TALLOC_CTX *mem_ctx,
- char **value);
-
-There's a function to set specific options of the socket.
-The behavior and error codes match the setsockopt(2) function
-of the bsd socket api. The option and value are represented as string
-values, where the 'value' parameter can be NULL. The supported options
-and values are up to the specific tsocket_context implementation.
-The 'force' parameter specifies whether an error should be returned
-for unsupported options.
-
- int tsocket_set_option(const struct tsocket_context *sock,
- const char *option,
- bool force,
- const char *value);
-
-There's a function to disconnect the socket. The behavior
-and error codes match the close(2) function of the bsd socket api.
-Maybe the specific tsocket_context implementation speficied some
-further details.
-
- void tsocket_disconnect(struct tsocket_context *sock);
-
-The glue to tevent
-==================
-
-As the tsocket library is based on the tevent library,
-there need to be functions to let the caller register
-callback functions, which are triggered when the socket
-is writeable or readable. Typically one would use
-tevent fd events, but in order to hide the filedescriptor
-the tsocket_context abstraction has their own functions.
-
-There's a function to set the currently active tevent_context
-for the socket. It's important there's only one tevent_context
-actively used with the socket. A second call will cancel
-all low level events made on the old tevent_context, it will
-also resets the send and recv handlers to NULL. If the caller
-sets attaches a new event context to the socket, the callback
-function also need to be registered again. It's important
-that the caller keeps the given tevent_context in memory
-and actively calls tsocket_set_event_context(sock, NULL)
-before calling talloc_free(event_context).
-The function returns 0 on success and -1 together with an errno
-on failure.
-
- int tsocket_set_event_context(struct tsocket_context *sock,
- struct tevent_context *ev);
-
-There's a function to register a callback function which is called
-when the socket is readable. If the caller don't want to get notified
-anymore the function should be called with NULL as handler.
-The function returns 0 on success and -1 together with an errno
-on failure.
-
- typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
- int tsocket_set_readable_handler(struct tsocket_context *sock,
- tsocket_event_handler_t handler,
- void *private_data);
-
-There's a function to register a callback function which is called
-when the socket is writeable. If the caller don't want to get notified
-anymore the function should be called with NULL as handler.
-The function returns 0 on success and -1 together with an errno
-on failure.
-
- typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
- int tsocket_set_writeable_handler(struct tsocket_context *sock,
- tsocket_event_handler_t handler,
- void *private_data);
-
-Note: if the socket is readable and writeable, only the writeable
- handler is called, this avoids deadlocks at the application level.
-
-Async helper functions
-======================
-
-To make the life easier for the callers, there're 'tevent_req' based
-helper functions for non-blocking io-operations. For each of this functions
-to work the caller must attach the tevent_context to the tsocket_context
-with tsocket_set_event_context(). Please remember that attching a new
-tevent_context will reset the event state of the socket and should only
-be done, when there's no async request is pending on the socket!
-
-The detailed calling conventions for 'tevent_req' based programming
-will be explained in the 'tevent' documentation.
-
-To receive the next availabe datagram from socket there's a wrapper
-for tsocket_recvfrom(). The caller virtually sends its desire to receive
-the next available datagram by calling the tsocket_recvfrom_send() function
-and attaches a callback function to the returned tevent_req via tevent_req_set_callback().
-The callback function is called when a datagram is available or an error has happened.
-The callback function needs to get the result by calling
-tsocket_recvfrom_recv(). The return value of tsocket_recvfrom_recv()
-matches the return value from tsocket_recvfrom(). A possible errno is delivered
-via the perrno parameter instead of the global errno variable. The datagram
-buffer and optional the source tsocket_address of the datagram are returned as talloc
-childs of the mem_ctx passed to tsocket_recvfrom_recv().
-It's important that the caller garanties that there's only one async
-read request on the socket at a time.
-
- struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx);
- ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
- int *perrno,
- TALLOC_CTX *mem_ctx,
- uint8_t **buf,
- struct tsocket_address **src);
-
-To send a datagram there's a wrapper for tsocket_sendto().
-The caller calls tsocket_sendto_send() instead of tsocket_sendto()
-which returns a tevent_req allocated on the given TALLOC_CTX.
-The caller attaches a callback function to the returned tevent_req via
-tevent_req_set_callback(). The callback function is called when a datagram was
-deliviered into the socket or an error has happened.
-The callback function needs to get the result by calling
-tsocket_sendto_recv(). The return value of tsocket_sendto_recv()
-matches the return value from tsocket_sendto(). A possible errno is delivered
-via the perrno parameter instead of the global errno variable.
-Normal callers should not use this function directly, they should use
-tsocket_sendto_queue_send/recv() instead.
-
- struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- const uint8_t *buf,
- size_t len,
- const struct tsocket_address *dst);
- ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno);
-
-As only one async tsocket_sendto() call should happen at a time,
-there's a 'tevent_queue' is used to serialize the sendto requests.
-
- struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
- struct tsocket_context *sock,
- struct tevent_queue *queue,
- const uint8_t *buf,
- size_t len,
- struct tsocket_address *dst);
- ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno);
-
-Ther's an async helper for tsocket_connect(), which should be used
-to connect TSOCKET_TYPE_STREAM based sockets.
-The caller virtually sends its desire to connect to the destination
-tsocket_address by calling tsocket_connect_send() and gets back a tevent_req.
-The caller sets a callback function via tevent_req_set_callback().
-The callback function is called if the tsocket is connected or an error has happened.
-The callback function needs to get the result by calling
-tsocket_connect_recv(). The return value of tsocket_connect_recv()
-matches the return value from tsocket_connect()/tsocket_get_status().
-A possible errno is delivered via the perrno parameter instead of the global
-errno variable.
-
- struct tevent_req *tsocket_connect_send(struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- const struct tsocket_address *dst);
- int tsocket_connect_recv(struct tevent_req *req, int *perrno);
-
-To send an 'iovec' there's a wrapper for tsocket_writev().
-The caller calls tsocket_writev_send() instead of tsocket_writev()
-which returns a tevent_req allocated on the given TALLOC_CTX.
-The caller attaches a callback function to the returned tevent_req via
-tevent_req_set_callback(). The callback function is called when the whole iovec
-was deliviered into the socket or an error has happened.
-The callback function needs to get the result by calling
-tsocket_writev_recv(). The return value of tsocket_writev_recv()
-matches the return value from tsocket_writev(). A possible errno is delivered
-via the perrno parameter instead of the global errno variable.
-Normal callers should not use this function directly, they should use
-tsocket_writev_queue_send/recv() instead.
-
- struct tevent_req *tsocket_writev_send(struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- const struct iovec *vector,
- size_t count);
- int tsocket_writev_recv(struct tevent_req *req, int *perrno);
-
-As only one async tsocket_writev() call should happen at a time,
-there's a 'tevent_queue' is used to serialize the writev requests.
-
- struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx,
- struct tsocket_context *sock,
- struct tevent_queue *queue,
- const struct iovec *vector,
- size_t count);
- int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno);
-
-For TSOCKET_TYPE_STREAM sockets, it's typically desired to split the stream
-into PDUs. That's why the helper function for tsocket_readv() is a bit
-different compared to the other helper functions. The general rule
-is still to get a tevent_req, set a callback which gets called when the
-operation is done. The callback function needs to get the result by
-calling tsocket_readv_recv(). The 'next_iovec' callback function
-makes the difference to the other helper function.
-The tsocket_writev_send/recv() logic asks the caller via the
-next_iovec_fn for an iovec array, which will be filled completely
-with bytes from the socket, then the next_iovec_fn is called for
-the next iovec array to fill, untill the next_iovec_fn returns an empty
-iovec array. That next_iovec_fn should allocate the array as child of the
-passed mem_ctx, while the buffers the array referr to belong to the caller.
-The tsocket_writev_send/recv() engine will modify and free the given array!
-The basic idea is that the caller allocates and maintains the real buffers.
-The next_iovec_fn should report error by returning -1 and setting errno to
-the specific error code. The engine will pass the error to the caller
-via tsocket_readv_recv().
-
-typedef int (*tsocket_readv_next_iovec_t)(struct tsocket_context *sock,
- void *private_data,
- TALLOC_CTX *mem_ctx,
- struct iovec **vector,
- size_t *count);
-struct tevent_req *tsocket_readv_send(struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- tsocket_readv_next_iovec_t next_iovec_fn,
- void *private_data);
-int tsocket_readv_recv(struct tevent_req *req, int *perrno);
-
-Wrapper for BSD style sockets
+The tstream_context is like an abstract class for stream
+based sockets. The interface provides async 'tevent_req' based
+functions on top functionality is similar to the
+readv(2)/writev(2)/close(2) syscalls.
+
+The tstream_pending_bytes() function is able to report
+how much bytes of the incoming stream have arrived
+but not consumed yet. It returns -1 and sets 'errno' on failure.
+Otherwise it returns the number of uncomsumed bytes
+(it can return 0!).
+
+ssize_t tstream_pending_bytes(struct tstream_context *stream);
+
+The tstream_readv_send() method can be called to read for a
+specific amount of bytes from the stream into the buffers
+of the given iovec vector. The caller has to preallocate the buffers
+in the iovec vector. The caller might need to use
+tstream_pending_bytes() if the protocol doesn't have a fixed pdu header
+containing the pdu size. tstream_readv_send() returns a 'tevent_req' handle,
+where the caller can register a callback with tevent_req_set_callback().
+The callback is triggered when all iovec buffers are completely
+filled with bytes from the socket or an error happened.
+
+The callback is then supposed to get the result by calling
+tstream_readv_recv() on the 'tevent_req'. It returns -1
+and sets *perrno to the actual 'errno' on failure.
+Otherwise it returns the length of the datagram
+(0 is never returned!).
+
+The caller can only have one outstanding tstream_readv_send()
+at a time otherwise the caller will get *perrno = EBUSY.
+
+struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count);
+int tstream_readv_recv(struct tevent_req *req,
+ int *perrno);
+
+The tstream_writev_send() method can be called to write
+buffers in the given iovec vector into the stream socket.
+It's invalid to pass an empty vector.
+tstream_writev_send() returns a 'tevent_req' handle,
+where the caller can register a callback with tevent_req_set_callback().
+The callback is triggered when the specific implementation (thinks it)
+has delivered the all buffers to the "wire".
+
+The callback is then supposed to get the result by calling
+tstream_writev_recv() on the 'tevent_req'. It returns -1
+and sets *perrno to the actual 'errno' on failure.
+Otherwise it returns the total amount of bytes sent.
+(0 is never returned!).
+
+The caller can only have one outstanding tstream_writev_send()
+at a time otherwise the caller will get *perrno = EBUSY.
+
+struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count);
+int tstream_writev_recv(struct tevent_req *req,
+ int *perrno);
+
+The tstream_disconnect_send() method should be used to normally
+shutdown/close the abstracted socket.
+
+The caller should make sure there're no outstanding tstream_readv_send()
+and tstream_writev_send() calls otherwise the caller will get *perrno = EBUSY.
+
+Note: you can always use talloc_free(tstream) to cleanup the resources
+of the tstream_context on a fatal error.
+
+struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+int tstream_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+PDU receive helper functions
+============================
+
+In order to make the live easier for callers which want to implement
+a function to receive a full PDU with a single async function pair,
+there're some helper functions.
+
+The caller can use the tstream_readv_pdu_send() function
+to ask for the next available PDU on the abstracted tstream_context.
+The caller needs to provide a "next_vector" function and a private
+state for this function. The tstream_readv_pdu engine will ask
+the next_vector function for the next iovec vetor to be filled.
+There's a tstream_readv_send/recv pair for each vector returned
+by the next_vector function. If the next_vector function detects
+it received a full pdu, it returns an empty vector. The the callback
+of the tevent_req (returned by tstream_readv_pdu_send()) is triggered.
+Note: the buffer allocation is completely up to the next_vector function
+and it's private state.
+
+See the 'dcerpc_read_ncacn_packet_send/recv' functions in Samba as an
+example.
+
+typedef int (*tstream_readv_pdu_next_vector_t)(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **vector,
+ size_t *count);
+struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private);
+int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno);
+
+Async 'tevent_queue' based helper functions
+===========================================
+
+There're some cases where the caller wants doesn't care about the
+order of doing IO on the abstracted sockets.
+(Remember at the low level there's always only one IO in a specific
+ direction allowed, only one tdgram_sendto_send() at a time).
+
+There're some helpers using 'tevent_queue' to make it easier
+for callers. The functions just get a 'queue' argument
+and serialize the operations.
+
+struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst);
+ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private);
+int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ const struct iovec *vector,
+ size_t count);
+int tstream_writev_queue_recv(struct tevent_req *req, int *perrno);
+
+BSD sockets: ipv4, ipv6 and unix
+================================
+
+The main tsocket library comes with implentations
+for BSD style ipv4, ipv6 and unix sockets.
+
+You can use the tsocket_address_inet_from_strings()
+function to create a tsocket_address for ipv4 and ipv6
+endpoint addresses. "family" can be "ipv4", "ipv6" or "ip".
+With "ip" is autodetects "ipv4" or "ipv6" based on the
+"addr_string" string. "addr_string" must be a valid
+ip address string based on the selected family
+(dns names are not allowed!). But it's valid to pass NULL,
+which gets mapped to "0.0.0.0" or "::".
+It return -1 and set errno on error. Otherwise it returns 0.
+
+int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *family,
+ const char *addr_string,
+ uint16_t port,
+ struct tsocket_address **addr);
+
+To get the ip address string of an existing 'inet' tsocket_address
+you can use the tsocket_address_inet_addr_string() function.
+It will return NULL and set errno to EINVAL if the tsocket_address
+doesn't represent an ipv4 or ipv6 endpoint address.
+
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+To get the port number of an existing 'inet' tsocket_address
+you can use the tsocket_address_inet_port() function.
+It will return 0 and set errno to EINVAL if the tsocket_address
+doesn't represent an ipv4 or ipv6 endpoint address.
+
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+
+To set the port number of an existing 'inet' tsocket_address
+you can use the tsocket_address_inet_set_port() function.
+It will return -1 and set errno to EINVAL if the tsocket_address
+doesn't represent an ipv4 or ipv6 endpoint address.
+It returns 0 on success.
+
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port);
+
+You can use the tsocket_address_unix_from_path()
+function to create a tsocket_address for unix domain
+endpoint addresses. "path" is the filesystem path
+(NULL will map ""). If the path is longer than
+the low level kernel supports the function will
+return -1 and set errno to ENAMETOOLONG.
+On success it returns 0.
+
+int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **addr);
+
+To get the path of an 'unix' tsocket_address
+you can use the tsocket_address_unix_path() function.
+It will return NULL and set errno to EINVAL if the tsocket_address
+doesn't represent an unix domain endpoint path.
+
+char *tsocket_address_unix_path(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+You can use tdgram_inet_udp_socket() to create a tdgram_context
+for ipv4 or ipv6 UDP communication. "local_address" has to be
+an 'inet' tsocket_address and it has to represent the local
+endpoint. "remote_address" can be NULL or an 'inet' tsocket_address
+presenting a remote endpoint. It returns -1 ans sets errno on error
+and it returns 0 on success.
+
+int tdgram_inet_udp_socket(const struct tsocket_address *local_address,
+ const struct tsocket_address *remote_address,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+
+You can use tdgram_unix_socket() to create a tdgram_context
+for unix domain datagram communication. "local_address" has to be
+an 'unix' tsocket_address and it has to represent the local
+endpoint. "remote_address" can be NULL or an 'unix' tsocket_address
+presenting a remote endpoint. It returns -1 ans sets errno on error
+and it returns 0 on success.
+
+int tdgram_unix_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+
+You can use tstream_inet_tcp_connect_send to async
+connect to a remote ipv4 or ipv6 TCP endpoint and create a
+tstream_context for the stream based communication. "local_address" has to be
+an 'inet' tsocket_address and it has to represent the local
+endpoint. "remote_address" has to be an 'inet' tsocket_address
+presenting a remote endpoint. It returns a 'tevent_req' handle,
+where the caller can register a callback with tevent_req_set_callback().
+The callback is triggered when a socket is connected and ready for IO
+or an error happened.
+
+The callback is then supposed to get the result by calling
+tstream_inet_tcp_connect_recv() on the 'tevent_req'. It returns -1
+and sets *perrno to the actual 'errno' on failure.
+It returns 0 on success and returns the new tstream_context
+in *stream.
+
+struct tevent_req *tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local_address,
+ const struct tsocket_address *remote_address);
+int tstream_inet_tcp_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream);
+
+You can use tstream_unix_connect_send to async
+connect to a unix domain endpoint and create a
+tstream_context for the stream based communication.
+"local_address" has to be an 'unix' tsocket_address and
+it has to represent the local endpoint. "remote_address"
+has to be an 'inet' tsocket_address presenting a remote endpoint.
+It returns a 'tevent_req' handle, where the caller can register
+a callback with tevent_req_set_callback(). The callback is
+triggered when a socket is connected and ready for IO
+or an error happened.
+
+The callback is then supposed to get the result by calling
+tstream_unix_connect_recv() on the 'tevent_req'. It returns -1
+and sets *perrno to the actual 'errno' on failure.
+It returns 0 on success and returns the new tstream_context
+in *stream.
+
+struct tevent_req *tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote);
+int _tstream_unix_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream);
+
+You can use tstream_unix_socketpair to create two connected
+'unix' tsocket_contexts for the stream based communication.
+It returns -1 and sets errno on error and it returns 0 on
+success.
+
+int tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
+ struct tstream_context **stream1,
+ TALLOC_CTX *mem_ctx2,
+ struct tstream_context **stream2);
+
+In some situations it's needed to wrap existing file descriptors
+into the tstream abstraction. You can use tstream_bsd_existing_socket()
+for that. But you should read the tsocket_bsd.c code and unterstand it
+in order use this function. E.g. the fd has to be non blocking already.
+It will return -1 and set errno on error. Otherwise it returns 0
+and sets *stream to point to the new tstream_context.
+
+int tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tstream_context **stream);
+
+Virtual Sockets
+===============
+
+The abstracted layout of tdgram_context and tstream_context
+allow implementations arround virtual sockets for encrypted tunnels
+(like TLS, SASL or GSSAPI) or named pipes over smb.
+
+Named Pipe Auth (NPA) Sockets
=============================
-Support for BSD style sockets of AF_INET, AF_INET6 and AF_UNIX
-are part of the main tsocket library.
-
-To wrap an existing fd into a tsocket_context the function
-tsocket_context_bsd_wrap_existing() can be used.
-The caller needs to make sure the fd is marked as non-blocking!
-Normaly the tsocket_disconnect() function would close the fd,
-but the caller can influence this behavior based on the close_on_disconnect
-parameter. The caller should also make sure that the socket is only
-accessed via the tsocket_context wrapper after the call to
-tsocket_context_bsd_wrap_existing().
-
- int tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
- int fd, bool close_on_disconnect,
- struct tsocket_context **_sock);
-
-To create a tsocket_address for an inet address you need to use
-the tsocket_address_inet_from_strings() function. It takes the family
-as parameter which can be "ipv4", "ipv6" or "ip", where "ip" autodetects
-"ipv4" or "ipv6", based on the given address string. Depending on the
-operating system, "ipv6" may not be supported. Note: NULL as address
-is mapped to "0.0.0.0" or "::" based on the given family.
-The address parameter only accepts valid ipv4 or ipv6 address strings
-and no names! The caller need to resolve names before using this function.
-
- int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
- const char *family,
- const char *address,
- uint16_t port,
- struct tsocket_address **addr);
-
-To get the address of the inet tsocket_address as string the
-tsocket_address_inet_addr_string() function should be used.
-The caller should not try to parse the tsocket_address_string() output!
-
- char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
- TALLOC_CTX *mem_ctx);
-
-To get the port number of the inet tsocket_address the
-tsocket_address_inet_port() function should be used.
-The caller should not try to parse the tsocket_address_string() output!
-
- uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
-
-To alter the port number of an inet tsocket_address the
-tsocket_address_inet_set_port() function can be used.
-This is usefull if the caller gets the address from
-tsocket_address_copy(), tsocket_context_remote_address() or
-tsocket_context_remote_address() instead of tsocket_address_inet_from_strings().
-
- int tsocket_address_inet_set_port(struct tsocket_address *addr,
- uint16_t port);
-
-If the caller wants to create a broadcast socket, with the SO_BROADCAST
-socket option, the broadcast option needs to be set with the
-tsocket_address_inet_set_broadcast() function before calling
-tsocket_address_create_socket().
-
- void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
- bool broadcast);
-
-To create a tsocket_address for AF_UNIX style sockets the
-tsocket_address_unix_from_path() should be used.
-NULL as path is handled like "".
-
- int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
- const char *path,
- struct tsocket_address **addr);
-
-To get the unix path of an existing unix tsocket_address
-the tsocket_address_unix_path() should be used.
-The caller should not try to parse the tsocket_address_string() output!
-
- char *tsocket_address_unix_path(const struct tsocket_address *addr,
- TALLOC_CTX *mem_ctx);
+Samba has an implementation to abstract named pipes over smb
+(within the server side). See libcli/named_pipe_auth/npa_tstream.[ch]
+for the core code. The current callers are located in source4/ntvfs/ipc/vfs_ipc.c
+and source4/rpc_server/service_rpc.c for the users.