aboutsummaryrefslogtreecommitdiff
path: root/src/lib9/announce.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib9/announce.c')
-rw-r--r--src/lib9/announce.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/lib9/announce.c b/src/lib9/announce.c
new file mode 100644
index 00000000..dc8cbbbf
--- /dev/null
+++ b/src/lib9/announce.c
@@ -0,0 +1,137 @@
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+extern int _p9dialparse(char*, char**, char**, u32int*, int*);
+
+static int
+getfd(char *dir)
+{
+ int fd;
+
+ if(strncmp(dir, "/dev/fd/", 8) != 0)
+ return -1;
+ fd = strtol(dir+8, &dir, 0);
+ if(*dir != 0)
+ return -1;
+ return fd;
+}
+
+static void
+putfd(char *dir, int fd)
+{
+ snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
+}
+
+#undef unix
+
+int
+p9announce(char *addr, char *dir)
+{
+ int proto;
+ char *buf, *unix;
+ char *net;
+ u32int host;
+ int port, s;
+ int n, sn;
+ struct sockaddr_in sa;
+ struct sockaddr_un sun;
+
+ buf = strdup(addr);
+ if(buf == nil)
+ return -1;
+
+ if(_p9dialparse(buf, &net, &unix, &host, &port) < 0){
+ free(buf);
+ return -1;
+ }
+ if(strcmp(net, "tcp") == 0)
+ proto = SOCK_STREAM;
+ else if(strcmp(net, "udp") == 0)
+ proto = SOCK_DGRAM;
+ else if(strcmp(net, "unix") == 0)
+ goto Unix;
+ else{
+ werrstr("can only handle tcp, udp, and unix: not %s", net);
+ free(buf);
+ return -1;
+ }
+ free(buf);
+
+ memset(&sa, 0, sizeof sa);
+ memmove(&sa.sin_addr, &host, 4);
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ if((s = socket(AF_INET, proto, 0)) < 0)
+ return -1;
+ sn = sizeof n;
+ if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&n, &sn) >= 0
+ && n == SOCK_STREAM){
+ n = 1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
+ }
+ if(bind(s, (struct sockaddr*)&sa, sizeof sa) < 0){
+ close(s);
+ return -1;
+ }
+ if(proto == SOCK_STREAM){
+ listen(s, 8);
+ putfd(dir, s);
+print("announce dir: %s\n", dir);
+ }
+ return s;
+
+Unix:
+ memset(&sun, 0, sizeof sun);
+ sun.sun_family = AF_UNIX;
+ sun.sun_len = sizeof sun;
+ strcpy(sun.sun_path, unix);
+ if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ return -1;
+ sn = sizeof sun;
+ if(bind(s, (struct sockaddr*)&sun, sizeof sun) < 0){
+ close(s);
+ return -1;
+ }
+ listen(s, 8);
+ putfd(dir, s);
+ return s;
+}
+
+int
+p9listen(char *dir, char *newdir)
+{
+ int fd;
+
+ if((fd = getfd(dir)) < 0){
+ werrstr("bad 'directory' in listen: %s", dir);
+ return -1;
+ }
+
+print("accept %d", fd);
+ if((fd = accept(fd, nil, nil)) < 0)
+ return -1;
+print(" -> %d\n", fd);
+
+ putfd(newdir, fd);
+print("listen dir: %s\n", newdir);
+ return fd;
+}
+
+int
+p9accept(int cfd, char *dir)
+{
+ int fd;
+
+ if((fd = getfd(dir)) < 0){
+ werrstr("bad 'directory' in accept");
+ return -1;
+ }
+ /* need to dup because the listen fd will be closed */
+ return dup(fd);
+}
+