docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket / socket.c
index 184c89f3edfb25098a6ce5a7c2c0173d9c4e1eb6..26f23f5665366a43e01df889146c3239ccd89e9d 100644 (file)
@@ -24,6 +24,8 @@
 #include "system/filesys.h"
 #include "system/network.h"
 #include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+#include "lib/util/util_net.h"
 
 /*
   auto-close sockets on free
@@ -37,6 +39,15 @@ static int socket_destructor(struct socket_context *sock)
        return 0;
 }
 
+_PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
+                                       struct tevent_fd *fde,
+                                       int fd,
+                                       void *private_data)
+{
+       /* this might be the socket_wrapper swrap_close() */
+       close(fd);
+}
+
 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
                                         struct socket_context **new_sock, 
                                         enum socket_type type, uint32_t flags)
@@ -68,16 +79,15 @@ _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socke
           send calls on non-blocking sockets will randomly recv/send
           less data than requested */
 
-       if (!(flags & SOCKET_FLAG_BLOCK) &&
-           type == SOCKET_TYPE_STREAM &&
-           lp_parm_bool(-1, "socket", "testnonblock", False)) {
+       if (type == SOCKET_TYPE_STREAM &&
+               getenv("SOCKET_TESTNONBLOCK") != NULL) {
                (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
        }
 
        /* we don't do a connect() on dgram sockets, so need to set
           non-blocking at socket create time */
-       if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
-               set_blocking(socket_get_fd(*new_sock), False);
+       if (type == SOCKET_TYPE_DGRAM) {
+               set_blocking(socket_get_fd(*new_sock), false);
        }
 
        talloc_set_destructor(*new_sock, socket_destructor);
@@ -85,7 +95,8 @@ _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socke
        return NT_STATUS_OK;
 }
 
-_PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type, 
+_PUBLIC_ NTSTATUS socket_create(TALLOC_CTX *mem_ctx,
+                               const char *name, enum socket_type type,
                                struct socket_context **new_sock, uint32_t flags)
 {
        const struct socket_ops *ops;
@@ -95,7 +106,7 @@ _PUBLIC_ NTSTATUS socket_create(const char *name, enum socket_type type,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       return socket_create_with_ops(NULL, ops, new_sock, type, flags);
+       return socket_create_with_ops(mem_ctx, ops, new_sock, type, flags);
 }
 
 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
@@ -335,6 +346,91 @@ _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock,
        return sock->ops->fn_get_my_addr(sock, mem_ctx);
 }
 
+_PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
+                                                                  const struct socket_address *a)
+{
+       struct tsocket_address *r;
+       int ret;
+
+       if (!a) {
+               return NULL;
+       }
+       if (a->sockaddr) {
+               ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
+                                                       a->sockaddr,
+                                                       a->sockaddrlen,
+                                                       &r);
+       } else {
+               ret = tsocket_address_inet_from_strings(mem_ctx,
+                                                       a->family,
+                                                       a->addr,
+                                                       a->port,
+                                                       &r);
+       }
+
+       if (ret != 0) {
+               return NULL;
+       }
+
+       return r;
+}
+
+_PUBLIC_ void socket_address_set_port(struct socket_address *a,
+                                     uint16_t port)
+{
+       if (a->sockaddr) {
+               set_sockaddr_port(a->sockaddr, port);
+       } else {
+               a->port = port;
+       }
+
+}
+
+_PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
+                                                                 const struct tsocket_address *a)
+{
+       ssize_t ret;
+       struct sockaddr_storage ss;
+       size_t sslen = sizeof(ss);
+
+       ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
+       if (ret < 0) {
+               return NULL;
+       }
+
+       return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
+}
+
+_PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+       struct socket_address *a;
+       struct tsocket_address *r;
+
+       a = socket_get_peer_addr(sock, mem_ctx);
+       if (a == NULL) {
+               return NULL;
+       }
+
+       r = socket_address_to_tsocket_address(mem_ctx, a);
+       talloc_free(a);
+       return r;
+}
+
+_PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+       struct socket_address *a;
+       struct tsocket_address *r;
+
+       a = socket_get_my_addr(sock, mem_ctx);
+       if (a == NULL) {
+               return NULL;
+       }
+
+       r = socket_address_to_tsocket_address(mem_ctx, a);
+       talloc_free(a);
+       return r;
+}
+
 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
 {
        if (!sock->ops->fn_get_fd) {
@@ -358,7 +454,7 @@ _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
        }
        fd = dup(sock->fd);
        if (fd == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
        close(sock->fd);
        sock->fd = fd;
@@ -380,6 +476,11 @@ _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
+       if (strcmp(family, "ip") == 0 && is_ipaddress_v6(host)) {
+               /* leaving as "ip" would force IPv4 */
+               family = "ipv6";
+       }
+
        addr->family = family;
        addr->addr = talloc_strdup(addr, host);
        if (!addr->addr) {
@@ -405,7 +506,19 @@ _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx
        if (!addr) {
                return NULL;
        }
-       addr->family = NULL; 
+       switch (sockaddr->sa_family) {
+       case AF_INET:
+               addr->family = "ipv4";
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               addr->family = "ipv6";
+               break;
+#endif
+       case AF_UNIX:
+               addr->family = "unix";
+               break;
+       }
        addr->addr = NULL;
        addr->port = 0;
        addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
@@ -417,6 +530,83 @@ _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx
        return addr;
 }
 
+
+/*
+   Create a new socket_address from sockaddr_storage
+ */
+_PUBLIC_ struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx,
+                                                                    const struct sockaddr_storage *sockaddr,
+       uint16_t port)
+{
+       struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
+       char addr_str[INET6_ADDRSTRLEN+1];
+       const char *str;
+
+       if (!addr) {
+               return NULL;
+       }
+       addr->port = port;
+       switch (sockaddr->ss_family) {
+       case AF_INET:
+               addr->family = "ipv4";
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               addr->family = "ipv6";
+               break;
+#endif
+       default:
+               talloc_free(addr);
+               return NULL;
+       }
+
+       str = print_sockaddr(addr_str, sizeof(addr_str), sockaddr);
+       if (str == NULL) {
+               talloc_free(addr);
+               return NULL;
+       }
+       addr->addr = talloc_strdup(addr, str);
+       if (addr->addr == NULL) {
+               talloc_free(addr);
+               return NULL;
+       }
+
+       return addr;
+}
+
+/* Copy a socket_address structure */
+struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx,
+                                          const struct socket_address *oaddr)
+{
+       struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
+       if (!addr) {
+               return NULL;
+       }
+       addr->family    = oaddr->family;
+       if (oaddr->addr) {
+               addr->addr      = talloc_strdup(addr, oaddr->addr);
+               if (!addr->addr) {
+                       goto nomem;
+               }
+       }
+       addr->port      = oaddr->port;
+       if (oaddr->sockaddr) {
+               addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
+                                                                 oaddr->sockaddr,
+                                                                 oaddr->sockaddrlen);
+               if (!addr->sockaddr) {
+                       goto nomem;
+               }
+               addr->sockaddrlen = oaddr->sockaddrlen;
+       }
+
+       return addr;
+
+nomem:
+       talloc_free(addr);
+       return NULL;
+}
+
 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
 {
        extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
@@ -428,7 +618,7 @@ _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum
                return socket_ipv4_ops(type);
        }
 
