User-level dial and get_html update
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 23 Jan 2014 01:19:59 +0000 (17:19 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 23 Jan 2014 01:19:59 +0000 (17:19 -0800)
To use, #include <net.h>.  Later, I might write announce() and whatever
others we need.

We can move dial() or snprintf_overflow() somewhere else, if we want.

tests/get_html.c
user/parlib/include/net.h [new file with mode: 0644]
user/parlib/net.c [new file with mode: 0644]

index a05f9e0..277590a 100644 (file)
@@ -3,24 +3,18 @@
 #include <string.h>
 #include <unistd.h>
 #include <assert.h>
-//#include <nixip.h>
+#include <net.h>
 
-int main()
-{
-       printf("Commented out, pending inferno stack\n");
-       return 0;
-}
-
-#if 0
 /* simple test, gets a single web page.  no url parsing, no timeout detection,
  * etc.  pass it the IP addr and page to fetch.
  *
  * check out http://www.d.umn.edu/~gshute/net/http-script.html for some info. */
 int main(int argc, char *argv[])
 {
-       char *host, *page, *addr;
+       char *host, *page;
        int dfd, ret;
        char buf[128];
+       char addr[256];
        if (argc != 3) {
                printf("Usage: %s HOST PAGE\n", argv[0]);
                host = "128.32.37.180";
@@ -30,8 +24,12 @@ int main(int argc, char *argv[])
                page = argv[2];
        }
        printf("Trying to access http://%s/%s\n", host, page);
-       /* mkaddr/dial style */
-       addr = netmkaddr(host, "/9/net/tcp", "80");
+       /* manually making our own addr (no mkaddr, which was racy anyway) */
+       ret = snprintf(addr, sizeof(addr), "tcp!%s!%s", host, "80");
+       if (snprintf_overflow(ret, addr, sizeof(addr))) {
+               perror("Addr string too long");
+               exit(-1);
+       }
        dfd = dial(addr, 0, 0, 0);
        if (dfd < 0) {
                perror("Bad Data FD");
@@ -52,4 +50,3 @@ int main(int argc, char *argv[])
                printf("%s", buf);
        }
 }
-#endif
diff --git a/user/parlib/include/net.h b/user/parlib/include/net.h
new file mode 100644 (file)
index 0000000..3218bfc
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Networking helpers for dealing with the plan 9 interface. */
+
+#ifndef _NET_H
+#define _NET_H
+
+static inline int snprintf_overflow(int ret, char *buf, size_t buf_len)
+{
+       return (ret == buf_len) && (buf[buf_len - 1] != 0);
+}
+
+int dial(char *addr, char *local, char *dir, int *cfdp);
+
+#endif /* _NET_H */
diff --git a/user/parlib/net.c b/user/parlib/net.c
new file mode 100644 (file)
index 0000000..7d3ceba
--- /dev/null
@@ -0,0 +1,106 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Networking helpers for dealing with the plan 9 interface. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <net.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* my cheap dial, assumes either /net/ or a protocol first, with !s btw the
+ * proto, host, and port.  it also will modify addr temporarily.  */
+int dial(char *addr, char *local, char *dir, int *cfdp)
+{
+       int ret, ctlfd, datafd, conv_id;
+       char *prefix;
+       char *hostname;                                         /* including !port */
+       size_t buf_len = strlen(addr) + 30;     /* 30 should be enough extra */
+       char *buf = malloc(buf_len);
+       if (!buf) {
+               perror("Unable to malloc buf!");
+               return -1;
+       }
+       if (local || dir) {
+               perror("Cheap dial doesn't support local or dir");
+               ret = -1;
+               goto out_buf;
+       }
+       hostname = strchr(addr, '!');
+       if (!hostname) {
+               perror("No first bang");
+               ret = -1;
+               goto out_buf;
+       }
+       *hostname++ = '\0';
+       prefix = (addr[0] == '/' ? "" : "/net/");
+       ret = snprintf(buf, buf_len, "%s%s/clone", prefix, addr);
+       if (snprintf_overflow(ret, buf, buf_len)) {
+               perror("Clone chan path too long");
+               ret = -1;
+               goto out_readdr;
+       }
+       ctlfd = open(buf, O_RDWR);
+       if (ctlfd < 0) {
+               perror("Can't clone a conversation");
+               ret = -1;
+               goto out_readdr;
+       }
+       ret = read(ctlfd, buf, buf_len - 1);
+       if (ret <= 0) {
+               if (!ret)
+                       printf("Got early EOF from ctl\n");
+               else
+                       perror("Can't read ctl");
+               ret = -1;
+               goto out_ctlfd;
+       }
+       buf[ret] = 0;
+       conv_id = atoi(buf);
+       ret = snprintf(buf, buf_len, "connect %s", hostname);
+       if (snprintf_overflow(ret, buf, buf_len)) {
+               perror("Connect string too long");
+               ret = -1;
+               goto out_ctlfd;
+       }
+       if ((write(ctlfd, buf, strlen(buf)) <= 0)) {
+               perror("Failed to connect");
+               ret = -1;
+               goto out_ctlfd;
+       }
+       ret = snprintf(buf, buf_len, "%s%s/%d/data", prefix, addr, conv_id);
+       if (snprintf_overflow(ret, buf, buf_len)) {
+               perror("Data chan path too long");
+               ret = -1;
+               goto out_ctlfd;
+       }
+       datafd = open(buf, O_RDWR);
+       if (datafd < 0) {
+               perror("Failed to open data chan");
+               ret = -1;
+               goto out_ctlfd;
+       }
+       if (cfdp)
+               *cfdp = ctlfd;
+       else
+               close(ctlfd);
+       ret = datafd;
+       /* skip over the ctlfd close */
+       goto out_readdr;
+
+out_ctlfd:
+       close(ctlfd);
+out_readdr:
+       /* restore the change we made to addr */
+       *--hostname = '!';
+out_buf:
+       free(buf);
+       return ret;
+}