dynconfig: added SBINDIR and BINDIR as updated dynconfig variables
[nivanova/samba-autobuild/.git] / lib / async_req / async_sock.c
index 643eb2d308f5c42686f310089d5dc1c4ad599b22..545d21378fa1b7a082763231ec639b8ba41d200b 100644 (file)
    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;
        }
@@ -61,8 +66,26 @@ struct tevent_req *async_send_send(TALLOC_CTX *mem_ctx,
        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);
@@ -71,16 +94,18 @@ struct tevent_req *async_send_send(TALLOC_CTX *mem_ctx,
        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;
@@ -92,10 +117,10 @@ static void async_send_handler(struct tevent_context *ev,
        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;
@@ -103,27 +128,31 @@ ssize_t async_send_recv(struct tevent_req *req, int *perrno)
        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;
        }
@@ -131,8 +160,10 @@ struct tevent_req *async_recv_send(TALLOC_CTX *mem_ctx,
        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);
@@ -141,21 +172,26 @@ struct tevent_req *async_recv_send(TALLOC_CTX *mem_ctx,
        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;
@@ -163,10 +199,10 @@ static void async_recv_handler(struct tevent_context *ev,
        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;
@@ -290,36 +326,24 @@ static void async_connect_connected(struct tevent_context *ev,
                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)
@@ -350,6 +374,7 @@ struct writev_state {
        int count;
        size_t total_size;
        uint16_t flags;
+       bool err_on_readability;
 };
 
 static void writev_trigger(struct tevent_req *req, void *private_data);
@@ -377,10 +402,8 @@ struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
        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;
@@ -426,8 +449,35 @@ static void writev_handler(struct tevent_context *ev, 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++) {
@@ -435,7 +485,7 @@ static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
        }
 
        written = writev(state->fd, state->iov, state->count);
-       if ((written == -1) && (errno = EINTR)) {
+       if ((written == -1) && (errno == EINTR)) {
                /* retry */
                return;
        }
@@ -605,3 +655,58 @@ ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
        *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;
+}