xref: /plan9/sys/src/cmd/unix/drawterm/libc/dial.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include <u.h>
2 #include <libc.h>
3 
4 typedef struct DS DS;
5 
6 static int	call(char*, char*, DS*);
7 static int	csdial(DS*);
8 static void	_dial_string_parse(char*, DS*);
9 
10 enum
11 {
12 	Maxstring	= 128,
13 	Maxpath		= 256,
14 };
15 
16 struct DS {
17 	/* dist string */
18 	char	buf[Maxstring];
19 	char	*netdir;
20 	char	*proto;
21 	char	*rem;
22 
23 	/* other args */
24 	char	*local;
25 	char	*dir;
26 	int	*cfdp;
27 };
28 
29 
30 /*
31  *  the dialstring is of the form '[/net/]proto!dest'
32  */
33 int
dial(char * dest,char * local,char * dir,int * cfdp)34 dial(char *dest, char *local, char *dir, int *cfdp)
35 {
36 	DS ds;
37 	int rv;
38 	char err[ERRMAX], alterr[ERRMAX];
39 
40 	ds.local = local;
41 	ds.dir = dir;
42 	ds.cfdp = cfdp;
43 
44 	_dial_string_parse(dest, &ds);
45 	if(ds.netdir)
46 		return csdial(&ds);
47 
48 	ds.netdir = "/net";
49 	rv = csdial(&ds);
50 	if(rv >= 0)
51 		return rv;
52 	err[0] = '\0';
53 	errstr(err, sizeof err);
54 	if(strstr(err, "refused") != 0){
55 		werrstr("%s", err);
56 		return rv;
57 	}
58 	ds.netdir = "/net.alt";
59 	rv = csdial(&ds);
60 	if(rv >= 0)
61 		return rv;
62 
63 	alterr[0] = 0;
64 	errstr(alterr, sizeof alterr);
65 	if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
66 		werrstr("%s", err);
67 	else
68 		werrstr("%s", alterr);
69 	return rv;
70 }
71 
72 static int
csdial(DS * ds)73 csdial(DS *ds)
74 {
75 	int n, fd, rv;
76 	char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
77 
78 	/*
79 	 *  open connection server
80 	 */
81 	snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
82 	fd = open(buf, ORDWR);
83 	if(fd < 0){
84 		/* no connection server, don't translate */
85 		snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
86 		return call(clone, ds->rem, ds);
87 	}
88 
89 	/*
90 	 *  ask connection server to translate
91 	 */
92 	snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
93 	if(write(fd, buf, strlen(buf)) < 0){
94 		close(fd);
95 		return -1;
96 	}
97 
98 	/*
99 	 *  loop through each address from the connection server till
100 	 *  we get one that works.
101 	 */
102 	*besterr = 0;
103 	rv = -1;
104 	seek(fd, 0, 0);
105 	strcpy(err, "cs gave empty translation list");
106 	while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
107 		buf[n] = 0;
108 		p = strchr(buf, ' ');
109 		if(p == 0)
110 			continue;
111 		*p++ = 0;
112 		rv = call(buf, p, ds);
113 		if(rv >= 0)
114 			break;
115 		err[0] = '\0';
116 		errstr(err, sizeof err);
117 		if(strstr(err, "does not exist") == 0)
118 			strcpy(besterr, err);
119 	}
120 	close(fd);
121 
122 	if(rv < 0 && *besterr)
123 		werrstr("%s", besterr);
124 	else
125 		werrstr("%s", err);
126 	return rv;
127 }
128 
129 static int
call(char * clone,char * dest,DS * ds)130 call(char *clone, char *dest, DS *ds)
131 {
132 	int fd, cfd, n;
133 	char name[Maxpath], data[Maxpath], *p;
134 
135 	cfd = open(clone, ORDWR);
136 	if(cfd < 0)
137 		return -1;
138 
139 	/* get directory name */
140 	n = read(cfd, name, sizeof(name)-1);
141 	if(n < 0){
142 		close(cfd);
143 		return -1;
144 	}
145 	name[n] = 0;
146 	for(p = name; *p == ' '; p++)
147 		;
148 	snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
149 	p = strrchr(clone, '/');
150 	*p = 0;
151 	if(ds->dir)
152 		snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name);
153 	snprint(data, sizeof(data), "%s/%s/data", clone, name);
154 
155 	/* connect */
156 	if(ds->local)
157 		snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
158 	else
159 		snprint(name, sizeof(name), "connect %s", dest);
160 	if(write(cfd, name, strlen(name)) < 0){
161 		close(cfd);
162 		return -1;
163 	}
164 
165 	/* open data connection */
166 	fd = open(data, ORDWR);
167 	if(fd < 0){
168 print("open %s: %r\n", data);
169 		close(cfd);
170 		return -1;
171 	}
172 	if(ds->cfdp)
173 		*ds->cfdp = cfd;
174 	else
175 		close(cfd);
176 	return fd;
177 }
178 
179 /*
180  *  parse a dial string
181  */
182 static void
_dial_string_parse(char * str,DS * ds)183 _dial_string_parse(char *str, DS *ds)
184 {
185 	char *p, *p2;
186 
187 	strncpy(ds->buf, str, Maxstring);
188 	ds->buf[Maxstring-1] = 0;
189 
190 	p = strchr(ds->buf, '!');
191 	if(p == 0) {
192 		ds->netdir = 0;
193 		ds->proto = "net";
194 		ds->rem = ds->buf;
195 	} else {
196 		if(*ds->buf != '/' && *ds->buf != '#'){
197 			ds->netdir = 0;
198 			ds->proto = ds->buf;
199 		} else {
200 			for(p2 = p; *p2 != '/'; p2--)
201 				;
202 			*p2++ = 0;
203 			ds->netdir = ds->buf;
204 			ds->proto = p2;
205 		}
206 		*p = 0;
207 		ds->rem = p + 1;
208 	}
209 }
210