Add getaddrinfo_send/recv
[ira/wip.git] / source3 / lib / util_sock.c
index de5b232aac7eba495a31d4d285061c176c41dc91..3fd0cc4ad31c83a0fe94ffecc9e2bbe94302b6fc 100644 (file)
@@ -208,13 +208,11 @@ static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len)
        return print_sockaddr_len(addr_buf, addr_len, (struct sockaddr *)&sa, length);
 }
 
-#if 0
-/* Not currently used. JRA. */
 /****************************************************************************
  Return the port number we've bound to on a socket.
 ****************************************************************************/
 
-static int get_socket_port(int fd)
+int get_socket_port(int fd)
 {
        struct sockaddr_storage sa;
        socklen_t length = sizeof(sa);
@@ -239,7 +237,6 @@ static int get_socket_port(int fd)
        }
        return -1;
 }
-#endif
 
 const char *client_name(int fd)
 {
@@ -519,7 +516,7 @@ NTSTATUS read_socket_with_timeout(int fd, char *buf,
                }
 
                while (nread < mincnt) {
-                       readret = sys_read(fd, buf + nread, maxcnt - nread);
+                       readret = sys_recv(fd, buf + nread, maxcnt - nread, 0);
 
                        if (readret == 0) {
                                DEBUG(5,("read_socket_with_timeout: "
@@ -588,7 +585,7 @@ NTSTATUS read_socket_with_timeout(int fd, char *buf,
                        return NT_STATUS_IO_TIMEOUT;
                }
 
-               readret = sys_read(fd, buf+nread, maxcnt-nread);
+               readret = sys_recv(fd, buf+nread, maxcnt-nread, 0);
 
                if (readret == 0) {
                        /* we got EOF on the file descriptor */
@@ -1942,6 +1939,10 @@ bool is_myname_or_ipaddr(const char *s)
                        return false;
                }
 
+               if (ismyaddr((struct sockaddr *)&ss)) {
+                       return true;
+               }
+
                if (is_zero_addr((struct sockaddr *)&ss) || 
                        is_loopback_addr((struct sockaddr *)&ss)) {
                        return false;
@@ -1965,3 +1966,172 @@ bool is_myname_or_ipaddr(const char *s)
        /* No match */
        return false;
 }
+
+/*
+ * Read an smb packet asynchronously, discard keepalives
+ */
+
+struct read_smb_state {
+       struct tevent_context *ev;
+       int fd;
+       uint8_t *buf;
+};
+
+static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data);
+static void read_smb_done(struct tevent_req *subreq);
+
+struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
+                                struct tevent_context *ev,
+                                int fd)
+{
+       struct tevent_req *result, *subreq;
+       struct read_smb_state *state;
+
+       result = tevent_req_create(mem_ctx, &state, struct read_smb_state);
+       if (result == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+       state->fd = fd;
+
+       subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL);
+       if (subreq == NULL) {
+               goto fail;
+       }
+       tevent_req_set_callback(subreq, read_smb_done, result);
+       return result;
+ fail:
+       TALLOC_FREE(result);
+       return NULL;
+}
+
+static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data)
+{
+       if (buflen > 4) {
+               return 0;       /* We've been here, we're done */
+       }
+       return smb_len_large(buf);
+}
+
+static void read_smb_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct read_smb_state *state = tevent_req_data(
+               req, struct read_smb_state);
+       ssize_t len;
+       int err;
+
+       len = read_packet_recv(subreq, state, &state->buf, &err);
+       TALLOC_FREE(subreq);
+       if (len == -1) {
+               tevent_req_error(req, err);
+               return;
+       }
+
+       if (CVAL(state->buf, 0) == SMBkeepalive) {
+               subreq = read_packet_send(state, state->ev, state->fd, 4,
+                                         read_smb_more, NULL);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+               tevent_req_set_callback(subreq, read_smb_done, req);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                     uint8_t **pbuf, int *perrno)
+{
+       struct read_smb_state *state = tevent_req_data(
+               req, struct read_smb_state);
+
+       if (tevent_req_is_unix_error(req, perrno)) {
+               return -1;
+       }
+       *pbuf = talloc_move(mem_ctx, &state->buf);
+       return talloc_get_size(*pbuf);
+}
+
+struct getaddrinfo_state {
+       const char *node;
+       const char *service;
+       const struct addrinfo *hints;
+       struct addrinfo *res;
+       int ret;
+};
+
+static void getaddrinfo_do(void *private_data);
+static void getaddrinfo_done(struct tevent_req *subreq);
+
+struct tevent_req *getaddrinfo_send(TALLOC_CTX *mem_ctx,
+                                   struct tevent_context *ev,
+                                   struct fncall_context *ctx,
+                                   const char *node,
+                                   const char *service,
+                                   const struct addrinfo *hints)
+{
+       struct tevent_req *req, *subreq;
+       struct getaddrinfo_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct getaddrinfo_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->node = node;
+       state->service = service;
+       state->hints = hints;
+
+       subreq = fncall_send(state, ev, ctx, getaddrinfo_do, state);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, getaddrinfo_done, req);
+       return req;
+}
+
+static void getaddrinfo_do(void *private_data)
+{
+       struct getaddrinfo_state *state =
+               (struct getaddrinfo_state *)private_data;
+
+       state->ret = getaddrinfo(state->node, state->service, state->hints,
+                                &state->res);
+}
+
+static void getaddrinfo_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       int ret, err;
+
+       ret = fncall_recv(subreq, &err);
+       TALLOC_FREE(subreq);
+       if (ret == -1) {
+               tevent_req_error(req, err);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+int getaddrinfo_recv(struct tevent_req *req, struct addrinfo **res)
+{
+       struct getaddrinfo_state *state = tevent_req_data(
+               req, struct getaddrinfo_state);
+       int err;
+
+       if (tevent_req_is_unix_error(req, &err)) {
+               switch(err) {
+               case ENOMEM:
+                       return EAI_MEMORY;
+               default:
+                       return EAI_FAIL;
+               }
+       }
+       if (state->ret == 0) {
+               *res = state->res;
+       }
+       return state->ret;
+}