-#if HAVE_IPV6
+#ifdef HAVE_IPV6
        if (strcmp("ipv6", family) == 0) {
                return socket_ipv6_ops(type);
        }
@@ -441,110 +631,6 @@ _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum
        return NULL;
 }
 
-enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
-
-static const struct {
-       const char *name;
-       int level;
-       int option;
-       int value;
-       int opttype;
-} socket_options[] = {
-  {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},
-  {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},
-  {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},
-#ifdef TCP_NODELAY
-  {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},
-#endif
-#ifdef IPTOS_LOWDELAY
-  {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},
-#endif
-#ifdef IPTOS_THROUGHPUT
-  {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},
-#endif
-#ifdef SO_REUSEPORT
-  {"SO_REUSEPORT",      SOL_SOCKET,    SO_REUSEPORT,    0,                 OPT_BOOL},
-#endif
-#ifdef SO_SNDBUF
-  {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},
-#endif
-#ifdef SO_RCVBUF
-  {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},
-#endif
-#ifdef SO_SNDLOWAT
-  {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},
-#endif
-#ifdef SO_RCVLOWAT
-  {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
-#endif
-#ifdef SO_SNDTIMEO
-  {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
-#endif
-#ifdef SO_RCVTIMEO
-  {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
-#endif
-  {NULL,0,0,0,0}};
-
-
-/**
- Set user socket options.
-**/
-_PUBLIC_ void set_socket_options(int fd, const char *options)
-{
-       const char **options_list = str_list_make(NULL, options, " \t,");
-       int j;
-
-       if (!options_list)
-               return;
-
-       for (j = 0; options_list[j]; j++) {
-               const char *tok = options_list[j];
-               int ret=0,i;
-               int value = 1;
-               char *p;
-               BOOL got_value = False;
-
-               if ((p = strchr(tok,'='))) {
-                       *p = 0;
-                       value = atoi(p+1);
-                       got_value = True;
-               }
-
-               for (i=0;socket_options[i].name;i++)
-                       if (strequal(socket_options[i].name,tok))
-                               break;
-
-               if (!socket_options[i].name) {
-                       DEBUG(0,("Unknown socket option %s\n",tok));
-                       continue;
-               }
-
-               switch (socket_options[i].opttype) {
-               case OPT_BOOL:
-               case OPT_INT:
-                       ret = setsockopt(fd,socket_options[i].level,
-                                               socket_options[i].option,(char *)&value,sizeof(int));
-                       break;
-
-               case OPT_ON:
-                       if (got_value)
-                               DEBUG(0,("syntax error - %s does not take a value\n",tok));
-
-                       {
-                               int on = socket_options[i].value;
-                               ret = setsockopt(fd,socket_options[i].level,
-                                                       socket_options[i].option,(char *)&on,sizeof(int));
-                       }
-                       break;    
-               }
-      
-               if (ret != 0)
-                       DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
-       }
-
-       talloc_free(options_list);
-}
-
 /*
   set some flags on a socket 
  */