2 Basic design of the tsocket abstraction
3 =======================================
5 The tsocket abstraction is splitted into two
6 different kinds of communitation interfaces.
8 There's the "tstream_context" interface with abstracts
9 the communication through a bidirectional
10 byte stream between two endpoints.
12 And there's the "tdgram_context" interface
13 with abstracts datagram based communication between any
16 Both interfaces share the "tsocket_address" abstraction
17 for endpoint addresses.
19 The whole library is based on the talloc(3) and 'tevent' libraries
20 and provides "tevent_req" based "foo_send()"/"foo_recv()" functions pairs
21 for all abstracted methods that need to be async.
23 The tsocket_address abstraction
24 ===============================
26 The tsocket_address represents an socket endpoint genericly.
27 As it's like an abstract class it has no specific constructor.
28 The specific constructors are descripted later sections.
30 There's a function get the string representation of the
31 endpoint for debugging. Callers should not try to parse
32 the string! The should use additional methods of the specific
33 tsocket_address implemention to get more details.
35 char *tsocket_address_string(const struct tsocket_address *addr,
38 There's a function to create a copy of the tsocket_address.
39 This is useful when before doing modifications to a socket
40 via additional methods of the specific tsocket_address implementation.
42 struct tsocket_address *tsocket_address_copy(const struct tsocket_address *addr,
45 The tdgram_context abstraction
46 ==============================
48 The tdgram_context is like an abstract class for datagram
49 based sockets. The interface provides async 'tevent_req' based
50 functions on top functionality is similar to the
51 recvfrom(2)/sendto(2)/close(2) syscalls.
53 The tdgram_recvfrom_send() method can be called to ask for the
54 next available datagram on the abstracted tdgram_context.
55 It returns a 'tevent_req' handle, where the caller can register
56 a callback with tevent_req_set_callback(). The callback is triggered
57 when a datagram is available or an error happened.
59 The callback is then supposed to get the result by calling
60 tdgram_recvfrom_recv() on the 'tevent_req'. It returns -1
61 and sets '*perrno' to the actual 'errno' on failure.
62 Otherwise it returns the length of the datagram
63 (0 is never returned!). '*buf' will contain the buffer of the
64 datagram and '*src' the abstracted tsocket_address of the sender
65 of the received datagram.
67 The caller can only have one outstanding tdgram_recvfrom_send()
68 at a time otherwise the caller will get '*perrno = EBUSY'.
70 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
71 struct tevent_context *ev,
72 struct tdgram_context *dgram);
74 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
78 struct tsocket_address **src);
80 The tdgram_sendto_send() method can be called to send a
81 datagram (specified by a buf/len) to a destination endpoint
82 (specified by dst). It's not allowed for len to be 0.
83 It returns a 'tevent_req' handle, where the caller can register a
84 callback with tevent_req_set_callback(). The callback is triggered
85 when the specific implementation (thinks it)
86 has delivered the datagram to the "wire".
88 The callback is then supposed to get the result by calling
89 tdgram_sendto_recv() on the 'tevent_req'. It returns -1
90 and sets '*perrno' to the actual 'errno' on failure.
91 Otherwise it returns the length of the datagram
92 (0 is never returned!).
94 The caller can only have one outstanding tdgram_sendto_send()
95 at a time otherwise the caller will get '*perrno = EBUSY'.
97 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
98 struct tevent_context *ev,
99 struct tdgram_context *dgram,
100 const uint8_t *buf, size_t len,
101 const struct tsocket_address *dst);
103 ssize_t tdgram_sendto_recv(struct tevent_req *req,
106 The tdgram_disconnect_send() method should be used to normally
107 shutdown/close the abstracted socket.
109 The caller should make sure there're no outstanding tdgram_recvfrom_send()
110 and tdgram_sendto_send() calls otherwise the caller will get '*perrno = EBUSY'.
112 Note: you can always use talloc_free(tdgram) to cleanup the resources
113 of the tdgram_context on a fatal error.
115 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
116 struct tevent_context *ev,
117 struct tdgram_context *dgram);
119 int tdgram_disconnect_recv(struct tevent_req *req,
122 The tstream_context abstraction
123 ===============================
125 The tstream_context is like an abstract class for stream
126 based sockets. The interface provides async 'tevent_req' based
127 functions on top functionality is similar to the
128 readv(2)/writev(2)/close(2) syscalls.
130 The tstream_pending_bytes() function is able to report
131 how much bytes of the incoming stream have arrived
132 but not consumed yet. It returns -1 and sets 'errno' on failure.
133 Otherwise it returns the number of uncomsumed bytes
136 ssize_t tstream_pending_bytes(struct tstream_context *stream);
138 The tstream_readv_send() method can be called to read for a
139 specific amount of bytes from the stream into the buffers
140 of the given iovec vector. The caller has to preallocate the buffers
141 in the iovec vector. The caller might need to use
142 tstream_pending_bytes() if the protocol doesn't have a fixed pdu header
143 containing the pdu size. tstream_readv_send() returns a 'tevent_req' handle,
144 where the caller can register a callback with tevent_req_set_callback().
145 The callback is triggered when all iovec buffers are completely
146 filled with bytes from the socket or an error happened.
148 The callback is then supposed to get the result by calling
149 tstream_readv_recv() on the 'tevent_req'. It returns -1
150 and sets '*perrno' to the actual 'errno' on failure.
151 Otherwise it returns the length of the datagram
152 (0 is never returned!).
154 The caller can only have one outstanding tstream_readv_send()
155 at a time otherwise the caller will get *perrno = EBUSY.
157 struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
158 struct tevent_context *ev,
159 struct tstream_context *stream,
160 struct iovec *vector,
163 int tstream_readv_recv(struct tevent_req *req,
166 The tstream_writev_send() method can be called to write
167 buffers in the given iovec vector into the stream socket.
168 It's invalid to pass an empty vector.
169 tstream_writev_send() returns a 'tevent_req' handle,
170 where the caller can register a callback with tevent_req_set_callback().
171 The callback is triggered when the specific implementation (thinks it)
172 has delivered the all buffers to the "wire".
174 The callback is then supposed to get the result by calling
175 tstream_writev_recv() on the 'tevent_req'. It returns -1
176 and sets '*perrno' to the actual 'errno' on failure.
177 Otherwise it returns the total amount of bytes sent.
178 (0 is never returned!).
180 The caller can only have one outstanding tstream_writev_send()
181 at a time otherwise the caller will get '*perrno = EBUSY'.
183 struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
184 struct tevent_context *ev,
185 struct tstream_context *stream,
186 const struct iovec *vector,
189 int tstream_writev_recv(struct tevent_req *req,
192 The tstream_disconnect_send() method should be used to normally
193 shutdown/close the abstracted socket.
195 The caller should make sure there're no outstanding tstream_readv_send()
196 and tstream_writev_send() calls otherwise the caller will get '*perrno = EBUSY'.
198 Note: you can always use talloc_free(tstream) to cleanup the resources
199 of the tstream_context on a fatal error.
201 struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
202 struct tevent_context *ev,
203 struct tstream_context *stream);
205 int tstream_disconnect_recv(struct tevent_req *req,
208 PDU receive helper functions
209 ============================
211 In order to make the live easier for callers which want to implement
212 a function to receive a full PDU with a single async function pair,
213 there're some helper functions.
215 The caller can use the tstream_readv_pdu_send() function
216 to ask for the next available PDU on the abstracted tstream_context.
217 The caller needs to provide a "next_vector" function and a private
218 state for this function. The tstream_readv_pdu engine will ask
219 the next_vector function for the next iovec vetor to be filled.
220 There's a tstream_readv_send/recv pair for each vector returned
221 by the next_vector function. If the next_vector function detects
222 it received a full pdu, it returns an empty vector. The the callback
223 of the tevent_req (returned by tstream_readv_pdu_send()) is triggered.
224 Note: the buffer allocation is completely up to the next_vector function
225 and it's private state.
227 See the 'dcerpc_read_ncacn_packet_send/recv' functions in Samba as an
230 typedef int (*tstream_readv_pdu_next_vector_t)(struct tstream_context *stream,
233 struct iovec **vector,
236 struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
237 struct tevent_context *ev,
238 struct tstream_context *stream,
239 tstream_readv_pdu_next_vector_t next_vector_fn,
240 void *next_vector_private);
242 int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno);
244 Async 'tevent_queue' based helper functions
245 ===========================================
247 There're some cases where the caller wants doesn't care about the
248 order of doing IO on the abstracted sockets.
249 (Remember at the low level there's always only one IO in a specific
250 direction allowed, only one tdgram_sendto_send() at a time).
252 There're some helpers using 'tevent_queue' to make it easier
253 for callers. The functions just get a 'queue' argument
254 and serialize the operations.
256 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
257 struct tevent_context *ev,
258 struct tdgram_context *dgram,
259 struct tevent_queue *queue,
262 struct tsocket_address *dst);
264 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno);
266 struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
267 struct tevent_context *ev,
268 struct tstream_context *stream,
269 struct tevent_queue *queue,
270 tstream_readv_pdu_next_vector_t next_vector_fn,
271 void *next_vector_private);
273 int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno);
275 struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
276 struct tevent_context *ev,
277 struct tstream_context *stream,
278 struct tevent_queue *queue,
279 const struct iovec *vector,
282 int tstream_writev_queue_recv(struct tevent_req *req, int *perrno);
284 BSD sockets: ipv4, ipv6 and unix
285 ================================
287 The main tsocket library comes with implentations
288 for BSD style ipv4, ipv6 and unix sockets.
290 You can use the tsocket_address_inet_from_strings()
291 function to create a tsocket_address for ipv4 and ipv6
292 endpoint addresses. "family" can be "ipv4", "ipv6" or "ip".
293 With "ip" is autodetects "ipv4" or "ipv6" based on the
294 "addr_string" string. "addr_string" must be a valid
295 ip address string based on the selected family
296 (dns names are not allowed!). But it's valid to pass NULL,
297 which gets mapped to "0.0.0.0" or "::".
298 It return -1 and set errno on error. Otherwise it returns 0.
300 int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
302 const char *addr_string,
304 struct tsocket_address **addr);
306 To get the ip address string of an existing 'inet' tsocket_address
307 you can use the tsocket_address_inet_addr_string() function.
308 It will return NULL and set errno to EINVAL if the tsocket_address
309 doesn't represent an ipv4 or ipv6 endpoint address.
311 char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
312 TALLOC_CTX *mem_ctx);
314 To get the port number of an existing 'inet' tsocket_address
315 you can use the tsocket_address_inet_port() function.
316 It will return 0 and set errno to EINVAL if the tsocket_address
317 doesn't represent an ipv4 or ipv6 endpoint address.
319 uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
321 To set the port number of an existing 'inet' tsocket_address
322 you can use the tsocket_address_inet_set_port() function.
323 It will return -1 and set errno to EINVAL if the tsocket_address
324 doesn't represent an ipv4 or ipv6 endpoint address.
325 It returns 0 on success.
327 int tsocket_address_inet_set_port(struct tsocket_address *addr,
330 You can use the tsocket_address_unix_from_path()
331 function to create a tsocket_address for unix domain
332 endpoint addresses. "path" is the filesystem path
333 (NULL will map ""). If the path is longer than
334 the low level kernel supports the function will
335 return -1 and set errno to ENAMETOOLONG.
336 On success it returns 0.
338 int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
340 struct tsocket_address **addr);
342 To get the path of an 'unix' tsocket_address
343 you can use the tsocket_address_unix_path() function.
344 It will return NULL and set errno to EINVAL if the tsocket_address
345 doesn't represent an unix domain endpoint path.
347 char *tsocket_address_unix_path(const struct tsocket_address *addr,
348 TALLOC_CTX *mem_ctx);
350 You can use tdgram_inet_udp_socket() to create a tdgram_context
351 for ipv4 or ipv6 UDP communication. "local_address" has to be
352 an 'inet' tsocket_address and it has to represent the local
353 endpoint. "remote_address" can be NULL or an 'inet' tsocket_address
354 presenting a remote endpoint. It returns -1 ans sets errno on error
355 and it returns 0 on success.
357 int tdgram_inet_udp_socket(const struct tsocket_address *local_address,
358 const struct tsocket_address *remote_address,
360 struct tdgram_context **dgram);
362 You can use tdgram_unix_socket() to create a tdgram_context
363 for unix domain datagram communication. "local_address" has to be
364 an 'unix' tsocket_address and it has to represent the local
365 endpoint. "remote_address" can be NULL or an 'unix' tsocket_address
366 presenting a remote endpoint. It returns -1 ans sets errno on error
367 and it returns 0 on success.
369 int tdgram_unix_socket(const struct tsocket_address *local,
370 const struct tsocket_address *remote,
372 struct tdgram_context **dgram);
374 You can use tstream_inet_tcp_connect_send to async
375 connect to a remote ipv4 or ipv6 TCP endpoint and create a
376 tstream_context for the stream based communication. "local_address" has to be
377 an 'inet' tsocket_address and it has to represent the local
378 endpoint. "remote_address" has to be an 'inet' tsocket_address
379 presenting a remote endpoint. It returns a 'tevent_req' handle,
380 where the caller can register a callback with tevent_req_set_callback().
381 The callback is triggered when a socket is connected and ready for IO
382 or an error happened.
384 The callback is then supposed to get the result by calling
385 tstream_inet_tcp_connect_recv() on the 'tevent_req'. It returns -1
386 and sets '*perrno' to the actual 'errno' on failure.
387 It returns 0 on success and returns the new tstream_context
390 struct tevent_req *tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
391 struct tevent_context *ev,
392 const struct tsocket_address *local_address,
393 const struct tsocket_address *remote_address);
395 int tstream_inet_tcp_connect_recv(struct tevent_req *req,
398 struct tstream_context **stream);
400 You can use tstream_unix_connect_send to async
401 connect to a unix domain endpoint and create a
402 tstream_context for the stream based communication.
403 "local_address" has to be an 'unix' tsocket_address and
404 it has to represent the local endpoint. "remote_address"
405 has to be an 'inet' tsocket_address presenting a remote endpoint.
406 It returns a 'tevent_req' handle, where the caller can register
407 a callback with tevent_req_set_callback(). The callback is
408 triggered when a socket is connected and ready for IO
409 or an error happened.
411 The callback is then supposed to get the result by calling
412 tstream_unix_connect_recv() on the 'tevent_req'. It returns -1
413 and sets '*perrno' to the actual 'errno' on failure.
414 It returns 0 on success and returns the new tstream_context
417 struct tevent_req *tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
418 struct tevent_context *ev,
419 const struct tsocket_address *local,
420 const struct tsocket_address *remote);
422 int _tstream_unix_connect_recv(struct tevent_req *req,
425 struct tstream_context **stream);
427 You can use tstream_unix_socketpair to create two connected
428 'unix' tsocket_contexts for the stream based communication.
429 It returns -1 and sets errno on error and it returns 0 on
432 int tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
433 struct tstream_context **stream1,
434 TALLOC_CTX *mem_ctx2,
435 struct tstream_context **stream2);
437 In some situations it's needed to create a tsocket_address from
438 a given 'struct sockaddr'. You can use tsocket_address_bsd_from_sockaddr()
439 for that. This should only be used if really needed, because of
440 already existing fixed APIs. Only AF_INET, AF_INET6 and AF_UNIX
441 sockets are allowed. The function returns -1 and set errno on error.
442 Otherwise it returns 0.
444 int tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
446 socklen_t sa_socklen,
447 struct tsocket_address **addr);
449 In some situations it's needed to get a 'struct sockaddr' from a
450 given tsocket_address . You can use tsocket_address_bsd_sockaddr()
451 for that. This should only be used if really needed. Only AF_INET,
452 AF_INET6 and AF_UNIX are supported. It returns the size of '*sa' on
453 success, otherwise it returns -1 and sets 'errno'.
455 ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
457 socklen_t sa_socklen);
459 In some situations it's needed to wrap existing file descriptors
460 into the tstream abstraction. You can use tstream_bsd_existing_socket()
461 for that. But you should read the tsocket_bsd.c code and unterstand it
462 in order use this function. E.g. the fd has to be non blocking already.
463 It will return -1 and set errno on error. Otherwise it returns 0
464 and sets '*stream' to point to the new tstream_context.
466 int tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
468 struct tstream_context **stream);
473 The abstracted layout of tdgram_context and tstream_context
474 allow implementations arround virtual sockets for encrypted tunnels
475 (like TLS, SASL or GSSAPI) or named pipes over smb.
477 Named Pipe Auth (NPA) Sockets
478 =============================
480 Samba has an implementation to abstract named pipes over smb
481 (within the server side). See libcli/named_pipe_auth/npa_tstream.[ch]
482 for the core code. The current callers are located in source4/ntvfs/ipc/vfs_ipc.c
483 and source4/rpc_server/service_rpc.c for the users.