along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
-#include "lib/talloc/talloc.h"
-#include "lib/tevent/tevent.h"
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include <talloc.h>
+#include <tevent.h>
#include "lib/async_req/async_sock.h"
+
+/* Note: lib/util/ is currently GPL */
#include "lib/util/tevent_unix.h"
-#include <fcntl.h>
+#include "lib/util/samba_util.h"
#ifndef TALLOC_FREE
#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
#endif
-struct async_send_state {
+struct sendto_state {
int fd;
const void *buf;
size_t len;
int flags;
+ const struct sockaddr_storage *addr;
+ socklen_t addr_len;
ssize_t sent;
};
-static void async_send_handler(struct tevent_context *ev,
+static void sendto_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *private_data);
-struct tevent_req *async_send_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- int fd, const void *buf, size_t len,
- int flags)
+struct tevent_req *sendto_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ int fd, const void *buf, size_t len, int flags,
+ const struct sockaddr_storage *addr)
{
struct tevent_req *result;
- struct async_send_state *state;
+ struct sendto_state *state;
struct tevent_fd *fde;
- result = tevent_req_create(mem_ctx, &state, struct async_send_state);
+ result = tevent_req_create(mem_ctx, &state, struct sendto_state);
if (result == NULL) {
return result;
}
state->buf = buf;
state->len = len;
state->flags = flags;
+ state->addr = addr;
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ state->addr_len = sizeof(struct sockaddr_in);
+ break;
+#if defined(HAVE_IPV6)
+ case AF_INET6:
+ state->addr_len = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case AF_UNIX:
+ state->addr_len = sizeof(struct sockaddr_un);
+ break;
+ default:
+ state->addr_len = sizeof(struct sockaddr_storage);
+ break;
+ }
- fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, async_send_handler,
+ fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, sendto_handler,
result);
if (fde == NULL) {
TALLOC_FREE(result);
return result;
}
-static void async_send_handler(struct tevent_context *ev,
+static void sendto_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *private_data)
{
struct tevent_req *req = talloc_get_type_abort(
private_data, struct tevent_req);
- struct async_send_state *state =
- tevent_req_data(req, struct async_send_state);
+ struct sendto_state *state =
+ tevent_req_data(req, struct sendto_state);
- state->sent = send(state->fd, state->buf, state->len, state->flags);
+ state->sent = sendto(state->fd, state->buf, state->len, state->flags,
+ (const struct sockaddr *)state->addr,
+ state->addr_len);
if ((state->sent == -1) && (errno == EINTR)) {
/* retry */
return;
tevent_req_done(req);
}
-ssize_t async_send_recv(struct tevent_req *req, int *perrno)
+ssize_t sendto_recv(struct tevent_req *req, int *perrno)
{
- struct async_send_state *state =
- tevent_req_data(req, struct async_send_state);
+ struct sendto_state *state =
+ tevent_req_data(req, struct sendto_state);
if (tevent_req_is_unix_error(req, perrno)) {
return -1;
return state->sent;
}
-struct async_recv_state {
+struct recvfrom_state {
int fd;
void *buf;
size_t len;
int flags;
+ struct sockaddr_storage *addr;
+ socklen_t *addr_len;
ssize_t received;
};
-static void async_recv_handler(struct tevent_context *ev,
+static void recvfrom_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *private_data);
-struct tevent_req *async_recv_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- int fd, void *buf, size_t len, int flags)
+struct tevent_req *recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, void *buf, size_t len, int flags,
+ struct sockaddr_storage *addr,
+ socklen_t *addr_len)
{
struct tevent_req *result;
- struct async_recv_state *state;
+ struct recvfrom_state *state;
struct tevent_fd *fde;
- result = tevent_req_create(mem_ctx, &state, struct async_recv_state);
+ result = tevent_req_create(mem_ctx, &state, struct recvfrom_state);
if (result == NULL) {
return result;
}
state->buf = buf;
state->len = len;
state->flags = flags;
+ state->addr = addr;
+ state->addr_len = addr_len;
- fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, async_recv_handler,
+ fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, recvfrom_handler,
result);
if (fde == NULL) {
TALLOC_FREE(result);
return result;
}
-static void async_recv_handler(struct tevent_context *ev,
+static void recvfrom_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *private_data)
{
struct tevent_req *req = talloc_get_type_abort(
private_data, struct tevent_req);
- struct async_recv_state *state =
- tevent_req_data(req, struct async_recv_state);
+ struct recvfrom_state *state =
+ tevent_req_data(req, struct recvfrom_state);
- state->received = recv(state->fd, state->buf, state->len,
- state->flags);
+ state->received = recvfrom(state->fd, state->buf, state->len,
+ state->flags, (struct sockaddr *)state->addr,
+ state->addr_len);
if ((state->received == -1) && (errno == EINTR)) {
/* retry */
return;
}
+ if (state->received == 0) {
+ tevent_req_error(req, EPIPE);
+ return;
+ }
if (state->received == -1) {
tevent_req_error(req, errno);
return;
tevent_req_done(req);
}
-ssize_t async_recv_recv(struct tevent_req *req, int *perrno)
+ssize_t recvfrom_recv(struct tevent_req *req, int *perrno)
{
- struct async_recv_state *state =
- tevent_req_data(req, struct async_recv_state);
+ struct recvfrom_state *state =
+ tevent_req_data(req, struct recvfrom_state);
if (tevent_req_is_unix_error(req, perrno)) {
return -1;
priv, struct tevent_req);
struct async_connect_state *state =
tevent_req_data(req, struct async_connect_state);
+ int ret;
- /*
- * Stevens, Network Programming says that if there's a
- * successful connect, the socket is only writable. Upon an
- * error, it's both readable and writable.
- */
- if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
- == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
- int ret;
-
- ret = connect(state->fd,
- (struct sockaddr *)(void *)&state->address,
- state->address_len);
- if (ret == 0) {
- TALLOC_FREE(fde);
- tevent_req_done(req);
- return;
- }
-
- if (errno == EINPROGRESS) {
- /* Try again later, leave the fde around */
- return;
- }
+ ret = connect(state->fd, (struct sockaddr *)(void *)&state->address,
+ state->address_len);
+ if (ret == 0) {
+ state->sys_errno = 0;
TALLOC_FREE(fde);
- tevent_req_error(req, errno);
+ tevent_req_done(req);
return;
}
-
- state->sys_errno = 0;
- tevent_req_done(req);
+ if (errno == EINPROGRESS) {
+ /* Try again later, leave the fde around */
+ return;
+ }
+ state->sys_errno = errno;
+ TALLOC_FREE(fde);
+ tevent_req_error(req, errno);
+ return;
}
int async_connect_recv(struct tevent_req *req, int *perrno)
int count;
size_t total_size;
uint16_t flags;
+ bool err_on_readability;
};
static void writev_trigger(struct tevent_req *req, void *private_data);
if (state->iov == NULL) {
goto fail;
}
- state->flags = TEVENT_FD_WRITE;
- if (err_on_readability) {
- state->flags |= TEVENT_FD_READ;
- }
+ state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
+ state->err_on_readability = err_on_readability;
if (queue == NULL) {
struct tevent_fd *fde;
to_write = 0;
if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) {
- tevent_req_error(req, EPIPE);
- return;
+ int ret, value;
+
+ if (state->err_on_readability) {
+ /* Readable and the caller wants an error on read. */
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ /* Might be an error. Check if there are bytes to read */
+ ret = ioctl(state->fd, FIONREAD, &value);
+ /* FIXME - should we also check
+ for ret == 0 and value == 0 here ? */
+ if (ret == -1) {
+ /* There's an error. */
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+ /* A request for TEVENT_FD_READ will succeed from now and
+ forevermore until the bytes are read so if there was
+ an error we'll wait until we do read, then get it in
+ the read callback function. Until then, remove TEVENT_FD_READ
+ from the flags we're waiting for. */
+ state->flags &= ~TEVENT_FD_READ;
+ TEVENT_FD_NOT_READABLE(fde);
+
+ /* If not writable, we're done. */
+ if (!(flags & TEVENT_FD_WRITE)) {
+ return;
+ }
}
for (i=0; i<state->count; i++) {
}
written = writev(state->fd, state->iov, state->count);
- if ((written == -1) && (errno = EINTR)) {
+ if ((written == -1) && (errno == EINTR)) {
/* retry */
return;
}
*pbuf = talloc_move(mem_ctx, &state->buf);
return talloc_get_size(*pbuf);
}
+
+struct wait_for_read_state {
+ struct tevent_req *req;
+ struct tevent_fd *fde;
+};
+
+static void wait_for_read_done(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd)
+{
+ struct tevent_req *req;
+ struct wait_for_read_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->req = req;
+ state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
+ wait_for_read_done, state);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void wait_for_read_done(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct wait_for_read_state *state = talloc_get_type_abort(
+ private_data, struct wait_for_read_state);
+
+ if (flags & TEVENT_FD_READ) {
+ TALLOC_FREE(state->fde);
+ tevent_req_done(state->req);
+ }
+}
+
+bool wait_for_read_recv(struct tevent_req *req, int *perr)
+{
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ *perr = err;
+ return false;
+ }
+ return true;
+}