1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4
5 static int nettrans(char*, char*, int na, char*, int);
6
7 enum
8 {
9 Maxpath= 256,
10 };
11
12 /*
13 * announce a network service.
14 */
15 int
announce(char * addr,char * dir)16 announce(char *addr, char *dir)
17 {
18 int ctl, n, m;
19 char buf[Maxpath];
20 char buf2[Maxpath];
21 char netdir[Maxpath];
22 char naddr[Maxpath];
23 char *cp;
24
25 /*
26 * translate the address
27 */
28 if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
29 return -1;
30
31 /*
32 * get a control channel
33 */
34 ctl = open(netdir, ORDWR);
35 if(ctl<0){
36 werrstr("announce opening %s: %r", netdir);
37 return -1;
38 }
39 cp = strrchr(netdir, '/');
40 if(cp == nil){
41 werrstr("announce arg format %s", netdir);
42 close(ctl);
43 return -1;
44 }
45 *cp = 0;
46
47 /*
48 * find out which line we have
49 */
50 n = snprint(buf, sizeof(buf), "%s/", netdir);
51 m = read(ctl, &buf[n], sizeof(buf)-n-1);
52 if(m <= 0){
53 werrstr("announce reading %s: %r", netdir);
54 close(ctl);
55 return -1;
56 }
57 buf[n+m] = 0;
58
59 /*
60 * make the call
61 */
62 n = snprint(buf2, sizeof(buf2), "announce %s", naddr);
63 if(write(ctl, buf2, n)!=n){
64 werrstr("announce writing %s: %r", netdir);
65 close(ctl);
66 return -1;
67 }
68
69 /*
70 * return directory etc.
71 */
72 if(dir){
73 strncpy(dir, buf, NETPATHLEN);
74 dir[NETPATHLEN-1] = 0;
75 }
76 return ctl;
77 }
78
79 /*
80 * listen for an incoming call
81 */
82 int
listen(char * dir,char * newdir)83 listen(char *dir, char *newdir)
84 {
85 int ctl, n, m;
86 char buf[Maxpath];
87 char *cp;
88
89 /*
90 * open listen, wait for a call
91 */
92 snprint(buf, sizeof(buf), "%s/listen", dir);
93 ctl = open(buf, ORDWR);
94 if(ctl < 0){
95 werrstr("listen opening %s: %r", buf);
96 return -1;
97 }
98
99 /*
100 * find out which line we have
101 */
102 strncpy(buf, dir, sizeof(buf) - 1);
103 buf[sizeof(buf) - 1] = 0;
104 cp = strrchr(buf, '/');
105 if(cp == nil){
106 close(ctl);
107 werrstr("listen arg format %s", dir);
108 return -1;
109 }
110 *++cp = 0;
111 n = cp-buf;
112 m = read(ctl, cp, sizeof(buf) - n - 1);
113 if(m <= 0){
114 close(ctl);
115 werrstr("listen reading %s/listen: %r", dir);
116 return -1;
117 }
118 buf[n+m] = 0;
119
120 /*
121 * return directory etc.
122 */
123 if(newdir){
124 strncpy(newdir, buf, NETPATHLEN);
125 newdir[NETPATHLEN-1] = 0;
126 }
127 return ctl;
128
129 }
130
131 /*
132 * accept a call, return an fd to the open data file
133 */
134 int
accept(int ctl,char * dir)135 accept(int ctl, char *dir)
136 {
137 char buf[Maxpath];
138 char *num;
139 long n;
140
141 num = strrchr(dir, '/');
142 if(num == nil)
143 num = dir;
144 else
145 num++;
146
147 n = snprint(buf, sizeof(buf), "accept %s", num);
148 write(ctl, buf, n); /* ignore return value, network might not need accepts */
149
150 snprint(buf, sizeof(buf), "%s/data", dir);
151 return open(buf, ORDWR);
152 }
153
154 /*
155 * reject a call, tell device the reason for the rejection
156 */
157 int
reject(int ctl,char * dir,char * cause)158 reject(int ctl, char *dir, char *cause)
159 {
160 char buf[Maxpath];
161 char *num;
162 long n;
163
164 num = strrchr(dir, '/');
165 if(num == 0)
166 num = dir;
167 else
168 num++;
169 snprint(buf, sizeof(buf), "reject %s %s", num, cause);
170 n = strlen(buf);
171 if(write(ctl, buf, n) != n)
172 return -1;
173 return 0;
174 }
175
176 /*
177 * perform the identity translation (in case we can't reach cs)
178 */
179 static int
identtrans(char * netdir,char * addr,char * naddr,int na,char * file,int nf)180 identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf)
181 {
182 char proto[Maxpath];
183 char *p;
184
185 USED(nf);
186
187 /* parse the protocol */
188 strncpy(proto, addr, sizeof(proto));
189 proto[sizeof(proto)-1] = 0;
190 p = strchr(proto, '!');
191 if(p)
192 *p++ = 0;
193
194 snprint(file, nf, "%s/%s/clone", netdir, proto);
195 strncpy(naddr, p, na);
196 naddr[na-1] = 0;
197
198 return 1;
199 }
200
201 /*
202 * call up the connection server and get a translation
203 */
204 static int
nettrans(char * addr,char * naddr,int na,char * file,int nf)205 nettrans(char *addr, char *naddr, int na, char *file, int nf)
206 {
207 int i, fd;
208 char buf[Maxpath];
209 char netdir[Maxpath];
210 char *p, *p2;
211 long n;
212
213 /*
214 * parse, get network directory
215 */
216 p = strchr(addr, '!');
217 if(p == 0){
218 werrstr("bad dial string: %s", addr);
219 return -1;
220 }
221 if(*addr != '/'){
222 strncpy(netdir, "/net", sizeof(netdir));
223 netdir[sizeof(netdir) - 1] = 0;
224 } else {
225 for(p2 = p; *p2 != '/'; p2--)
226 ;
227 i = p2 - addr;
228 if(i == 0 || i >= sizeof(netdir)){
229 werrstr("bad dial string: %s", addr);
230 return -1;
231 }
232 strncpy(netdir, addr, i);
233 netdir[i] = 0;
234 addr = p2 + 1;
235 }
236
237 /*
238 * ask the connection server
239 */
240 snprint(buf, sizeof(buf), "%s/cs", netdir);
241 fd = open(buf, ORDWR);
242 if(fd < 0)
243 return identtrans(netdir, addr, naddr, na, file, nf);
244 if(write(fd, addr, strlen(addr)) < 0){
245 close(fd);
246 return -1;
247 }
248 seek(fd, 0, 0);
249 n = read(fd, buf, sizeof(buf)-1);
250 close(fd);
251 if(n <= 0)
252 return -1;
253 buf[n] = 0;
254
255 /*
256 * parse the reply
257 */
258 p = strchr(buf, ' ');
259 if(p == 0)
260 return -1;
261 *p++ = 0;
262 strncpy(naddr, p, na);
263 naddr[na-1] = 0;
264
265 if(buf[0] == '/'){
266 p = strchr(buf+1, '/');
267 if(p == nil)
268 p = buf;
269 else
270 p++;
271 }
272 snprint(file, nf, "%s/%s", netdir, p);
273 return 0;
274 }
275