2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2008
6 ** NOTE! The following LGPL license applies to the async_sock
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "system/network.h"
26 #include "system/filesys.h"
29 #include "lib/async_req/async_sock.h"
31 /* Note: lib/util/ is currently GPL */
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/util.h"
36 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
39 struct async_send_state
{
47 static void async_send_handler(struct tevent_context
*ev
,
48 struct tevent_fd
*fde
,
49 uint16_t flags
, void *private_data
);
51 struct tevent_req
*async_send_send(TALLOC_CTX
*mem_ctx
,
52 struct tevent_context
*ev
,
53 int fd
, const void *buf
, size_t len
,
56 struct tevent_req
*result
;
57 struct async_send_state
*state
;
58 struct tevent_fd
*fde
;
60 result
= tevent_req_create(mem_ctx
, &state
, struct async_send_state
);
69 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, async_send_handler
,
78 static void async_send_handler(struct tevent_context
*ev
,
79 struct tevent_fd
*fde
,
80 uint16_t flags
, void *private_data
)
82 struct tevent_req
*req
= talloc_get_type_abort(
83 private_data
, struct tevent_req
);
84 struct async_send_state
*state
=
85 tevent_req_data(req
, struct async_send_state
);
87 state
->sent
= send(state
->fd
, state
->buf
, state
->len
, state
->flags
);
88 if ((state
->sent
== -1) && (errno
== EINTR
)) {
92 if (state
->sent
== -1) {
93 tevent_req_error(req
, errno
);
99 ssize_t
async_send_recv(struct tevent_req
*req
, int *perrno
)
101 struct async_send_state
*state
=
102 tevent_req_data(req
, struct async_send_state
);
104 if (tevent_req_is_unix_error(req
, perrno
)) {
110 struct async_recv_state
{
118 static void async_recv_handler(struct tevent_context
*ev
,
119 struct tevent_fd
*fde
,
120 uint16_t flags
, void *private_data
);
122 struct tevent_req
*async_recv_send(TALLOC_CTX
*mem_ctx
,
123 struct tevent_context
*ev
,
124 int fd
, void *buf
, size_t len
, int flags
)
126 struct tevent_req
*result
;
127 struct async_recv_state
*state
;
128 struct tevent_fd
*fde
;
130 result
= tevent_req_create(mem_ctx
, &state
, struct async_recv_state
);
131 if (result
== NULL
) {
137 state
->flags
= flags
;
139 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, async_recv_handler
,
148 static void async_recv_handler(struct tevent_context
*ev
,
149 struct tevent_fd
*fde
,
150 uint16_t flags
, void *private_data
)
152 struct tevent_req
*req
= talloc_get_type_abort(
153 private_data
, struct tevent_req
);
154 struct async_recv_state
*state
=
155 tevent_req_data(req
, struct async_recv_state
);
157 state
->received
= recv(state
->fd
, state
->buf
, state
->len
,
159 if ((state
->received
== -1) && (errno
== EINTR
)) {
163 if (state
->received
== 0) {
164 tevent_req_error(req
, EPIPE
);
167 if (state
->received
== -1) {
168 tevent_req_error(req
, errno
);
171 tevent_req_done(req
);
174 ssize_t
async_recv_recv(struct tevent_req
*req
, int *perrno
)
176 struct async_recv_state
*state
=
177 tevent_req_data(req
, struct async_recv_state
);
179 if (tevent_req_is_unix_error(req
, perrno
)) {
182 return state
->received
;
185 struct async_connect_state
{
190 socklen_t address_len
;
191 struct sockaddr_storage address
;
194 static void async_connect_connected(struct tevent_context
*ev
,
195 struct tevent_fd
*fde
, uint16_t flags
,
199 * @brief async version of connect(2)
200 * @param[in] mem_ctx The memory context to hang the result off
201 * @param[in] ev The event context to work from
202 * @param[in] fd The socket to recv from
203 * @param[in] address Where to connect?
204 * @param[in] address_len Length of *address
205 * @retval The async request
207 * This function sets the socket into non-blocking state to be able to call
208 * connect in an async state. This will be reset when the request is finished.
211 struct tevent_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
212 struct tevent_context
*ev
,
213 int fd
, const struct sockaddr
*address
,
214 socklen_t address_len
)
216 struct tevent_req
*result
;
217 struct async_connect_state
*state
;
218 struct tevent_fd
*fde
;
220 result
= tevent_req_create(
221 mem_ctx
, &state
, struct async_connect_state
);
222 if (result
== NULL
) {
227 * We have to set the socket to nonblocking for async connect(2). Keep
228 * the old sockflags around.
232 state
->sys_errno
= 0;
234 state
->old_sockflags
= fcntl(fd
, F_GETFL
, 0);
235 if (state
->old_sockflags
== -1) {
239 state
->address_len
= address_len
;
240 if (address_len
> sizeof(state
->address
)) {
244 memcpy(&state
->address
, address
, address_len
);
246 set_blocking(fd
, false);
248 state
->result
= connect(fd
, address
, address_len
);
249 if (state
->result
== 0) {
250 tevent_req_done(result
);
255 * A number of error messages show that something good is progressing
256 * and that we have to wait for readability.
258 * If none of them are present, bail out.
261 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
265 errno
== EAGAIN
|| errno
== EINTR
)) {
266 state
->sys_errno
= errno
;
270 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
| TEVENT_FD_WRITE
,
271 async_connect_connected
, result
);
273 state
->sys_errno
= ENOMEM
;
279 tevent_req_error(result
, state
->sys_errno
);
281 fcntl(fd
, F_SETFL
, state
->old_sockflags
);
282 return tevent_req_post(result
, ev
);
286 * fde event handler for connect(2)
287 * @param[in] ev The event context that sent us here
288 * @param[in] fde The file descriptor event associated with the connect
289 * @param[in] flags Indicate read/writeability of the socket
290 * @param[in] priv private data, "struct async_req *" in this case
293 static void async_connect_connected(struct tevent_context
*ev
,
294 struct tevent_fd
*fde
, uint16_t flags
,
297 struct tevent_req
*req
= talloc_get_type_abort(
298 priv
, struct tevent_req
);
299 struct async_connect_state
*state
=
300 tevent_req_data(req
, struct async_connect_state
);
303 * Stevens, Network Programming says that if there's a
304 * successful connect, the socket is only writable. Upon an
305 * error, it's both readable and writable.
307 if ((flags
& (TEVENT_FD_READ
|TEVENT_FD_WRITE
))
308 == (TEVENT_FD_READ
|TEVENT_FD_WRITE
)) {
311 ret
= connect(state
->fd
,
312 (struct sockaddr
*)(void *)&state
->address
,
316 tevent_req_done(req
);
320 if (errno
== EINPROGRESS
) {
321 /* Try again later, leave the fde around */
325 tevent_req_error(req
, errno
);
329 state
->sys_errno
= 0;
330 tevent_req_done(req
);
333 int async_connect_recv(struct tevent_req
*req
, int *perrno
)
335 struct async_connect_state
*state
=
336 tevent_req_data(req
, struct async_connect_state
);
339 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
341 if (tevent_req_is_unix_error(req
, &err
)) {
346 if (state
->sys_errno
== 0) {
350 *perrno
= state
->sys_errno
;
354 struct writev_state
{
355 struct tevent_context
*ev
;
363 static void writev_trigger(struct tevent_req
*req
, void *private_data
);
364 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
365 uint16_t flags
, void *private_data
);
367 struct tevent_req
*writev_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
368 struct tevent_queue
*queue
, int fd
,
369 bool err_on_readability
,
370 struct iovec
*iov
, int count
)
372 struct tevent_req
*req
;
373 struct writev_state
*state
;
375 req
= tevent_req_create(mem_ctx
, &state
, struct writev_state
);
381 state
->total_size
= 0;
382 state
->count
= count
;
383 state
->iov
= (struct iovec
*)talloc_memdup(
384 state
, iov
, sizeof(struct iovec
) * count
);
385 if (state
->iov
== NULL
) {
388 state
->flags
= TEVENT_FD_WRITE
;
389 if (err_on_readability
) {
390 state
->flags
|= TEVENT_FD_READ
;
394 struct tevent_fd
*fde
;
395 fde
= tevent_add_fd(state
->ev
, state
, state
->fd
,
396 state
->flags
, writev_handler
, req
);
397 if (tevent_req_nomem(fde
, req
)) {
398 return tevent_req_post(req
, ev
);
403 if (!tevent_queue_add(queue
, ev
, req
, writev_trigger
, NULL
)) {
412 static void writev_trigger(struct tevent_req
*req
, void *private_data
)
414 struct writev_state
*state
= tevent_req_data(req
, struct writev_state
);
415 struct tevent_fd
*fde
;
417 fde
= tevent_add_fd(state
->ev
, state
, state
->fd
, state
->flags
,
418 writev_handler
, req
);
420 tevent_req_error(req
, ENOMEM
);
424 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
425 uint16_t flags
, void *private_data
)
427 struct tevent_req
*req
= talloc_get_type_abort(
428 private_data
, struct tevent_req
);
429 struct writev_state
*state
=
430 tevent_req_data(req
, struct writev_state
);
431 size_t to_write
, written
;
436 if ((state
->flags
& TEVENT_FD_READ
) && (flags
& TEVENT_FD_READ
)) {
437 tevent_req_error(req
, EPIPE
);
441 for (i
=0; i
<state
->count
; i
++) {
442 to_write
+= state
->iov
[i
].iov_len
;
445 written
= writev(state
->fd
, state
->iov
, state
->count
);
446 if ((written
== -1) && (errno
== EINTR
)) {
451 tevent_req_error(req
, errno
);
455 tevent_req_error(req
, EPIPE
);
458 state
->total_size
+= written
;
460 if (written
== to_write
) {
461 tevent_req_done(req
);
466 * We've written less than we were asked to, drop stuff from
470 while (written
> 0) {
471 if (written
< state
->iov
[0].iov_len
) {
472 state
->iov
[0].iov_base
=
473 (char *)state
->iov
[0].iov_base
+ written
;
474 state
->iov
[0].iov_len
-= written
;
477 written
-= state
->iov
[0].iov_len
;
483 ssize_t
writev_recv(struct tevent_req
*req
, int *perrno
)
485 struct writev_state
*state
=
486 tevent_req_data(req
, struct writev_state
);
488 if (tevent_req_is_unix_error(req
, perrno
)) {
491 return state
->total_size
;
494 struct read_packet_state
{
498 ssize_t (*more
)(uint8_t *buf
, size_t buflen
, void *private_data
);
502 static void read_packet_handler(struct tevent_context
*ev
,
503 struct tevent_fd
*fde
,
504 uint16_t flags
, void *private_data
);
506 struct tevent_req
*read_packet_send(TALLOC_CTX
*mem_ctx
,
507 struct tevent_context
*ev
,
508 int fd
, size_t initial
,
509 ssize_t (*more
)(uint8_t *buf
,
514 struct tevent_req
*result
;
515 struct read_packet_state
*state
;
516 struct tevent_fd
*fde
;
518 result
= tevent_req_create(mem_ctx
, &state
, struct read_packet_state
);
519 if (result
== NULL
) {
525 state
->private_data
= private_data
;
527 state
->buf
= talloc_array(state
, uint8_t, initial
);
528 if (state
->buf
== NULL
) {
532 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, read_packet_handler
,
543 static void read_packet_handler(struct tevent_context
*ev
,
544 struct tevent_fd
*fde
,
545 uint16_t flags
, void *private_data
)
547 struct tevent_req
*req
= talloc_get_type_abort(
548 private_data
, struct tevent_req
);
549 struct read_packet_state
*state
=
550 tevent_req_data(req
, struct read_packet_state
);
551 size_t total
= talloc_get_size(state
->buf
);
555 nread
= recv(state
->fd
, state
->buf
+state
->nread
, total
-state
->nread
,
557 if ((nread
== -1) && (errno
== EINTR
)) {
562 tevent_req_error(req
, errno
);
566 tevent_req_error(req
, EPIPE
);
570 state
->nread
+= nread
;
571 if (state
->nread
< total
) {
572 /* Come back later */
577 * We got what was initially requested. See if "more" asks for -- more.
579 if (state
->more
== NULL
) {
580 /* Nobody to ask, this is a async read_data */
581 tevent_req_done(req
);
585 more
= state
->more(state
->buf
, total
, state
->private_data
);
587 /* We got an invalid packet, tell the caller */
588 tevent_req_error(req
, EIO
);
592 /* We're done, full packet received */
593 tevent_req_done(req
);
597 tmp
= talloc_realloc(state
, state
->buf
, uint8_t, total
+more
);
598 if (tevent_req_nomem(tmp
, req
)) {
604 ssize_t
read_packet_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
605 uint8_t **pbuf
, int *perrno
)
607 struct read_packet_state
*state
=
608 tevent_req_data(req
, struct read_packet_state
);
610 if (tevent_req_is_unix_error(req
, perrno
)) {
613 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
614 return talloc_get_size(*pbuf
);