announce.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
announce.c (2724B) | |
--- | |
1 #include <u.h> | |
2 #define NOPLAN9DEFINES | |
3 #include <libc.h> | |
4 | |
5 #include <sys/socket.h> | |
6 #include <netinet/in.h> | |
7 #include <netinet/tcp.h> | |
8 #include <sys/un.h> | |
9 #include <errno.h> | |
10 | |
11 #undef sun | |
12 #define sun sockun | |
13 | |
14 int | |
15 _p9netfd(char *dir) | |
16 { | |
17 int fd; | |
18 | |
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 } | |
26 | |
27 static void | |
28 putfd(char *dir, int fd) | |
29 { | |
30 snprint(dir, NETPATHLEN, "/dev/fd/%d", fd); | |
31 } | |
32 | |
33 #undef unix | |
34 #define unix sockunix | |
35 | |
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; | |
48 | |
49 buf = strdup(addr); | |
50 if(buf == nil) | |
51 return -1; | |
52 | |
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", ne… | |
65 free(buf); | |
66 return -1; | |
67 } | |
68 free(buf); | |
69 | |
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) >=… | |
78 && n == SOCK_STREAM){ | |
79 n = 1; | |
80 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeo… | |
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; | |
91 | |
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) >… | |
109 goto Success; | |
110 } | |
111 close(s); | |
112 return -1; | |
113 } | |
114 Success: | |
115 listen(s, 8); | |
116 putfd(dir, s); | |
117 return s; | |
118 } | |
119 | |
120 int | |
121 p9listen(char *dir, char *newdir) | |
122 { | |
123 int fd, one; | |
124 | |
125 if((fd = _p9netfd(dir)) < 0){ | |
126 werrstr("bad 'directory' in listen: %s", dir); | |
127 return -1; | |
128 } | |
129 | |
130 if((fd = accept(fd, nil, nil)) < 0) | |
131 return -1; | |
132 | |
133 one = 1; | |
134 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one… | |
135 | |
136 putfd(newdir, fd); | |
137 return fd; | |
138 } | |
139 | |
140 int | |
141 p9accept(int cfd, char *dir) | |
142 { | |
143 int fd; | |
144 | |
145 if((fd = _p9netfd(dir)) < 0){ | |
146 werrstr("bad 'directory' in accept"); | |
147 return -1; | |
148 } | |
149 /* need to dup because the listen fd will be closed */ | |
150 return dup(fd); | |
151 } | |
152 |