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);