diff options
author | Stefan Metzmacher <metze@samba.org> | 2009-11-03 18:06:17 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2009-11-03 18:26:30 +0100 |
commit | 97a32035bec03b76b67cb7088a7be1b7b3b9ac48 (patch) | |
tree | 21c6a858b2c7791f190fa4446e311b9299cc7651 /lib | |
parent | eb39f6694055267302580bbf6afa988c82c55fed (diff) | |
download | samba-97a32035bec03b76b67cb7088a7be1b7b3b9ac48.tar.gz samba-97a32035bec03b76b67cb7088a7be1b7b3b9ac48.tar.bz2 samba-97a32035bec03b76b67cb7088a7be1b7b3b9ac48.zip |
tsocket: rewrite tsocket_guide.txt to reflect the current APIs
metze
Diffstat (limited to 'lib')
-rw-r--r-- | lib/tsocket/tsocket_guide.txt | 880 |
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. |