diff --git a/lib/tsocket/config.mk b/lib/tsocket/config.mk index 016663ffea9..18cb8260e0a 100644 --- a/lib/tsocket/config.mk +++ b/lib/tsocket/config.mk @@ -4,7 +4,8 @@ PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBREPLACE_NETWORK LIBTSOCKET_OBJ_FILES = $(addprefix ../lib/tsocket/, \ tsocket.o \ tsocket_helpers.o \ - tsocket_bsd.o) + tsocket_bsd.o \ + tsocket_recvfrom.o) PUBLIC_HEADERS += $(addprefix ../lib/tsocket/, \ tsocket.h\ diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h index 04eb989a076..8cabd4263f6 100644 --- a/lib/tsocket/tsocket.h +++ b/lib/tsocket/tsocket.h @@ -124,7 +124,6 @@ int _tsocket_address_create_socket(const struct tsocket_address *addr, * BSD sockets: inet, inet6 and unix */ - int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx, const char *fam, const char *addr, @@ -161,5 +160,17 @@ int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx, _tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock, \ __location__) +/* + * Async helpers + */ + +struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock, + TALLOC_CTX *mem_ctx); +ssize_t tsocket_recvfrom_recv(struct tevent_req *req, + int *perrno, + TALLOC_CTX *mem_ctx, + uint8_t **buf, + struct tsocket_address **src); + #endif /* _TSOCKET_H */ diff --git a/lib/tsocket/tsocket_recvfrom.c b/lib/tsocket/tsocket_recvfrom.c new file mode 100644 index 00000000000..467738cfc20 --- /dev/null +++ b/lib/tsocket/tsocket_recvfrom.c @@ -0,0 +1,164 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Stefan Metzmacher 2009 + + ** NOTE! The following LGPL license applies to the tevent + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +#include "replace.h" +#include "system/network.h" +#include "tsocket.h" +#include "tsocket_internal.h" + +struct tsocket_recvfrom_state { + /* this structs are owned by the caller */ + struct { + struct tsocket_context *sock; + } caller; + + uint8_t *buf; + size_t len; + struct tsocket_address *src; +}; + +static int tsocket_recvfrom_state_destructor(struct tsocket_recvfrom_state *state) +{ + if (state->caller.sock) { + tsocket_set_readable_handler(state->caller.sock, NULL, NULL); + } + ZERO_STRUCT(state->caller); + + return 0; +} + +static void tsocket_recvfrom_handler(struct tsocket_context *sock, + void *private_data); + +struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock, + TALLOC_CTX *mem_ctx) +{ + struct tevent_req *req; + struct tsocket_recvfrom_state *state; + int ret; + int err; + bool dummy; + + req = tevent_req_create(mem_ctx, &state, + struct tsocket_recvfrom_state); + if (!req) { + return NULL; + } + + state->caller.sock = sock; + state->buf = NULL; + state->len = 0; + state->src = NULL; + + talloc_set_destructor(state, tsocket_recvfrom_state_destructor); + + ret = tsocket_set_readable_handler(sock, + tsocket_recvfrom_handler, + req); + err = tsocket_error_from_errno(ret, errno, &dummy); + if (tevent_req_error(req, err)) { + goto post; + } + + return req; + + post: + return tevent_req_post(req, sock->event.ctx); +} + +static void tsocket_recvfrom_handler(struct tsocket_context *sock, + void *private_data) +{ + struct tevent_req *req = talloc_get_type(private_data, + struct tevent_req); + struct tsocket_recvfrom_state *state = tevent_req_data(req, + struct tsocket_recvfrom_state); + ssize_t ret; + int err; + bool retry; + + ret = tsocket_pending(state->caller.sock); + if (ret == 0) { + /* retry later */ + return; + } + err = tsocket_error_from_errno(ret, errno, &retry); + if (retry) { + /* retry later */ + return; + } + if (tevent_req_error(req, err)) { + return; + } + + state->buf = talloc_array(state, uint8_t, ret); + if (tevent_req_nomem(state->buf, req)) { + return; + } + state->len = ret; + + ret = tsocket_recvfrom(state->caller.sock, + state->buf, + state->len, + state, + &state->src); + err = tsocket_error_from_errno(ret, errno, &retry); + if (retry) { + /* retry later */ + return; + } + if (tevent_req_error(req, err)) { + return; + } + + if (ret != state->len) { + tevent_req_error(req, EIO); + return; + } + + tevent_req_done(req); +} + +ssize_t tsocket_recvfrom_recv(struct tevent_req *req, + int *perrno, + TALLOC_CTX *mem_ctx, + uint8_t **buf, + struct tsocket_address **src) +{ + struct tsocket_recvfrom_state *state = tevent_req_data(req, + struct tsocket_recvfrom_state); + ssize_t ret; + + ret = tsocket_simple_int_recv(req, perrno); + if (ret == 0) { + *buf = talloc_move(mem_ctx, &state->buf); + ret = state->len; + if (src) { + *src = talloc_move(mem_ctx, &state->src); + } + } + + tevent_req_received(req); + return ret; +} +