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