BSD sockets fix-up
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 4 Jun 2014 22:59:22 +0000 (15:59 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 4 Jun 2014 23:03:30 +0000 (16:03 -0700)
Removes the listenproc stuff and just does the plan9-listen directly.

Also adds a listener to test basic listening for both plan9 and BSD.
You'll need to manually edit and compile it to use the BSD code.  Check
out the top of the file for more info.

tests/listener.c [new file with mode: 0644]
user/bsd/_sock_ingetaddr.c
user/bsd/accept.c
user/bsd/listen.c
user/bsd/socket.c

diff --git a/tests/listener.c b/tests/listener.c
new file mode 100644 (file)
index 0000000..fa5750b
--- /dev/null
@@ -0,0 +1,144 @@
+/* Echo server, runs on port 23.  Main purpose is low-level network debugging
+ * and to show how networking commands in plan 9 correspond to BSD sockets. 
+ *
+ * if you want to build the BSD version, you need to change the #define and link
+ * with -lbsd instead of -liplib.  easiest way is to build manually:
+ *
+ * $ x86_64-ros-gcc   -O2 -std=gnu99 -fno-stack-protector -fgnu89-inline -g 
+ * -o obj/tests/listener tests/listener.c -lpthread -lbenchutil -lm -lbsd
+ *
+ * based off http://www2.informatik.hu-berlin.de/~apolze/LV/plan9.docs/net.V
+ * and http://en.wikibooks.org/wiki/C_Programming/Networking_in_UNIX */
+
+#define PLAN9NET 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <parlib.h>
+#include <unistd.h>
+#include <event.h>
+#include <measure.h>
+#include <uthread.h>
+#include <timing.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef PLAN9NET
+
+#include <iplib.h>
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#endif
+
+int main()
+{
+       int ret;
+       int afd, dfd, lcfd;
+       char adir[40], ldir[40];
+       int n;
+       char buf[256];
+       char debugbuf[256];
+
+#ifdef PLAN9NET
+       /* This clones a conversation (opens /net/tcp/clone), then reads the cloned
+        * fd (which is the ctl) to givure out the conv number (the line), then
+        * writes "announce [addr]" into ctl.  This "announce" command often has a
+        * "bind" in it too.  plan9 bind just sets the local addr/port.  TCP
+        * announce also does this.  Returns the ctlfd. */
+       afd = announce("tcp!*!23", adir);
+
+       if (afd < 0) {
+               perror("Announce failure");
+               return -1;
+       }
+       printf("Announced on line %s\n", adir);
+#else
+       int srv_socket, con_socket;
+       struct sockaddr_in dest, srv = {0};
+       srv.sin_family = AF_INET;
+       srv.sin_addr.s_addr = htonl(INADDR_ANY);
+       srv.sin_port = htons(23);
+       socklen_t socksize = sizeof(struct sockaddr_in);
+
+       /* Equiv to cloning a converstation in plan 9.  The shim returns the data FD
+        * for the conversation. */
+       srv_socket = socket(AF_INET, SOCK_STREAM, 0);
+       if (srv_socket < 0) {
+               perror("Socket failure");
+               return -1;
+       }
+
+       /* bind + listen is equiv to announce() in plan 9.  Note that the "bind"
+        * command is used, unlike in the plan9 announce. */
+       /* Binds our socket to the given addr/port in srv. */
+       ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in));
+       if (ret < 0) {
+               perror("Bind failure");
+               return -1;
+       }
+       /* marks the socket as a listener/server */
+       ret = listen(srv_socket, 1);
+       if (ret < 0) {
+               perror("Listen failure");
+               return -1;
+       }
+#endif
+
+       /* at this point, the server has done all the prep necessary to be able to
+        * sleep/block/wait on an incoming connection. */
+
+#ifdef PLAN9NET
+       /* Opens the conversation's listen file.  This blocks til someone connects.
+        * When they do, a new conversation is created, and that open returned an FD
+        * for the new conv's ctl.  listen() reads that to find out the conv number
+        * (the line) for this new conv.  listen() returns the ctl for this new
+        * conv. */
+       lcfd = listen(adir, ldir);
+
+       if (lcfd < 0) {
+               perror("Listen failure");
+               return -1;
+       }
+       printf("Listened and got line %s\n", ldir);
+
+       /* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and
+        * returns that fd.  Writing "accept" is a noop for most of our protocols.
+        * */
+       dfd = accept(lcfd, ldir);
+       if (dfd < 0) {
+               perror("Accept failure");
+               return -1;
+       }
+#else
+       /* returns an FD for a new socket. */
+       dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize);
+       if (dfd < 0) {
+               perror("Accept failure");
+               return -1;
+       }
+#endif
+
+       /* echo until EOF */
+       while ((n = read(dfd, buf, sizeof(buf))) > 0) {
+               snprintf(debugbuf, n, "%s", buf);
+               printf("Server read: %s", debugbuf);
+               write(dfd, buf, n);
+       }
+
+#ifdef PLAN9NET
+       close(dfd);             /* data fd for the new conv, from listen */
+       close(lcfd);    /* ctl fd for the new conv, from listen */
+       close(afd);             /* ctl fd for the listening conv */
+#else
+       close(dfd);             /* new connection socket, from accept */
+       close(srv_socket);
+#endif
+}
index 1f68681..1b5abcd 100644 (file)
@@ -44,7 +44,7 @@ _sock_ingetaddr(Rock *r, struct sockaddr_in *ip, int *alen, char *a)
                        if(p){
                                *p++ = 0;
                                ip->sin_family = AF_INET;
-                               ip->sin_port = atoi(p);
+                               ip->sin_port = htons(atoi(p));
                                ip->sin_addr.s_addr = inet_addr(name);
                                if(alen)
                                        *alen = sizeof(struct sockaddr_in);
index adbcea8..f64efed 100644 (file)
@@ -29,12 +29,13 @@ accept(int fd, __SOCKADDR_ARG __addr,
        socklen_t *__restrict alen)
 {
        void *a = (void*)__addr;
-       int n, nfd, cfd;
+       int n, nfd, lcfd;
        Rock *r, *nr;
        struct sockaddr_in *ip;
        char name[Ctlsize];
        char file[8+Ctlsize+1];
        char *p, *net;
+       char listen[Ctlsize];
 
        r = _sock_findrock(fd, 0);
        if(r == 0){
@@ -52,27 +53,25 @@ accept(int fd, __SOCKADDR_ARG __addr,
                        net = "tcp";
                        break;
                }
-
-               /* get control file name from listener process */
-               n = read(fd, name, sizeof(name)-1);
-               if(n <= 0){
-                       return -1;
-               }
-               name[n] = 0;
-               cfd = open(name, O_RDWR);
-               if(cfd < 0){
+               /* at this point, our FD is for the data file.  we need to open the
+                * listen file.  The line is stored in r->ctl (e.g. /net/tcp/666/ctl) */
+               strcpy(listen, r->ctl);
+               p = strrchr(listen, '/');
+               if (p == 0)
                        return -1;
-               }
+               strcpy(p + 1, "listen");
 
-               nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
-               if(nfd < 0){
+               lcfd = open(listen, O_RDWR);
+               if (lcfd < 0)
                        return -1;
-               }
-
-               if(write(fd, "OK", 2) < 0){
-                       close(nfd);
+               /* at this point, we have a new conversation, and lcfd is its ctl fd.
+                * nfd will be the FD for that conv's data file. */
+               nfd = _sock_data(lcfd, net, r->domain, r->stype, r->protocol, &nr);
+               if (nfd < 0)
                        return -1;
-               }
+               /* we have the data file, and can reopen the ctl based on the info in
+                * the rock (nr) */
+               close(lcfd);
 
                /* get remote address */
                ip = (struct sockaddr_in*)&nr->raddr;
index 4483602..f687446 100644 (file)
 
 #include "priv.h"
 
-/*
- * replace the fd with a pipe and start a process to
- * accept calls in.  this is all to make select work.
- * NO LONGER A PROC ON AKAROS.
- */
-static int
-listenproc(Rock *r, int fd)
-{
-       Rock *nr;
-       char *net;
-       int cfd, nfd, dfd;
-       struct stat d;
-       char *p;
-       char listen[Ctlsize];
-       char name[Ctlsize];
-
-       switch(r->stype){
-       case SOCK_DGRAM:
-               net = "udp";
-               break;
-       case SOCK_STREAM:
-               net = "tcp";
-               break;
-       }
-
-       strcpy(listen, r->ctl);
-       p = strrchr(listen, '/');
-       if(p == 0)
-               return -1;
-       strcpy(p+1, "listen");
-
-       /* start listening process */
-               cfd = open(listen, O_RDWR);
-               if(cfd < 0)
-                       return -1;
-
-               dfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
-               if(dfd < 0)
-                       return -1;
-
-               return fd;
-
-}
-
 int
 listen(fd, backlog)
        int fd;
@@ -113,7 +69,8 @@ listen(fd, backlog)
                }
                close(cfd);
 
-               return fd;
+               return 0;
+
        case PF_UNIX:
                if(r->other < 0){
                        errno = EINVAL;//EGREG;
index a60cc08..7dd926b 100644 (file)
@@ -56,6 +56,7 @@ _sock_newrock(int fd)
                r->dev = d.st_dev;
                r->inode = d.st_ino;
                r->other = -1;
+               /* TODO: this is not thread-safe! */
                r->next = _sock_rock;
                _sock_rock = r;
        }
@@ -68,6 +69,8 @@ _sock_newrock(int fd)
        return r;
 }
 
+/* For a ctlfd and a few other settings, it opens and returns the corresponding
+ * datafd. */
 int
 _sock_data(int cfd, char *net, int domain, int stype, int protocol, Rock **rp)
 {