Blob


1 #include <u.h>
2 #define NOPLAN9DEFINES
3 #include <libc.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <sys/un.h>
8 #include <errno.h>
10 #undef sun
11 #define sun sockun
12 extern int _p9dialparse(char*, char**, char**, u32int*, int*);
14 int
15 _p9netfd(char *dir)
16 {
17 int fd;
19 if(strncmp(dir, "/dev/fd/", 8) != 0)
20 return -1;
21 fd = strtol(dir+8, &dir, 0);
22 if(*dir != 0)
23 return -1;
24 return fd;
25 }
27 static void
28 putfd(char *dir, int fd)
29 {
30 snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
31 }
33 #undef unix
35 int
36 p9announce(char *addr, char *dir)
37 {
38 int proto;
39 char *buf, *unix;
40 char *net;
41 u32int host;
42 int port, s;
43 int n, sn;
44 struct sockaddr_in sa;
45 struct sockaddr_un sun;
47 buf = strdup(addr);
48 if(buf == nil)
49 return -1;
51 if(_p9dialparse(buf, &net, &unix, &host, &port) < 0){
52 free(buf);
53 return -1;
54 }
55 if(strcmp(net, "tcp") == 0)
56 proto = SOCK_STREAM;
57 else if(strcmp(net, "udp") == 0)
58 proto = SOCK_DGRAM;
59 else if(strcmp(net, "unix") == 0)
60 goto Unix;
61 else{
62 werrstr("can only handle tcp, udp, and unix: not %s", net);
63 free(buf);
64 return -1;
65 }
66 free(buf);
68 memset(&sa, 0, sizeof sa);
69 memmove(&sa.sin_addr, &host, 4);
70 sa.sin_family = AF_INET;
71 sa.sin_port = htons(port);
72 if((s = socket(AF_INET, proto, 0)) < 0)
73 return -1;
74 sn = sizeof n;
75 if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&n, &sn) >= 0
76 && n == SOCK_STREAM){
77 n = 1;
78 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
79 }
80 if(bind(s, (struct sockaddr*)&sa, sizeof sa) < 0){
81 close(s);
82 return -1;
83 }
84 if(proto == SOCK_STREAM){
85 listen(s, 8);
86 putfd(dir, s);
87 }
88 return s;
90 Unix:
91 memset(&sun, 0, sizeof sun);
92 sun.sun_family = AF_UNIX;
93 strcpy(sun.sun_path, unix);
94 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
95 return -1;
96 sn = sizeof sun;
97 if(bind(s, (struct sockaddr*)&sun, sizeof sun) < 0){
98 if(errno == EADDRINUSE
99 && connect(s, (struct sockaddr*)&sun, sizeof sun) < 0
100 && errno == ECONNREFUSED){
101 /* dead socket, so remove it */
102 remove(unix);
103 close(s);
104 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
105 return -1;
106 if(bind(s, (struct sockaddr*)&sun, sizeof sun) >= 0)
107 goto Success;
109 close(s);
110 return -1;
112 Success:
113 listen(s, 8);
114 putfd(dir, s);
115 return s;
118 int
119 p9listen(char *dir, char *newdir)
121 int fd;
123 if((fd = _p9netfd(dir)) < 0){
124 werrstr("bad 'directory' in listen: %s", dir);
125 return -1;
128 if((fd = accept(fd, nil, nil)) < 0)
129 return -1;
131 putfd(newdir, fd);
132 return fd;
135 int
136 p9accept(int cfd, char *dir)
138 int fd;
140 if((fd = _p9netfd(dir)) < 0){
141 werrstr("bad 'directory' in accept");
142 return -1;
144 /* need to dup because the listen fd will be closed */
145 return dup(fd);