Blob


1 #include <u.h>
2 #define NOPLAN9DEFINES
3 #include <libc.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <netinet/tcp.h>
8 #include <sys/un.h>
9 #include <errno.h>
11 #undef sun
12 #define sun sockun
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;
44 socklen_t sn;
45 struct sockaddr_in sa;
46 struct sockaddr_un sun;
48 buf = strdup(addr);
49 if(buf == nil)
50 return -1;
52 if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
53 free(buf);
54 return -1;
55 }
56 if(strcmp(net, "tcp") == 0)
57 proto = SOCK_STREAM;
58 else if(strcmp(net, "udp") == 0)
59 proto = SOCK_DGRAM;
60 else if(strcmp(net, "unix") == 0)
61 goto Unix;
62 else{
63 werrstr("can only handle tcp, udp, and unix: not %s", net);
64 free(buf);
65 return -1;
66 }
67 free(buf);
69 memset(&sa, 0, sizeof sa);
70 memmove(&sa.sin_addr, &host, 4);
71 sa.sin_family = AF_INET;
72 sa.sin_port = htons(port);
73 if((s = socket(AF_INET, proto, 0)) < 0)
74 return -1;
75 sn = sizeof n;
76 if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
77 && n == SOCK_STREAM){
78 n = 1;
79 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
80 }
81 if(bind(s, (struct sockaddr*)&sa, sizeof sa) < 0){
82 close(s);
83 return -1;
84 }
85 if(proto == SOCK_STREAM){
86 listen(s, 8);
87 putfd(dir, s);
88 }
89 return s;
91 Unix:
92 memset(&sun, 0, sizeof sun);
93 sun.sun_family = AF_UNIX;
94 strcpy(sun.sun_path, unix);
95 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
96 return -1;
97 sn = sizeof sun;
98 if(bind(s, (struct sockaddr*)&sun, sizeof sun) < 0){
99 if(errno == EADDRINUSE
100 && connect(s, (struct sockaddr*)&sun, sizeof sun) < 0
101 && errno == ECONNREFUSED){
102 /* dead socket, so remove it */
103 remove(unix);
104 close(s);
105 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
106 return -1;
107 if(bind(s, (struct sockaddr*)&sun, sizeof sun) >= 0)
108 goto Success;
110 close(s);
111 return -1;
113 Success:
114 listen(s, 8);
115 putfd(dir, s);
116 return s;
119 int
120 p9listen(char *dir, char *newdir)
122 int fd, one;
124 if((fd = _p9netfd(dir)) < 0){
125 werrstr("bad 'directory' in listen: %s", dir);
126 return -1;
129 if((fd = accept(fd, nil, nil)) < 0)
130 return -1;
132 one = 1;
133 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
135 putfd(newdir, fd);
136 return fd;
139 int
140 p9accept(int cfd, char *dir)
142 int fd;
144 if((fd = _p9netfd(dir)) < 0){
145 werrstr("bad 'directory' in accept");
146 return -1;
148 /* need to dup because the listen fd will be closed */
149 return dup(fd);