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
34 #define unix sockunix
36 int
37 p9announce(char *addr, char *dir)
38 {
39 int proto;
40 char *buf, *unix;
41 char *net;
42 u32int host;
43 int port, s;
44 int n;
45 socklen_t sn;
46 struct sockaddr_in sa;
47 struct sockaddr_un sun;
49 buf = strdup(addr);
50 if(buf == nil)
51 return -1;
53 if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
54 free(buf);
55 return -1;
56 }
57 if(strcmp(net, "tcp") == 0)
58 proto = SOCK_STREAM;
59 else if(strcmp(net, "udp") == 0)
60 proto = SOCK_DGRAM;
61 else if(strcmp(net, "unix") == 0)
62 goto Unix;
63 else{
64 werrstr("can only handle tcp, udp, and unix: not %s", net);
65 free(buf);
66 return -1;
67 }
68 free(buf);
70 memset(&sa, 0, sizeof sa);
71 memmove(&sa.sin_addr, &host, 4);
72 sa.sin_family = AF_INET;
73 sa.sin_port = htons(port);
74 if((s = socket(AF_INET, proto, 0)) < 0)
75 return -1;
76 sn = sizeof n;
77 if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
78 && n == SOCK_STREAM){
79 n = 1;
80 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
81 }
82 if(bind(s, (struct sockaddr*)&sa, sizeof sa) < 0){
83 close(s);
84 return -1;
85 }
86 if(proto == SOCK_STREAM){
87 listen(s, 8);
88 putfd(dir, s);
89 }
90 return s;
92 Unix:
93 memset(&sun, 0, sizeof sun);
94 sun.sun_family = AF_UNIX;
95 strcpy(sun.sun_path, unix);
96 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
97 return -1;
98 sn = sizeof sun;
99 if(bind(s, (struct sockaddr*)&sun, sizeof sun) < 0){
100 if(errno == EADDRINUSE
101 && connect(s, (struct sockaddr*)&sun, sizeof sun) < 0
102 && errno == ECONNREFUSED){
103 /* dead socket, so remove it */
104 remove(unix);
105 close(s);
106 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
107 return -1;
108 if(bind(s, (struct sockaddr*)&sun, sizeof sun) >= 0)
109 goto Success;
111 close(s);
112 return -1;
114 Success:
115 listen(s, 8);
116 putfd(dir, s);
117 return s;
120 int
121 p9listen(char *dir, char *newdir)
123 int fd, one;
125 if((fd = _p9netfd(dir)) < 0){
126 werrstr("bad 'directory' in listen: %s", dir);
127 return -1;
130 if((fd = accept(fd, nil, nil)) < 0)
131 return -1;
133 one = 1;
134 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
136 putfd(newdir, fd);
137 return fd;
140 int
141 p9accept(int cfd, char *dir)
143 int fd;
145 if((fd = _p9netfd(dir)) < 0){
146 werrstr("bad 'directory' in accept");
147 return -1;
149 /* need to dup because the listen fd will be closed */
150 return dup(fd);