socket-wrapped: added wrappers for dup() and dup2()
authorAndrew Tridgell <tridge@samba.org>
Fri, 12 Aug 2011 04:28:03 +0000 (14:28 +1000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 12 Aug 2011 07:38:26 +0000 (09:38 +0200)
The Samba4 standard process model uses dup() on incoming sockets as an
optimisation (it makes select() a tiny bit faster when used).

Adding dup() to socket wrapper allows us to use the standard process
model in selftest

Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>

lib/socket_wrapper/socket_wrapper.c
lib/socket_wrapper/socket_wrapper.h

index 2b526262bd78f26aee0ed7cb3534fd9e12ae696f..946980963edce71d1cf399bcecc240ba9af99e41 100644 (file)
 #define real_writev writev
 #define real_socket socket
 #define real_close close
+#define real_dup dup
+#define real_dup2 dup2
 #endif
 
 #ifdef HAVE_GETTIMEOFDAY_TZ
@@ -225,7 +227,6 @@ struct socket_info
        int connected;
        int defer_connect;
 
-       char *path;
        char *tmp_path;
 
        struct sockaddr *myname;
@@ -2523,7 +2524,6 @@ _PUBLIC_ int swrap_close(int fd)
                swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
        }
 
-       if (si->path) free(si->path);
        if (si->myname) free(si->myname);
        if (si->peername) free(si->peername);
        if (si->tmp_path) {
@@ -2534,3 +2534,121 @@ _PUBLIC_ int swrap_close(int fd)
 
        return ret;
 }
+
+_PUBLIC_ int swrap_dup(int fd)
+{
+       struct socket_info *si, *si2;
+       int fd2;
+
+       si = find_socket_info(fd);
+
+       if (!si) {
+               return real_dup(fd);
+       }
+
+       if (si->tmp_path) {
+               /* we would need reference counting to handle this */
+               errno = EINVAL;
+               return -1;
+       }
+
+       fd2 = real_dup(fd);
+       if (fd2 == -1) {
+               return -1;
+       }
+
+       si2 = (struct socket_info *)malloc(sizeof(struct socket_info));
+       if (si2 == NULL) {
+               real_close(fd2);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       /* copy the whole structure, then duplicate pointer elements */
+       *si2 = *si;
+
+       si2->fd = fd2;
+
+       if (si2->myname) {
+               si2->myname = sockaddr_dup(si2->myname, si2->myname_len);
+               if (si2->myname == NULL) {
+                       real_close(fd2);
+                       errno = ENOMEM;
+                       return -1;
+               }
+       }
+
+       if (si2->peername) {
+               si2->peername = sockaddr_dup(si2->peername, si2->peername_len);
+               if (si2->peername == NULL) {
+                       real_close(fd2);
+                       errno = ENOMEM;
+                       return -1;
+               }
+       }
+
+       SWRAP_DLIST_ADD(sockets, si2);
+       return fd2;
+}
+
+_PUBLIC_ int swrap_dup2(int fd, int newfd)
+{
+       struct socket_info *si, *si2;
+       int fd2;
+
+       si = find_socket_info(fd);
+
+       if (!si) {
+               return real_dup2(fd, newfd);
+       }
+
+       if (si->tmp_path) {
+               /* we would need reference counting to handle this */
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (find_socket_info(newfd)) {
+               /* dup2() does an implicit close of newfd, which we
+                * need to emulate */
+               swrap_close(newfd);
+       }
+
+       fd2 = real_dup2(fd, newfd);
+       if (fd2 == -1) {
+               return -1;
+       }
+
+       si2 = (struct socket_info *)malloc(sizeof(struct socket_info));
+       if (si2 == NULL) {
+               real_close(fd2);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       /* copy the whole structure, then duplicate pointer elements */
+       *si2 = *si;
+
+       si2->fd = fd2;
+
+       if (si2->myname) {
+               si2->myname = sockaddr_dup(si2->myname, si2->myname_len);
+               if (si2->myname == NULL) {
+                       real_close(fd2);
+                       errno = ENOMEM;
+                       return -1;
+               }
+       }
+
+       if (si2->peername) {
+               si2->peername = sockaddr_dup(si2->peername, si2->peername_len);
+               if (si2->peername == NULL) {
+                       real_close(fd2);
+                       errno = ENOMEM;
+                       return -1;
+               }
+       }
+
+       SWRAP_DLIST_ADD(sockets, si2);
+       return fd2;
+}
index 77af6feadd7d0658fda80a1af8204242e5b85256..32c9de6b682bdd2485065ce8a721614e26d7a0e2 100644 (file)
@@ -58,6 +58,8 @@ ssize_t swrap_send(int s, const void *buf, size_t len, int flags);
 int swrap_readv(int s, const struct iovec *vector, size_t count);
 int swrap_writev(int s, const struct iovec *vector, size_t count);
 int swrap_close(int);
+int swrap_dup(int oldfd);
+int swrap_dup2(int oldfd, int newfd);
 
 #ifdef SOCKET_WRAPPER_REPLACE
 
@@ -160,7 +162,16 @@ int swrap_close(int);
 #undef close
 #endif
 #define close(s)                       swrap_close(s)
+
+#ifdef dup
+#undef dup
 #endif
+#define dup(s)                 swrap_dup(s)
 
+#ifdef dup2
+#undef dup2
+#endif
+#define dup2(s, s2)            swrap_dup2(s, s2)
 
+#endif /* SOCKET_WRAPPER_REPLACE */
 #endif /* __SOCKET_WRAPPER_H__ */