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_req.h"
24 #include "lib/async_req/async_sock.h"
25 #include "lib/util/tevent_unix.h"
29 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
33 * @brief Map async_req states to unix-style errnos
34 * @param[in] req The async req to get the state from
35 * @param[out] err Pointer to take the unix-style errno
37 * @return true if the async_req is in an error state, false otherwise
40 bool async_req_is_errno(struct async_req
*req
, int *err
)
42 enum async_req_state state
;
45 if (!async_req_is_error(req
, &state
, &error
)) {
50 case ASYNC_REQ_USER_ERROR
:
53 case ASYNC_REQ_TIMED_OUT
:
60 case ASYNC_REQ_NO_MEMORY
:
70 int async_req_simple_recv_errno(struct async_req
*req
)
74 if (async_req_is_errno(req
, &err
)) {
81 struct async_send_state
{
89 static void async_send_handler(struct tevent_context
*ev
,
90 struct tevent_fd
*fde
,
91 uint16_t flags
, void *private_data
);
93 struct tevent_req
*async_send_send(TALLOC_CTX
*mem_ctx
,
94 struct tevent_context
*ev
,
95 int fd
, const void *buf
, size_t len
,
98 struct tevent_req
*result
;
99 struct async_send_state
*state
;
100 struct tevent_fd
*fde
;
102 result
= tevent_req_create(mem_ctx
, &state
, struct async_send_state
);
103 if (result
== NULL
) {
109 state
->flags
= flags
;
111 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, async_send_handler
,
120 static void async_send_handler(struct tevent_context
*ev
,
121 struct tevent_fd
*fde
,
122 uint16_t flags
, void *private_data
)
124 struct tevent_req
*req
= talloc_get_type_abort(
125 private_data
, struct tevent_req
);
126 struct async_send_state
*state
=
127 tevent_req_data(req
, struct async_send_state
);
129 state
->sent
= send(state
->fd
, state
->buf
, state
->len
, state
->flags
);
130 if (state
->sent
== -1) {
131 tevent_req_error(req
, errno
);
134 tevent_req_done(req
);
137 ssize_t
async_send_recv(struct tevent_req
*req
, int *perrno
)
139 struct async_send_state
*state
=
140 tevent_req_data(req
, struct async_send_state
);
142 if (tevent_req_is_unix_error(req
, perrno
)) {
148 struct async_recv_state
{
156 static void async_recv_handler(struct tevent_context
*ev
,
157 struct tevent_fd
*fde
,
158 uint16_t flags
, void *private_data
);
160 struct tevent_req
*async_recv_send(TALLOC_CTX
*mem_ctx
,
161 struct tevent_context
*ev
,
162 int fd
, void *buf
, size_t len
, int flags
)
164 struct tevent_req
*result
;
165 struct async_recv_state
*state
;
166 struct tevent_fd
*fde
;
168 result
= tevent_req_create(mem_ctx
, &state
, struct async_recv_state
);
169 if (result
== NULL
) {
175 state
->flags
= flags
;
177 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, async_recv_handler
,
186 static void async_recv_handler(struct tevent_context
*ev
,
187 struct tevent_fd
*fde
,
188 uint16_t flags
, void *private_data
)
190 struct tevent_req
*req
= talloc_get_type_abort(
191 private_data
, struct tevent_req
);
192 struct async_recv_state
*state
=
193 tevent_req_data(req
, struct async_recv_state
);
195 state
->received
= recv(state
->fd
, state
->buf
, state
->len
,
197 if (state
->received
== -1) {
198 tevent_req_error(req
, errno
);
201 tevent_req_done(req
);
204 ssize_t
async_recv_recv(struct tevent_req
*req
, int *perrno
)
206 struct async_recv_state
*state
=
207 tevent_req_data(req
, struct async_recv_state
);
209 if (tevent_req_is_unix_error(req
, perrno
)) {
212 return state
->received
;
215 struct async_connect_state
{
222 static void async_connect_connected(struct tevent_context
*ev
,
223 struct tevent_fd
*fde
, uint16_t flags
,
227 * @brief async version of connect(2)
228 * @param[in] mem_ctx The memory context to hang the result off
229 * @param[in] ev The event context to work from
230 * @param[in] fd The socket to recv from
231 * @param[in] address Where to connect?
232 * @param[in] address_len Length of *address
233 * @retval The async request
235 * This function sets the socket into non-blocking state to be able to call
236 * connect in an async state. This will be reset when the request is finished.
239 struct tevent_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
240 struct tevent_context
*ev
,
241 int fd
, const struct sockaddr
*address
,
242 socklen_t address_len
)
244 struct tevent_req
*result
;
245 struct async_connect_state
*state
;
246 struct tevent_fd
*fde
;
248 result
= tevent_req_create(
249 mem_ctx
, &state
, struct async_connect_state
);
250 if (result
== NULL
) {
255 * We have to set the socket to nonblocking for async connect(2). Keep
256 * the old sockflags around.
260 state
->sys_errno
= 0;
262 state
->old_sockflags
= fcntl(fd
, F_GETFL
, 0);
263 if (state
->old_sockflags
== -1) {
267 set_blocking(fd
, false);
269 state
->result
= connect(fd
, address
, address_len
);
270 if (state
->result
== 0) {
271 tevent_req_done(result
);
276 * A number of error messages show that something good is progressing
277 * and that we have to wait for readability.
279 * If none of them are present, bail out.
282 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
286 errno
== EAGAIN
|| errno
== EINTR
)) {
287 state
->sys_errno
= errno
;
291 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
| TEVENT_FD_WRITE
,
292 async_connect_connected
, result
);
294 state
->sys_errno
= ENOMEM
;
300 tevent_req_error(result
, state
->sys_errno
);
302 fcntl(fd
, F_SETFL
, state
->old_sockflags
);
303 return tevent_req_post(result
, ev
);
307 * fde event handler for connect(2)
308 * @param[in] ev The event context that sent us here
309 * @param[in] fde The file descriptor event associated with the connect
310 * @param[in] flags Indicate read/writeability of the socket
311 * @param[in] priv private data, "struct async_req *" in this case
314 static void async_connect_connected(struct tevent_context
*ev
,
315 struct tevent_fd
*fde
, uint16_t flags
,
318 struct tevent_req
*req
= talloc_get_type_abort(
319 priv
, struct tevent_req
);
320 struct async_connect_state
*state
=
321 tevent_req_data(req
, struct async_connect_state
);
326 * Stevens, Network Programming says that if there's a
327 * successful connect, the socket is only writable. Upon an
328 * error, it's both readable and writable.
330 if ((flags
& (TEVENT_FD_READ
|TEVENT_FD_WRITE
))
331 == (TEVENT_FD_READ
|TEVENT_FD_WRITE
)) {
333 socklen_t err_len
= sizeof(sockerr
);
335 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
336 (void *)&sockerr
, &err_len
) == 0) {
340 state
->sys_errno
= errno
;
342 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
344 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
345 tevent_req_error(req
, state
->sys_errno
);
349 state
->sys_errno
= 0;
350 tevent_req_done(req
);
353 int async_connect_recv(struct tevent_req
*req
, int *perrno
)
355 struct async_connect_state
*state
=
356 tevent_req_data(req
, struct async_connect_state
);
359 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
361 if (tevent_req_is_unix_error(req
, &err
)) {
366 if (state
->sys_errno
== 0) {
370 *perrno
= state
->sys_errno
;
374 struct writev_state
{
375 struct tevent_context
*ev
;
382 static void writev_trigger(struct tevent_req
*req
, void *private_data
);
383 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
384 uint16_t flags
, void *private_data
);
386 struct tevent_req
*writev_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
387 struct tevent_queue
*queue
, int fd
,
388 struct iovec
*iov
, int count
)
390 struct tevent_req
*result
;
391 struct writev_state
*state
;
393 result
= tevent_req_create(mem_ctx
, &state
, struct writev_state
);
394 if (result
== NULL
) {
399 state
->total_size
= 0;
400 state
->count
= count
;
401 state
->iov
= (struct iovec
*)talloc_memdup(
402 state
, iov
, sizeof(struct iovec
) * count
);
403 if (state
->iov
== NULL
) {
407 if (!tevent_queue_add(queue
, ev
, result
, writev_trigger
, NULL
)) {
416 static void writev_trigger(struct tevent_req
*req
, void *private_data
)
418 struct writev_state
*state
= tevent_req_data(req
, struct writev_state
);
419 struct tevent_fd
*fde
;
421 fde
= tevent_add_fd(state
->ev
, state
, state
->fd
, TEVENT_FD_WRITE
,
422 writev_handler
, req
);
424 tevent_req_error(req
, ENOMEM
);
428 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
429 uint16_t flags
, void *private_data
)
431 struct tevent_req
*req
= talloc_get_type_abort(
432 private_data
, struct tevent_req
);
433 struct writev_state
*state
=
434 tevent_req_data(req
, struct writev_state
);
435 size_t to_write
, written
;
440 for (i
=0; i
<state
->count
; i
++) {
441 to_write
+= state
->iov
[i
].iov_len
;
444 written
= sys_writev(state
->fd
, state
->iov
, state
->count
);
446 tevent_req_error(req
, errno
);
450 tevent_req_error(req
, EPIPE
);
453 state
->total_size
+= written
;
455 if (written
== to_write
) {
456 tevent_req_done(req
);
461 * We've written less than we were asked to, drop stuff from
465 while (written
> 0) {
466 if (written
< state
->iov
[0].iov_len
) {
467 state
->iov
[0].iov_base
=
468 (char *)state
->iov
[0].iov_base
+ written
;
469 state
->iov
[0].iov_len
-= written
;
472 written
-= state
->iov
[0].iov_len
;
478 ssize_t
writev_recv(struct tevent_req
*req
, int *perrno
)
480 struct writev_state
*state
=
481 tevent_req_data(req
, struct writev_state
);
483 if (tevent_req_is_unix_error(req
, perrno
)) {
486 return state
->total_size
;
489 struct read_packet_state
{
493 ssize_t (*more
)(uint8_t *buf
, size_t buflen
, void *private_data
);
497 static void read_packet_handler(struct tevent_context
*ev
,
498 struct tevent_fd
*fde
,
499 uint16_t flags
, void *private_data
);
501 struct tevent_req
*read_packet_send(TALLOC_CTX
*mem_ctx
,
502 struct tevent_context
*ev
,
503 int fd
, size_t initial
,
504 ssize_t (*more
)(uint8_t *buf
,
509 struct tevent_req
*result
;
510 struct read_packet_state
*state
;
511 struct tevent_fd
*fde
;
513 result
= tevent_req_create(mem_ctx
, &state
, struct read_packet_state
);
514 if (result
== NULL
) {
520 state
->private_data
= private_data
;
522 state
->buf
= talloc_array(state
, uint8_t, initial
);
523 if (state
->buf
== NULL
) {
527 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, read_packet_handler
,
538 static void read_packet_handler(struct tevent_context
*ev
,
539 struct tevent_fd
*fde
,
540 uint16_t flags
, void *private_data
)
542 struct tevent_req
*req
= talloc_get_type_abort(
543 private_data
, struct tevent_req
);
544 struct read_packet_state
*state
=
545 tevent_req_data(req
, struct read_packet_state
);
546 size_t total
= talloc_get_size(state
->buf
);
550 nread
= recv(state
->fd
, state
->buf
+state
->nread
, total
-state
->nread
,
553 tevent_req_error(req
, errno
);
557 tevent_req_error(req
, EPIPE
);
561 state
->nread
+= nread
;
562 if (state
->nread
< total
) {
563 /* Come back later */
568 * We got what was initially requested. See if "more" asks for -- more.
570 if (state
->more
== NULL
) {
571 /* Nobody to ask, this is a async read_data */
572 tevent_req_done(req
);
576 more
= state
->more(state
->buf
, total
, state
->private_data
);
578 /* We got an invalid packet, tell the caller */
579 tevent_req_error(req
, EIO
);
583 /* We're done, full packet received */
584 tevent_req_done(req
);
588 tmp
= TALLOC_REALLOC_ARRAY(state
, state
->buf
, uint8_t, total
+more
);
589 if (tevent_req_nomem(tmp
, req
)) {
595 ssize_t
read_packet_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
596 uint8_t **pbuf
, int *perrno
)
598 struct read_packet_state
*state
=
599 tevent_req_data(req
, struct read_packet_state
);
601 if (tevent_req_is_unix_error(req
, perrno
)) {
604 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
605 return talloc_get_size(*pbuf
);