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);
73 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
77 struct tsocket_address **src);
79 The tdgram_sendto_send() method can be called to send a
80 datagram (specified by a buf/len) to a destination endpoint
81 (specified by dst). It's not allowed for len to be 0.
82 It returns a 'tevent_req' handle, where the caller can register a
83 callback with tevent_req_set_callback(). The callback is triggered
84 when the specific implementation (thinks it)
85 has delivered the datagram to the "wire".
87 The callback is then supposed to get the result by calling
88 tdgram_sendto_recv() on the 'tevent_req'. It returns -1
89 and sets *perrno to the actual 'errno' on failure.
90 Otherwise it returns the length of the datagram
91 (0 is never returned!).
93 The caller can only have one outstanding tdgram_sendto_send()
94 at a time otherwise the caller will get *perrno = EBUSY.
96 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
97 struct tevent_context *ev,
98 struct tdgram_context *dgram,
99 const uint8_t *buf, size_t len,
100 const struct tsocket_address *dst);
101 ssize_t tdgram_sendto_recv(struct tevent_req *req,
104 The tdgram_disconnect_send() method should be used to normally
105 shutdown/close the abstracted socket.
107 The caller should make sure there're no outstanding tdgram_recvfrom_send()
108 and tdgram_sendto_send() calls otherwise the caller will get *perrno = EBUSY.
110 Note: you can always use talloc_free(tdgram) to cleanup the resources
111 of the tdgram_context on a fatal error.
113 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
114 struct tevent_context *ev,
115 struct tdgram_context *dgram);
116 int tdgram_disconnect_recv(struct tevent_req *req,
119 The tstream_context abstraction
120 ===============================
122 The tstream_context is like an abstract class for stream
123 based sockets. The interface provides async 'tevent_req' based
124 functions on top functionality is similar to the
125 readv(2)/writev(2)/close(2) syscalls.
127 The tstream_pending_bytes() function is able to report
128 how much bytes of the incoming stream have arrived
129 but not consumed yet. It returns -1 and sets 'errno' on failure.
130 Otherwise it returns the number of uncomsumed bytes
133 ssize_t tstream_pending_bytes(struct tstream_context *stream);
135 The tstream_readv_send() method can be called to read for a
136 specific amount of bytes from the stream into the buffers
137 of the given iovec vector. The caller has to preallocate the buffers
138 in the iovec vector. The caller might need to use
139 tstream_pending_bytes() if the protocol doesn't have a fixed pdu header
140 containing the pdu size. tstream_readv_send() returns a 'tevent_req' handle,
141 where the caller can register a callback with tevent_req_set_callback().
142 The callback is triggered when all iovec buffers are completely
143 filled with bytes from the socket or an error happened.
145 The callback is then supposed to get the result by calling
146 tstream_readv_recv() on the 'tevent_req'. It returns -1
147 and sets *perrno to the actual 'errno' on failure.
148 Otherwise it returns the length of the datagram
149 (0 is never returned!).
151 The caller can only have one outstanding tstream_readv_send()
152 at a time otherwise the caller will get *perrno = EBUSY.
154 struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
155 struct tevent_context *ev,
156 struct tstream_context *stream,
157 struct iovec *vector,
159 int tstream_readv_recv(struct tevent_req *req,
162 The tstream_writev_send() method can be called to write
163 buffers in the given iovec vector into the stream socket.
164 It's invalid to pass an empty vector.
165 tstream_writev_send() returns a 'tevent_req' handle,
166 where the caller can register a callback with tevent_req_set_callback().
167 The callback is triggered when the specific implementation (thinks it)
168 has delivered the all buffers to the "wire".
170 The callback is then supposed to get the result by calling
171 tstream_writev_recv() on the 'tevent_req'. It returns -1
172 and sets *perrno to the actual 'errno' on failure.
173 Otherwise it returns the total amount of bytes sent.
174 (0 is never returned!).
176 The caller can only have one outstanding tstream_writev_send()
177 at a time otherwise the caller will get *perrno = EBUSY.
179 struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
180 struct tevent_context *ev,
181 struct tstream_context *stream,
182 const struct iovec *vector,
184 int tstream_writev_recv(struct tevent_req *req,
187 The tstream_disconnect_send() method should be used to normally
188 shutdown/close the abstracted socket.
190 The caller should make sure there're no outstanding tstream_readv_send()
191 and tstream_writev_send() calls otherwise the caller will get *perrno = EBUSY.
193 Note: you can always use talloc_free(tstream) to cleanup the resources
194 of the tstream_context on a fatal error.
196 struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
197 struct tevent_context *ev,
198 struct tstream_context *stream);
199 int tstream_disconnect_recv(struct tevent_req *req,
202 PDU receive helper functions
203 ============================
205 In order to make the live easier for callers which want to implement
206 a function to receive a full PDU with a single async function pair,
207 there're some helper functions.
209 The caller can use the tstream_readv_pdu_send() function
210 to ask for the next available PDU on the abstracted tstream_context.
211 The caller needs to provide a "next_vector" function and a private
212 state for this function. The tstream_readv_pdu engine will ask
213 the next_vector function for the next iovec vetor to be filled.
214 There's a tstream_readv_send/recv pair for each vector returned
215 by the next_vector function. If the next_vector function detects
216 it received a full pdu, it returns an empty vector. The the callback
217 of the tevent_req (returned by tstream_readv_pdu_send()) is triggered.
218 Note: the buffer allocation is completely up to the next_vector function
219 and it's private state.
221 See the 'dcerpc_read_ncacn_packet_send/recv' functions in Samba as an
224 typedef int (*tstream_readv_pdu_next_vector_t)(struct tstream_context *stream,
227 struct iovec **vector,
229 struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
230 struct tevent_context *ev,
231 struct tstream_context *stream,
232 tstream_readv_pdu_next_vector_t next_vector_fn,
233 void *next_vector_private);
234 int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno);
236 Async 'tevent_queue' based helper functions
237 ===========================================
239 There're some cases where the caller wants doesn't care about the
240 order of doing IO on the abstracted sockets.
241 (Remember at the low level there's always only one IO in a specific
242 direction allowed, only one tdgram_sendto_send() at a time).
244 There're some helpers using 'tevent_queue' to make it easier
245 for callers. The functions just get a 'queue' argument
246 and serialize the operations.
248 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
249 struct tevent_context *ev,
250 struct tdgram_context *dgram,
251 struct tevent_queue *queue,
254 struct tsocket_address *dst);
255 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno);
257 struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
258 struct tevent_context *ev,
259 struct tstream_context *stream,
260 struct tevent_queue *queue,
261 tstream_readv_pdu_next_vector_t next_vector_fn,
262 void *next_vector_private);
263 int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno);
265 struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
266 struct tevent_context *ev,
267 struct tstream_context *stream,
268 struct tevent_queue *queue,
269 const struct iovec *vector,
271 int tstream_writev_queue_recv(struct tevent_req *req, int *perrno);
273 BSD sockets: ipv4, ipv6 and unix
274 ================================
276 The main tsocket library comes with implentations
277 for BSD style ipv4, ipv6 and unix sockets.
279 You can use the tsocket_address_inet_from_strings()
280 function to create a tsocket_address for ipv4 and ipv6
281 endpoint addresses. "family" can be "ipv4", "ipv6" or "ip".
282 With "ip" is autodetects "ipv4" or "ipv6" based on the
283 "addr_string" string. "addr_string" must be a valid
284 ip address string based on the selected family
285 (dns names are not allowed!). But it's valid to pass NULL,
286 which gets mapped to "0.0.0.0" or "::".
287 It return -1 and set errno on error. Otherwise it returns 0.
289 int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
291 const char *addr_string,
293 struct tsocket_address **addr);
295 To get the ip address string of an existing 'inet' tsocket_address
296 you can use the tsocket_address_inet_addr_string() function.
297 It will return NULL and set errno to EINVAL if the tsocket_address
298 doesn't represent an ipv4 or ipv6 endpoint address.
300 char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
301 TALLOC_CTX *mem_ctx);
303 To get the port number of an existing 'inet' tsocket_address
304 you can use the tsocket_address_inet_port() function.
305 It will return 0 and set errno to EINVAL if the tsocket_address
306 doesn't represent an ipv4 or ipv6 endpoint address.
308 uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
310 To set the port number of an existing 'inet' tsocket_address
311 you can use the tsocket_address_inet_set_port() function.
312 It will return -1 and set errno to EINVAL if the tsocket_address
313 doesn't represent an ipv4 or ipv6 endpoint address.
314 It returns 0 on success.
316 int tsocket_address_inet_set_port(struct tsocket_address *addr,
319 You can use the tsocket_address_unix_from_path()
320 function to create a tsocket_address for unix domain
321 endpoint addresses. "path" is the filesystem path
322 (NULL will map ""). If the path is longer than
323 the low level kernel supports the function will
324 return -1 and set errno to ENAMETOOLONG.
325 On success it returns 0.
327 int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
329 struct tsocket_address **addr);
331 To get the path of an 'unix' tsocket_address
332 you can use the tsocket_address_unix_path() function.
333 It will return NULL and set errno to EINVAL if the tsocket_address
334 doesn't represent an unix domain endpoint path.
336 char *tsocket_address_unix_path(const struct tsocket_address *addr,
337 TALLOC_CTX *mem_ctx);
339 You can use tdgram_inet_udp_socket() to create a tdgram_context
340 for ipv4 or ipv6 UDP communication. "local_address" has to be
341 an 'inet' tsocket_address and it has to represent the local
342 endpoint. "remote_address" can be NULL or an 'inet' tsocket_address
343 presenting a remote endpoint. It returns -1 ans sets errno on error
344 and it returns 0 on success.
346 int tdgram_inet_udp_socket(const struct tsocket_address *local_address,
347 const struct tsocket_address *remote_address,
349 struct tdgram_context **dgram);
351 You can use tdgram_unix_socket() to create a tdgram_context
352 for unix domain datagram communication. "local_address" has to be
353 an 'unix' tsocket_address and it has to represent the local
354 endpoint. "remote_address" can be NULL or an 'unix' tsocket_address
355 presenting a remote endpoint. It returns -1 ans sets errno on error
356 and it returns 0 on success.
358 int tdgram_unix_socket(const struct tsocket_address *local,
359 const struct tsocket_address *remote,
361 struct tdgram_context **dgram);
363 You can use tstream_inet_tcp_connect_send to async
364 connect to a remote ipv4 or ipv6 TCP endpoint and create a
365 tstream_context for the stream based communication. "local_address" has to be
366 an 'inet' tsocket_address and it has to represent the local
367 endpoint. "remote_address" has to be an 'inet' tsocket_address
368 presenting a remote endpoint. It returns a 'tevent_req' handle,
369 where the caller can register a callback with tevent_req_set_callback().
370 The callback is triggered when a socket is connected and ready for IO
371 or an error happened.
373 The callback is then supposed to get the result by calling
374 tstream_inet_tcp_connect_recv() on the 'tevent_req'. It returns -1
375 and sets *perrno to the actual 'errno' on failure.
376 It returns 0 on success and returns the new tstream_context
379 struct tevent_req *tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
380 struct tevent_context *ev,
381 const struct tsocket_address *local_address,
382 const struct tsocket_address *remote_address);
383 int tstream_inet_tcp_connect_recv(struct tevent_req *req,
386 struct tstream_context **stream);
388 You can use tstream_unix_connect_send to async
389 connect to a unix domain endpoint and create a
390 tstream_context for the stream based communication.
391 "local_address" has to be an 'unix' tsocket_address and
392 it has to represent the local endpoint. "remote_address"
393 has to be an 'inet' tsocket_address presenting a remote endpoint.
394 It returns a 'tevent_req' handle, where the caller can register
395 a callback with tevent_req_set_callback(). The callback is
396 triggered when a socket is connected and ready for IO
397 or an error happened.
399 The callback is then supposed to get the result by calling
400 tstream_unix_connect_recv() on the 'tevent_req'. It returns -1
401 and sets *perrno to the actual 'errno' on failure.
402 It returns 0 on success and returns the new tstream_context
405 struct tevent_req *tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
406 struct tevent_context *ev,
407 const struct tsocket_address *local,
408 const struct tsocket_address *remote);
409 int _tstream_unix_connect_recv(struct tevent_req *req,
412 struct tstream_context **stream);
414 You can use tstream_unix_socketpair to create two connected
415 'unix' tsocket_contexts for the stream based communication.
416 It returns -1 and sets errno on error and it returns 0 on
419 int tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
420 struct tstream_context **stream1,
421 TALLOC_CTX *mem_ctx2,
422 struct tstream_context **stream2);
424 In some situations it's needed to create a tsocket_address from
425 a given 'struct sockaddr'. You can use tsocket_address_bsd_from_sockaddr()
426 for that. This should only be used if really needed, because of
427 already existing fixed APIs. Only AF_INET, AF_INET6 and AF_UNIX
428 sockets are allowed. The function returns -1 and set errno on error.
429 Otherwise it returns 0.
431 int tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
433 socklen_t sa_socklen,
434 struct tsocket_address **addr);
436 In some situations it's needed to get a 'struct sockaddr' from a
437 given tsocket_address . You can use tsocket_address_bsd_sockaddr()
438 for that. This should only be used if really needed. Only AF_INET,
439 AF_INET6 and AF_UNIX are supported. It returns the size of '*sa' on
440 success, otherwise it returns -1 and sets 'errno'.
442 int tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
444 socklen_t *sa_socklen);
446 In some situations it's needed to wrap existing file descriptors
447 into the tstream abstraction. You can use tstream_bsd_existing_socket()
448 for that. But you should read the tsocket_bsd.c code and unterstand it
449 in order use this function. E.g. the fd has to be non blocking already.
450 It will return -1 and set errno on error. Otherwise it returns 0
451 and sets *stream to point to the new tstream_context.
453 int tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
455 struct tstream_context **stream);
460 The abstracted layout of tdgram_context and tstream_context
461 allow implementations arround virtual sockets for encrypted tunnels
462 (like TLS, SASL or GSSAPI) or named pipes over smb.
464 Named Pipe Auth (NPA) Sockets
465 =============================
467 Samba has an implementation to abstract named pipes over smb
468 (within the server side). See libcli/named_pipe_auth/npa_tstream.[ch]
469 for the core code. The current callers are located in source4/ntvfs/ipc/vfs_ipc.c
470 and source4/rpc_server/service_rpc.c for the users.