xref: /plan9/sys/src/libventi/client.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include <u.h>
2 #include <libc.h>
3 #include <venti.h>
4 #include "session.h"
5 
6 static char EProtocolBotch[] = "venti protocol botch";
7 static char ELumpSize[] = "illegal lump size";
8 static char ENotConnected[] = "not connected to venti server";
9 
10 static Packet *vtRPC(VtSession *z, int op, Packet *p);
11 
12 VtSession *
13 vtClientAlloc(void)
14 {
15 	VtSession *z = vtAlloc();
16 	return z;
17 }
18 
19 VtSession *
20 vtDial(char *host, int canfail)
21 {
22 	VtSession *z;
23 	int fd;
24 	char *na;
25 	char e[ERRMAX];
26 
27 	if(host == nil)
28 		host = getenv("venti");
29 	if(host == nil)
30 		host = "$venti";
31 
32 	na = netmkaddr(host, 0, "venti");
33 	fd = dial(na, 0, 0, 0);
34 	if(fd < 0){
35 		rerrstr(e, sizeof e);
36 		if(!canfail){
37 			vtSetError("%s", e);
38 			return nil;
39 		}
40 	}
41 	z = vtClientAlloc();
42 	if(fd < 0)
43 		strcpy(z->fderror, e);
44 	vtSetFd(z, fd);
45 	return z;
46 }
47 
48 int
49 vtRedial(VtSession *z, char *host)
50 {
51 	int fd;
52 	char *na;
53 
54 	if(host == nil)
55 		host = getenv("venti");
56 	if(host == nil)
57 		host = "$venti";
58 
59 	na = netmkaddr(host, 0, "venti");
60 	fd = dial(na, 0, 0, 0);
61 	if(fd < 0){
62 		vtOSError();
63 		return 0;
64 	}
65 	vtReset(z);
66 	vtSetFd(z, fd);
67 	return 1;
68 }
69 
70 VtSession *
71 vtStdioServer(char *server)
72 {
73 	int pfd[2];
74 	VtSession *z;
75 
76 	if(server == nil)
77 		return nil;
78 
79 	if(access(server, AEXEC) < 0) {
80 		vtOSError();
81 		return nil;
82 	}
83 
84 	if(pipe(pfd) < 0) {
85 		vtOSError();
86 		return nil;
87 	}
88 
89 	switch(fork()) {
90 	case -1:
91 		close(pfd[0]);
92 		close(pfd[1]);
93 		vtOSError();
94 		return nil;
95 	case 0:
96 		close(pfd[0]);
97 		dup(pfd[1], 0);
98 		dup(pfd[1], 1);
99 		execl(server, "ventiserver", "-i", 0);
100 		exits("exec failed");
101 	}
102 	close(pfd[1]);
103 
104 	z = vtClientAlloc();
105 	vtSetFd(z, pfd[0]);
106 	return z;
107 }
108 
109 int
110 vtPing(VtSession *z)
111 {
112 	Packet *p = packetAlloc();
113 
114 	p = vtRPC(z, VtQPing, p);
115 	if(p == nil)
116 		return 0;
117 	packetFree(p);
118 	return 1;
119 }
120 
121 int
122 vtHello(VtSession *z)
123 {
124 	Packet *p;
125 	uchar buf[10];
126 	char *sid;
127 	int crypto, codec;
128 
129 	sid = nil;
130 
131 	p = packetAlloc();
132 	if(!vtAddString(p, vtGetVersion(z)))
133 		goto Err;
134 	if(!vtAddString(p, vtGetUid(z)))
135 		goto Err;
136 	buf[0] = vtGetCryptoStrength(z);
137 	buf[1] = 0;
138 	buf[2] = 0;
139 	packetAppend(p, buf, 3);
140 	p = vtRPC(z, VtQHello, p);
141 	if(p == nil)
142 		return 0;
143 	if(!vtGetString(p, &sid))
144 		goto Err;
145 	if(!packetConsume(p, buf, 2))
146 		goto Err;
147 	if(packetSize(p) != 0) {
148 		vtSetError(EProtocolBotch);
149 		goto Err;
150 	}
151 	crypto = buf[0];
152 	codec = buf[1];
153 
154 	USED(crypto);
155 	USED(codec);
156 
157 	packetFree(p);
158 
159 	vtLock(z->lk);
160 	z->sid = sid;
161 	z->auth.state = VtAuthOK;
162 	vtSha1Free(z->inHash);
163 	z->inHash = nil;
164 	vtSha1Free(z->outHash);
165 	z->outHash = nil;
166 	vtUnlock(z->lk);
167 
168 	return 1;
169 Err:
170 	packetFree(p);
171 	vtMemFree(sid);
172 	return 0;
173 }
174 
175 int
176 vtSync(VtSession *z)
177 {
178 	Packet *p = packetAlloc();
179 
180 	p = vtRPC(z, VtQSync, p);
181 	if(p == nil)
182 		return 0;
183 	if(packetSize(p) != 0){
184 		vtSetError(EProtocolBotch);
185 		goto Err;
186 	}
187 	packetFree(p);
188 	return 1;
189 
190 Err:
191 	packetFree(p);
192 	return 0;
193 }
194 
195 int
196 vtWrite(VtSession *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
197 {
198 	Packet *p = packetAlloc();
199 
200 	packetAppend(p, buf, n);
201 	return vtWritePacket(z, score, type, p);
202 }
203 
204 int
205 vtWritePacket(VtSession *z, uchar score[VtScoreSize], int type, Packet *p)
206 {
207 	int n = packetSize(p);
208 	uchar *hdr;
209 
210 	if(n > VtMaxLumpSize || n < 0) {
211 		vtSetError(ELumpSize);
212 		goto Err;
213 	}
214 
215 	if(n == 0) {
216 		memmove(score, vtZeroScore, VtScoreSize);
217 		return 1;
218 	}
219 
220 	hdr = packetHeader(p, 4);
221 	hdr[0] = type;
222 	hdr[1] = 0;	/* pad */
223 	hdr[2] = 0;	/* pad */
224 	hdr[3] = 0;	/* pad */
225 	p = vtRPC(z, VtQWrite, p);
226 	if(p == nil)
227 		return 0;
228 	if(!packetConsume(p, score, VtScoreSize))
229 		goto Err;
230 	if(packetSize(p) != 0) {
231 		vtSetError(EProtocolBotch);
232 		goto Err;
233 	}
234 	packetFree(p);
235 	return 1;
236 Err:
237 	packetFree(p);
238 	return 0;
239 }
240 
241 int
242 vtRead(VtSession *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
243 {
244 	Packet *p;
245 
246 	p = vtReadPacket(z, score, type, n);
247 	if(p == nil)
248 		return -1;
249 	n = packetSize(p);
250 	packetCopy(p, buf, 0, n);
251 	packetFree(p);
252 	return n;
253 }
254 
255 Packet *
256 vtReadPacket(VtSession *z, uchar score[VtScoreSize], int type, int n)
257 {
258 	Packet *p;
259 	uchar buf[10];
260 
261 	if(n < 0 || n > VtMaxLumpSize) {
262 		vtSetError(ELumpSize);
263 		return nil;
264 	}
265 
266 	p = packetAlloc();
267 	if(memcmp(score, vtZeroScore, VtScoreSize) == 0)
268 		return p;
269 
270 	packetAppend(p, score, VtScoreSize);
271 	buf[0] = type;
272 	buf[1] = 0;	/* pad */
273 	buf[2] = n >> 8;
274 	buf[3] = n;
275 	packetAppend(p, buf, 4);
276 	return vtRPC(z, VtQRead, p);
277 }
278 
279 
280 static Packet *
281 vtRPC(VtSession *z, int op, Packet *p)
282 {
283 	uchar *hdr, buf[2];
284 	char *err;
285 
286 	if(z == nil){
287 		vtSetError(ENotConnected);
288 		return nil;
289 	}
290 
291 	/*
292 	 * single threaded for the momment
293 	 */
294 	vtLock(z->lk);
295 	if(z->cstate != VtStateConnected){
296 		vtSetError(ENotConnected);
297 		goto Err;
298 	}
299 	hdr = packetHeader(p, 2);
300 	hdr[0] = op;	/* op */
301 	hdr[1] = 0;	/* tid */
302 	vtDebug(z, "client send: ");
303 	vtDebugMesg(z, p, "\n");
304 	if(!vtSendPacket(z, p)) {
305 		p = nil;
306 		goto Err;
307 	}
308 	p = vtRecvPacket(z);
309 	if(p == nil)
310 		goto Err;
311 	vtDebug(z, "client recv: ");
312 	vtDebugMesg(z, p, "\n");
313 	if(!packetConsume(p, buf, 2))
314 		goto Err;
315 	if(buf[0] == VtRError) {
316 		if(!vtGetString(p, &err)) {
317 			vtSetError(EProtocolBotch);
318 			goto Err;
319 		}
320 		vtSetError(err);
321 		vtMemFree(err);
322 		packetFree(p);
323 		vtUnlock(z->lk);
324 		return nil;
325 	}
326 	if(buf[0] != op+1 || buf[1] != 0) {
327 		vtSetError(EProtocolBotch);
328 		goto Err;
329 	}
330 	vtUnlock(z->lk);
331 	return p;
332 Err:
333 	vtDebug(z, "vtRPC failed: %s\n", vtGetError());
334 	if(p != nil)
335 		packetFree(p);
336 	vtUnlock(z->lk);
337 	vtDisconnect(z, 1);
338 	return nil;
339 }
340