Provide a lookup for a socket's listen FD (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Sep 2015 18:08:26 +0000 (14:08 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
Due to the nature of Rocks, in that they basically multiplex the entire
conversation directory into one FD, we need a way to get certain parts
of the Rock from libraries/apps (e.g. epoll).

The listen fd is one of those things we need.  However, unlike with the
ctl file, we actually want the FD for Qlisten.  These functions will
create and return a listen FD on demand (the "get" function) and lookup
previously created FDs.  It is the job of the caller to close the FD
when it's done.

Ideally, I'd just have close() call out to the Rock code to close a
potential Rock.  Then we just store the FD in there, and don't really
worry about it.  However, close.c cannot link against the plan9_sockets,
due to the "multiple libcs" problem endemic to glibc.

Rebuild glibc.

tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Versions
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/listen.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.h

index bad6f43..f3837ac 100644 (file)
@@ -66,9 +66,8 @@ int __listen(int fd, int backlog)
                                return -1;
                        }
                        close(cfd);
-
+                       r->is_listener = TRUE;
                        return 0;
-
                case PF_UNIX:
                        if (r->other < 0) {
                                errno = EINVAL; //EGREG;
index fae05b0..d26df10 100644 (file)
@@ -182,6 +182,8 @@ Rock *_sock_newrock(int fd)
        memset(&r->raddr, 0, sizeof(r->raddr));
        r->ctl[0] = '\0';
        r->other = -1;
+       r->is_listener = FALSE;
+       r->listen_fd = -1;
        return r;
 }
 
@@ -280,3 +282,54 @@ int _sock_get_opts(int type)
 {
        return type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
 }
+
+/* Used by user/iplib (e.g. epoll).  Opens and returns the FD for the
+ * conversation's listen fd, which the caller needs to close.  Returns -1 if the
+ * FD is not a listener. */
+int _sock_get_listen_fd(int sock_fd)
+{
+       char listen_file[Ctlsize + 3];
+       char *x, *last_ctl;
+       Rock *r = _sock_findrock(sock_fd, 0);
+       int ret;
+
+       if (!r)
+               return -1;
+       if (!r->is_listener)
+               return -1;
+       /* We want an FD for the "listen" file.  This is for epoll.  We
+        * could optimize and only do this on demand, but whatever. */
+       strncpy(listen_file, r->ctl, sizeof(listen_file));
+       /* We want the conversation directory.  We can find the last "ctl"
+        * in the CTL name (they could have mounted at /ctlfoo/net/) */
+       x = listen_file;
+       do {
+               last_ctl = x;
+               x++;    /* move forward enough to not find the same "ctl" */
+               x = strstr(x, "ctl");
+       } while (x);
+       /* last_ctl is either listen_file (if we never found ctl, which should never
+        * happen) or it points at the 'c' in the last "ctl". */
+       assert(last_ctl != listen_file);
+       strcpy(last_ctl, "listen");
+       ret = open(listen_file, O_PATH);
+       /* Probably a bug in the rock code (or the kernel!) if we couldn't walk to
+        * our listen. */
+       assert(ret >= 0);
+       r->listen_fd = ret;
+       return ret;
+}
+
+/* Used by user/iplib (e.g. epoll).  Looks up a previously opened FD for the
+ * listen file for this conversation.  Returns -1 if the FD is not a listener
+ * with an already-opened listen FD. */
+int _sock_lookup_listen_fd(int sock_fd)
+{
+       Rock *r = _sock_findrock(sock_fd, 0);
+
+       if (!r)
+               return -1;
+       if (!r->is_listener)
+               return -1;
+       return r->listen_fd;
+}
index a6ca8bd..46f6cea 100644 (file)
@@ -51,6 +51,8 @@ struct Rock {
        struct sockaddr raddr;          /* peer address */
        char ctl[Ctlsize];                      /* name of control file (if any) */
        int other;                                      /* fd of the remote end for Unix domain */
+       bool is_listener;                       /* has called listen() and will accept() */
+       int listen_fd;                          /* fd of the listen file, if any */
 };
 
 extern Rock *_sock_findrock(int, struct stat *);