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