2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "lib/talloc/talloc.h"
22 #include "lib/tevent/tevent.h"
23 #include "lib/async_req/async_sock.h"
24 #include "lib/util/tevent_unix.h"
28 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
31 struct async_send_state
{
39 static void async_send_handler(struct tevent_context
*ev
,
40 struct tevent_fd
*fde
,
41 uint16_t flags
, void *private_data
);
43 struct tevent_req
*async_send_send(TALLOC_CTX
*mem_ctx
,
44 struct tevent_context
*ev
,
45 int fd
, const void *buf
, size_t len
,
48 struct tevent_req
*result
;
49 struct async_send_state
*state
;
50 struct tevent_fd
*fde
;
52 result
= tevent_req_create(mem_ctx
, &state
, struct async_send_state
);
61 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, async_send_handler
,
70 static void async_send_handler(struct tevent_context
*ev
,
71 struct tevent_fd
*fde
,
72 uint16_t flags
, void *private_data
)
74 struct tevent_req
*req
= talloc_get_type_abort(
75 private_data
, struct tevent_req
);
76 struct async_send_state
*state
=
77 tevent_req_data(req
, struct async_send_state
);
79 state
->sent
= send(state
->fd
, state
->buf
, state
->len
, state
->flags
);
80 if (state
->sent
== -1) {
81 tevent_req_error(req
, errno
);
87 ssize_t
async_send_recv(struct tevent_req
*req
, int *perrno
)
89 struct async_send_state
*state
=
90 tevent_req_data(req
, struct async_send_state
);
92 if (tevent_req_is_unix_error(req
, perrno
)) {
98 struct async_recv_state
{
106 static void async_recv_handler(struct tevent_context
*ev
,
107 struct tevent_fd
*fde
,
108 uint16_t flags
, void *private_data
);
110 struct tevent_req
*async_recv_send(TALLOC_CTX
*mem_ctx
,
111 struct tevent_context
*ev
,
112 int fd
, void *buf
, size_t len
, int flags
)
114 struct tevent_req
*result
;
115 struct async_recv_state
*state
;
116 struct tevent_fd
*fde
;
118 result
= tevent_req_create(mem_ctx
, &state
, struct async_recv_state
);
119 if (result
== NULL
) {
125 state
->flags
= flags
;
127 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, async_recv_handler
,
136 static void async_recv_handler(struct tevent_context
*ev
,
137 struct tevent_fd
*fde
,
138 uint16_t flags
, void *private_data
)
140 struct tevent_req
*req
= talloc_get_type_abort(
141 private_data
, struct tevent_req
);
142 struct async_recv_state
*state
=
143 tevent_req_data(req
, struct async_recv_state
);
145 state
->received
= recv(state
->fd
, state
->buf
, state
->len
,
147 if (state
->received
== -1) {
148 tevent_req_error(req
, errno
);
151 tevent_req_done(req
);
154 ssize_t
async_recv_recv(struct tevent_req
*req
, int *perrno
)
156 struct async_recv_state
*state
=
157 tevent_req_data(req
, struct async_recv_state
);
159 if (tevent_req_is_unix_error(req
, perrno
)) {
162 return state
->received
;
165 struct async_connect_state
{
172 static void async_connect_connected(struct tevent_context
*ev
,
173 struct tevent_fd
*fde
, uint16_t flags
,
177 * @brief async version of connect(2)
178 * @param[in] mem_ctx The memory context to hang the result off
179 * @param[in] ev The event context to work from
180 * @param[in] fd The socket to recv from
181 * @param[in] address Where to connect?
182 * @param[in] address_len Length of *address
183 * @retval The async request
185 * This function sets the socket into non-blocking state to be able to call
186 * connect in an async state. This will be reset when the request is finished.
189 struct tevent_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
190 struct tevent_context
*ev
,
191 int fd
, const struct sockaddr
*address
,
192 socklen_t address_len
)
194 struct tevent_req
*result
;
195 struct async_connect_state
*state
;
196 struct tevent_fd
*fde
;
198 result
= tevent_req_create(
199 mem_ctx
, &state
, struct async_connect_state
);
200 if (result
== NULL
) {
205 * We have to set the socket to nonblocking for async connect(2). Keep
206 * the old sockflags around.
210 state
->sys_errno
= 0;
212 state
->old_sockflags
= fcntl(fd
, F_GETFL
, 0);
213 if (state
->old_sockflags
== -1) {
217 set_blocking(fd
, false);
219 state
->result
= connect(fd
, address
, address_len
);
220 if (state
->result
== 0) {
221 tevent_req_done(result
);
226 * A number of error messages show that something good is progressing
227 * and that we have to wait for readability.
229 * If none of them are present, bail out.
232 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
236 errno
== EAGAIN
|| errno
== EINTR
)) {
237 state
->sys_errno
= errno
;
241 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
| TEVENT_FD_WRITE
,
242 async_connect_connected
, result
);
244 state
->sys_errno
= ENOMEM
;
250 tevent_req_error(result
, state
->sys_errno
);
252 fcntl(fd
, F_SETFL
, state
->old_sockflags
);
253 return tevent_req_post(result
, ev
);
257 * fde event handler for connect(2)
258 * @param[in] ev The event context that sent us here
259 * @param[in] fde The file descriptor event associated with the connect
260 * @param[in] flags Indicate read/writeability of the socket
261 * @param[in] priv private data, "struct async_req *" in this case
264 static void async_connect_connected(struct tevent_context
*ev
,
265 struct tevent_fd
*fde
, uint16_t flags
,
268 struct tevent_req
*req
= talloc_get_type_abort(
269 priv
, struct tevent_req
);
270 struct async_connect_state
*state
=
271 tevent_req_data(req
, struct async_connect_state
);
276 * Stevens, Network Programming says that if there's a
277 * successful connect, the socket is only writable. Upon an
278 * error, it's both readable and writable.
280 if ((flags
& (TEVENT_FD_READ
|TEVENT_FD_WRITE
))
281 == (TEVENT_FD_READ
|TEVENT_FD_WRITE
)) {
283 socklen_t err_len
= sizeof(sockerr
);
285 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
286 (void *)&sockerr
, &err_len
) == 0) {
290 state
->sys_errno
= errno
;
292 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
294 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
295 tevent_req_error(req
, state
->sys_errno
);
299 state
->sys_errno
= 0;
300 tevent_req_done(req
);
303 int async_connect_recv(struct tevent_req
*req
, int *perrno
)
305 struct async_connect_state
*state
=
306 tevent_req_data(req
, struct async_connect_state
);
309 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
311 if (tevent_req_is_unix_error(req
, &err
)) {
316 if (state
->sys_errno
== 0) {
320 *perrno
= state
->sys_errno
;
324 struct writev_state
{
325 struct tevent_context
*ev
;
332 static void writev_trigger(struct tevent_req
*req
, void *private_data
);
333 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
334 uint16_t flags
, void *private_data
);
336 struct tevent_req
*writev_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
337 struct tevent_queue
*queue
, int fd
,
338 struct iovec
*iov
, int count
)
340 struct tevent_req
*result
;
341 struct writev_state
*state
;
343 result
= tevent_req_create(mem_ctx
, &state
, struct writev_state
);
344 if (result
== NULL
) {
349 state
->total_size
= 0;
350 state
->count
= count
;
351 state
->iov
= (struct iovec
*)talloc_memdup(
352 state
, iov
, sizeof(struct iovec
) * count
);
353 if (state
->iov
== NULL
) {
357 if (!tevent_queue_add(queue
, ev
, result
, writev_trigger
, NULL
)) {
366 static void writev_trigger(struct tevent_req
*req
, void *private_data
)
368 struct writev_state
*state
= tevent_req_data(req
, struct writev_state
);
369 struct tevent_fd
*fde
;
371 fde
= tevent_add_fd(state
->ev
, state
, state
->fd
, TEVENT_FD_WRITE
,
372 writev_handler
, req
);
374 tevent_req_error(req
, ENOMEM
);
378 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
379 uint16_t flags
, void *private_data
)
381 struct tevent_req
*req
= talloc_get_type_abort(
382 private_data
, struct tevent_req
);
383 struct writev_state
*state
=
384 tevent_req_data(req
, struct writev_state
);
385 size_t to_write
, written
;
390 for (i
=0; i
<state
->count
; i
++) {
391 to_write
+= state
->iov
[i
].iov_len
;
394 written
= sys_writev(state
->fd
, state
->iov
, state
->count
);
396 tevent_req_error(req
, errno
);
400 tevent_req_error(req
, EPIPE
);
403 state
->total_size
+= written
;
405 if (written
== to_write
) {
406 tevent_req_done(req
);
411 * We've written less than we were asked to, drop stuff from
415 while (written
> 0) {
416 if (written
< state
->iov
[0].iov_len
) {
417 state
->iov
[0].iov_base
=
418 (char *)state
->iov
[0].iov_base
+ written
;
419 state
->iov
[0].iov_len
-= written
;
422 written
-= state
->iov
[0].iov_len
;
428 ssize_t
writev_recv(struct tevent_req
*req
, int *perrno
)
430 struct writev_state
*state
=
431 tevent_req_data(req
, struct writev_state
);
433 if (tevent_req_is_unix_error(req
, perrno
)) {
436 return state
->total_size
;
439 struct read_packet_state
{
443 ssize_t (*more
)(uint8_t *buf
, size_t buflen
, void *private_data
);
447 static void read_packet_handler(struct tevent_context
*ev
,
448 struct tevent_fd
*fde
,
449 uint16_t flags
, void *private_data
);
451 struct tevent_req
*read_packet_send(TALLOC_CTX
*mem_ctx
,
452 struct tevent_context
*ev
,
453 int fd
, size_t initial
,
454 ssize_t (*more
)(uint8_t *buf
,
459 struct tevent_req
*result
;
460 struct read_packet_state
*state
;
461 struct tevent_fd
*fde
;
463 result
= tevent_req_create(mem_ctx
, &state
, struct read_packet_state
);
464 if (result
== NULL
) {
470 state
->private_data
= private_data
;
472 state
->buf
= talloc_array(state
, uint8_t, initial
);
473 if (state
->buf
== NULL
) {
477 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, read_packet_handler
,
488 static void read_packet_handler(struct tevent_context
*ev
,
489 struct tevent_fd
*fde
,
490 uint16_t flags
, void *private_data
)
492 struct tevent_req
*req
= talloc_get_type_abort(
493 private_data
, struct tevent_req
);
494 struct read_packet_state
*state
=
495 tevent_req_data(req
, struct read_packet_state
);
496 size_t total
= talloc_get_size(state
->buf
);
500 nread
= recv(state
->fd
, state
->buf
+state
->nread
, total
-state
->nread
,
503 tevent_req_error(req
, errno
);
507 tevent_req_error(req
, EPIPE
);
511 state
->nread
+= nread
;
512 if (state
->nread
< total
) {
513 /* Come back later */
518 * We got what was initially requested. See if "more" asks for -- more.
520 if (state
->more
== NULL
) {
521 /* Nobody to ask, this is a async read_data */
522 tevent_req_done(req
);
526 more
= state
->more(state
->buf
, total
, state
->private_data
);
528 /* We got an invalid packet, tell the caller */
529 tevent_req_error(req
, EIO
);
533 /* We're done, full packet received */
534 tevent_req_done(req
);
538 tmp
= TALLOC_REALLOC_ARRAY(state
, state
->buf
, uint8_t, total
+more
);
539 if (tevent_req_nomem(tmp
, req
)) {
545 ssize_t
read_packet_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
546 uint8_t **pbuf
, int *perrno
)
548 struct read_packet_state
*state
=
549 tevent_req_data(req
, struct read_packet_state
);
551 if (tevent_req_is_unix_error(req
, perrno
)) {
554 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
555 return talloc_get_size(*pbuf
);