xref: /plan9/sys/src/libc/9sys/announce.c (revision da51d93a95fd527106ceeb0537961de9ab01e9ec)
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