tsocket: rewrite tsocket_guide.txt to reflect the current APIs
[ira/wip.git] / lib / tsocket / tsocket_guide.txt
index a02fa373faf64000217895fcf9525778be287831..ed903c602727535b77aa3a3371c0bcf00b19cb3c 100644 (file)
@@ -2,32 +2,23 @@
 Basic design of the tsocket abstraction
 =======================================
 
 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
 ===============================
 
 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);
 
    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.