xref: /plan9/sys/src/liboventi/rpc.c (revision 225077b0bf393489f69f6689df234a9b945497b7)
1368c31abSDavid du Colombier #include <u.h>
2368c31abSDavid du Colombier #include <libc.h>
3368c31abSDavid du Colombier #include <oventi.h>
4368c31abSDavid du Colombier #include "session.h"
5368c31abSDavid du Colombier 
6368c31abSDavid du Colombier struct {
7368c31abSDavid du Colombier 	int version;
8368c31abSDavid du Colombier 	char *s;
9368c31abSDavid du Colombier } vtVersions[] = {
10368c31abSDavid du Colombier 	VtVersion02, "02",
11368c31abSDavid du Colombier 	0, 0,
12368c31abSDavid du Colombier };
13368c31abSDavid du Colombier 
14368c31abSDavid du Colombier static char EBigString[] = "string too long";
15368c31abSDavid du Colombier static char EBigPacket[] = "packet too long";
16368c31abSDavid du Colombier static char ENullString[] = "missing string";
17368c31abSDavid du Colombier static char EBadVersion[] = "bad format in version string";
18368c31abSDavid du Colombier 
19368c31abSDavid du Colombier static Packet *vtRPC(VtSession *z, int op, Packet *p);
20368c31abSDavid du Colombier 
21368c31abSDavid du Colombier 
22368c31abSDavid du Colombier VtSession *
vtAlloc(void)23368c31abSDavid du Colombier vtAlloc(void)
24368c31abSDavid du Colombier {
25368c31abSDavid du Colombier 	VtSession *z;
26368c31abSDavid du Colombier 
27368c31abSDavid du Colombier 	z = vtMemAllocZ(sizeof(VtSession));
28368c31abSDavid du Colombier 	z->lk = vtLockAlloc();
29368c31abSDavid du Colombier //	z->inHash = vtSha1Alloc();
30368c31abSDavid du Colombier 	z->inLock = vtLockAlloc();
31368c31abSDavid du Colombier 	z->part = packetAlloc();
32368c31abSDavid du Colombier //	z->outHash = vtSha1Alloc();
33368c31abSDavid du Colombier 	z->outLock = vtLockAlloc();
34368c31abSDavid du Colombier 	z->fd = -1;
35368c31abSDavid du Colombier 	z->uid = vtStrDup("anonymous");
36368c31abSDavid du Colombier 	z->sid = vtStrDup("anonymous");
37368c31abSDavid du Colombier 	return z;
38368c31abSDavid du Colombier }
39368c31abSDavid du Colombier 
40368c31abSDavid du Colombier void
vtReset(VtSession * z)41368c31abSDavid du Colombier vtReset(VtSession *z)
42368c31abSDavid du Colombier {
43368c31abSDavid du Colombier 	vtLock(z->lk);
44368c31abSDavid du Colombier 	z->cstate = VtStateAlloc;
45368c31abSDavid du Colombier 	if(z->fd >= 0){
46368c31abSDavid du Colombier 		vtFdClose(z->fd);
47368c31abSDavid du Colombier 		z->fd = -1;
48368c31abSDavid du Colombier 	}
49368c31abSDavid du Colombier 	vtUnlock(z->lk);
50368c31abSDavid du Colombier }
51368c31abSDavid du Colombier 
52368c31abSDavid du Colombier int
vtConnected(VtSession * z)53368c31abSDavid du Colombier vtConnected(VtSession *z)
54368c31abSDavid du Colombier {
55368c31abSDavid du Colombier 	return z->cstate == VtStateConnected;
56368c31abSDavid du Colombier }
57368c31abSDavid du Colombier 
58368c31abSDavid du Colombier void
vtDisconnect(VtSession * z,int error)59368c31abSDavid du Colombier vtDisconnect(VtSession *z, int error)
60368c31abSDavid du Colombier {
61368c31abSDavid du Colombier 	Packet *p;
62368c31abSDavid du Colombier 	uchar *b;
63368c31abSDavid du Colombier 
64368c31abSDavid du Colombier vtDebug(z, "vtDisconnect\n");
65368c31abSDavid du Colombier 	vtLock(z->lk);
66368c31abSDavid du Colombier 	if(z->cstate == VtStateConnected && !error && z->vtbl == nil) {
67368c31abSDavid du Colombier 		/* clean shutdown */
68368c31abSDavid du Colombier 		p = packetAlloc();
69368c31abSDavid du Colombier 		b = packetHeader(p, 2);
70368c31abSDavid du Colombier 		b[0] = VtQGoodbye;
71368c31abSDavid du Colombier 		b[1] = 0;
72368c31abSDavid du Colombier 		vtSendPacket(z, p);
73368c31abSDavid du Colombier 	}
74368c31abSDavid du Colombier 	if(z->fd >= 0)
75368c31abSDavid du Colombier 		vtFdClose(z->fd);
76368c31abSDavid du Colombier 	z->fd = -1;
77368c31abSDavid du Colombier 	z->cstate = VtStateClosed;
78368c31abSDavid du Colombier 	vtUnlock(z->lk);
79368c31abSDavid du Colombier }
80368c31abSDavid du Colombier 
81368c31abSDavid du Colombier void
vtClose(VtSession * z)82368c31abSDavid du Colombier vtClose(VtSession *z)
83368c31abSDavid du Colombier {
84368c31abSDavid du Colombier 	vtDisconnect(z, 0);
85368c31abSDavid du Colombier }
86368c31abSDavid du Colombier 
87368c31abSDavid du Colombier void
vtFree(VtSession * z)88368c31abSDavid du Colombier vtFree(VtSession *z)
89368c31abSDavid du Colombier {
90368c31abSDavid du Colombier 	if(z == nil)
91368c31abSDavid du Colombier 		return;
92368c31abSDavid du Colombier 	vtLockFree(z->lk);
93368c31abSDavid du Colombier 	vtSha1Free(z->inHash);
94368c31abSDavid du Colombier 	vtLockFree(z->inLock);
95368c31abSDavid du Colombier 	packetFree(z->part);
96368c31abSDavid du Colombier 	vtSha1Free(z->outHash);
97368c31abSDavid du Colombier 	vtLockFree(z->outLock);
98368c31abSDavid du Colombier 	vtMemFree(z->uid);
99368c31abSDavid du Colombier 	vtMemFree(z->sid);
100368c31abSDavid du Colombier 	vtMemFree(z->vtbl);
101368c31abSDavid du Colombier 
102368c31abSDavid du Colombier 	memset(z, 0, sizeof(VtSession));
103368c31abSDavid du Colombier 	z->fd = -1;
104368c31abSDavid du Colombier 
105368c31abSDavid du Colombier 	vtMemFree(z);
106368c31abSDavid du Colombier }
107368c31abSDavid du Colombier 
108368c31abSDavid du Colombier char *
vtGetUid(VtSession * s)109368c31abSDavid du Colombier vtGetUid(VtSession *s)
110368c31abSDavid du Colombier {
111368c31abSDavid du Colombier 	return s->uid;
112368c31abSDavid du Colombier }
113368c31abSDavid du Colombier 
114368c31abSDavid du Colombier char *
vtGetSid(VtSession * z)115368c31abSDavid du Colombier vtGetSid(VtSession *z)
116368c31abSDavid du Colombier {
117368c31abSDavid du Colombier 	return z->sid;
118368c31abSDavid du Colombier }
119368c31abSDavid du Colombier 
120368c31abSDavid du Colombier int
vtSetDebug(VtSession * z,int debug)121368c31abSDavid du Colombier vtSetDebug(VtSession *z, int debug)
122368c31abSDavid du Colombier {
123368c31abSDavid du Colombier 	int old;
124368c31abSDavid du Colombier 	vtLock(z->lk);
125368c31abSDavid du Colombier 	old = z->debug;
126368c31abSDavid du Colombier 	z->debug = debug;
127368c31abSDavid du Colombier 	vtUnlock(z->lk);
128368c31abSDavid du Colombier 	return old;
129368c31abSDavid du Colombier }
130368c31abSDavid du Colombier 
131368c31abSDavid du Colombier int
vtSetFd(VtSession * z,int fd)132368c31abSDavid du Colombier vtSetFd(VtSession *z, int fd)
133368c31abSDavid du Colombier {
134368c31abSDavid du Colombier 	vtLock(z->lk);
135368c31abSDavid du Colombier 	if(z->cstate != VtStateAlloc) {
136368c31abSDavid du Colombier 		vtSetError("bad state");
137368c31abSDavid du Colombier 		vtUnlock(z->lk);
138368c31abSDavid du Colombier 		return 0;
139368c31abSDavid du Colombier 	}
140368c31abSDavid du Colombier 	if(z->fd >= 0)
141368c31abSDavid du Colombier 		vtFdClose(z->fd);
142368c31abSDavid du Colombier 	z->fd = fd;
143368c31abSDavid du Colombier 	vtUnlock(z->lk);
144368c31abSDavid du Colombier 	return 1;
145368c31abSDavid du Colombier }
146368c31abSDavid du Colombier 
147368c31abSDavid du Colombier int
vtGetFd(VtSession * z)148368c31abSDavid du Colombier vtGetFd(VtSession *z)
149368c31abSDavid du Colombier {
150368c31abSDavid du Colombier 	return z->fd;
151368c31abSDavid du Colombier }
152368c31abSDavid du Colombier 
153368c31abSDavid du Colombier int
vtSetCryptoStrength(VtSession * z,int c)154368c31abSDavid du Colombier vtSetCryptoStrength(VtSession *z, int c)
155368c31abSDavid du Colombier {
156368c31abSDavid du Colombier 	if(z->cstate != VtStateAlloc) {
157368c31abSDavid du Colombier 		vtSetError("bad state");
158368c31abSDavid du Colombier 		return 0;
159368c31abSDavid du Colombier 	}
160368c31abSDavid du Colombier 	if(c != VtCryptoStrengthNone) {
161368c31abSDavid du Colombier 		vtSetError("not supported yet");
162368c31abSDavid du Colombier 		return 0;
163368c31abSDavid du Colombier 	}
164368c31abSDavid du Colombier 	return 1;
165368c31abSDavid du Colombier }
166368c31abSDavid du Colombier 
167368c31abSDavid du Colombier int
vtGetCryptoStrength(VtSession * s)168368c31abSDavid du Colombier vtGetCryptoStrength(VtSession *s)
169368c31abSDavid du Colombier {
170368c31abSDavid du Colombier 	return s->cryptoStrength;
171368c31abSDavid du Colombier }
172368c31abSDavid du Colombier 
173368c31abSDavid du Colombier int
vtSetCompression(VtSession * z,int fd)174368c31abSDavid du Colombier vtSetCompression(VtSession *z, int fd)
175368c31abSDavid du Colombier {
176368c31abSDavid du Colombier 	vtLock(z->lk);
177368c31abSDavid du Colombier 	if(z->cstate != VtStateAlloc) {
178368c31abSDavid du Colombier 		vtSetError("bad state");
179368c31abSDavid du Colombier 		vtUnlock(z->lk);
180368c31abSDavid du Colombier 		return 0;
181368c31abSDavid du Colombier 	}
182368c31abSDavid du Colombier 	z->fd = fd;
183368c31abSDavid du Colombier 	vtUnlock(z->lk);
184368c31abSDavid du Colombier 	return 1;
185368c31abSDavid du Colombier }
186368c31abSDavid du Colombier 
187368c31abSDavid du Colombier int
vtGetCompression(VtSession * s)188368c31abSDavid du Colombier vtGetCompression(VtSession *s)
189368c31abSDavid du Colombier {
190368c31abSDavid du Colombier 	return s->compression;
191368c31abSDavid du Colombier }
192368c31abSDavid du Colombier 
193368c31abSDavid du Colombier int
vtGetCrypto(VtSession * s)194368c31abSDavid du Colombier vtGetCrypto(VtSession *s)
195368c31abSDavid du Colombier {
196368c31abSDavid du Colombier 	return s->crypto;
197368c31abSDavid du Colombier }
198368c31abSDavid du Colombier 
199368c31abSDavid du Colombier int
vtGetCodec(VtSession * s)200368c31abSDavid du Colombier vtGetCodec(VtSession *s)
201368c31abSDavid du Colombier {
202368c31abSDavid du Colombier 	return s->codec;
203368c31abSDavid du Colombier }
204368c31abSDavid du Colombier 
205368c31abSDavid du Colombier char *
vtGetVersion(VtSession * z)206368c31abSDavid du Colombier vtGetVersion(VtSession *z)
207368c31abSDavid du Colombier {
208368c31abSDavid du Colombier 	int v, i;
209368c31abSDavid du Colombier 
210368c31abSDavid du Colombier 	v = z->version;
211368c31abSDavid du Colombier 	if(v == 0)
212368c31abSDavid du Colombier 		return "unknown";
213368c31abSDavid du Colombier 	for(i=0; vtVersions[i].version; i++)
214368c31abSDavid du Colombier 		if(vtVersions[i].version == v)
215368c31abSDavid du Colombier 			return vtVersions[i].s;
216368c31abSDavid du Colombier 	assert(0);
217368c31abSDavid du Colombier 	return 0;
218368c31abSDavid du Colombier }
219368c31abSDavid du Colombier 
220368c31abSDavid du Colombier /* hold z->inLock */
221368c31abSDavid du Colombier static int
vtVersionRead(VtSession * z,char * prefix,int * ret)222368c31abSDavid du Colombier vtVersionRead(VtSession *z, char *prefix, int *ret)
223368c31abSDavid du Colombier {
224368c31abSDavid du Colombier 	char c;
225368c31abSDavid du Colombier 	char buf[VtMaxStringSize];
226368c31abSDavid du Colombier 	char *q, *p, *pp;
227368c31abSDavid du Colombier 	int i;
228368c31abSDavid du Colombier 
229368c31abSDavid du Colombier 	q = prefix;
230368c31abSDavid du Colombier 	p = buf;
231368c31abSDavid du Colombier 	for(;;) {
232368c31abSDavid du Colombier 		if(p >= buf + sizeof(buf)) {
233368c31abSDavid du Colombier 			vtSetError(EBadVersion);
234368c31abSDavid du Colombier 			return 0;
235368c31abSDavid du Colombier 		}
236368c31abSDavid du Colombier 		if(!vtFdReadFully(z->fd, (uchar*)&c, 1))
237368c31abSDavid du Colombier 			return 0;
238368c31abSDavid du Colombier 		if(z->inHash)
239368c31abSDavid du Colombier 			vtSha1Update(z->inHash, (uchar*)&c, 1);
240368c31abSDavid du Colombier 		if(c == '\n') {
241368c31abSDavid du Colombier 			*p = 0;
242368c31abSDavid du Colombier 			break;
243368c31abSDavid du Colombier 		}
244368c31abSDavid du Colombier 		if(c < ' ' || *q && c != *q) {
245368c31abSDavid du Colombier 			vtSetError(EBadVersion);
246368c31abSDavid du Colombier 			return 0;
247368c31abSDavid du Colombier 		}
248368c31abSDavid du Colombier 		*p++ = c;
249368c31abSDavid du Colombier 		if(*q)
250368c31abSDavid du Colombier 			q++;
251368c31abSDavid du Colombier 	}
252368c31abSDavid du Colombier 
253368c31abSDavid du Colombier 	vtDebug(z, "version string in: %s\n", buf);
254368c31abSDavid du Colombier 
255368c31abSDavid du Colombier 	p = buf + strlen(prefix);
256368c31abSDavid du Colombier 	for(;;) {
257368c31abSDavid du Colombier 		for(pp=p; *pp && *pp != ':'  && *pp != '-'; pp++)
258368c31abSDavid du Colombier 			;
259368c31abSDavid du Colombier 		for(i=0; vtVersions[i].version; i++) {
260368c31abSDavid du Colombier 			if(strlen(vtVersions[i].s) != pp-p)
261368c31abSDavid du Colombier 				continue;
262368c31abSDavid du Colombier 			if(memcmp(vtVersions[i].s, p, pp-p) == 0) {
263368c31abSDavid du Colombier 				*ret = vtVersions[i].version;
264368c31abSDavid du Colombier 				return 1;
265368c31abSDavid du Colombier 			}
266368c31abSDavid du Colombier 		}
267368c31abSDavid du Colombier 		p = pp;
268368c31abSDavid du Colombier 		if(*p != ':')
269368c31abSDavid du Colombier 			return 0;
270368c31abSDavid du Colombier 		p++;
271368c31abSDavid du Colombier 	}
272368c31abSDavid du Colombier }
273368c31abSDavid du Colombier 
274368c31abSDavid du Colombier Packet*
vtRecvPacket(VtSession * z)275368c31abSDavid du Colombier vtRecvPacket(VtSession *z)
276368c31abSDavid du Colombier {
277368c31abSDavid du Colombier 	uchar buf[10], *b;
278368c31abSDavid du Colombier 	int n;
279368c31abSDavid du Colombier 	Packet *p;
280368c31abSDavid du Colombier 	int size, len;
281368c31abSDavid du Colombier 
282368c31abSDavid du Colombier 	if(z->cstate != VtStateConnected) {
283368c31abSDavid du Colombier 		vtSetError("session not connected");
284368c31abSDavid du Colombier 		return 0;
285368c31abSDavid du Colombier 	}
286368c31abSDavid du Colombier 
287368c31abSDavid du Colombier 	vtLock(z->inLock);
288368c31abSDavid du Colombier 	p = z->part;
289368c31abSDavid du Colombier 	/* get enough for head size */
290368c31abSDavid du Colombier 	size = packetSize(p);
291368c31abSDavid du Colombier 	while(size < 2) {
292368c31abSDavid du Colombier 		b = packetTrailer(p, MaxFragSize);
293368c31abSDavid du Colombier 		assert(b != nil);
294368c31abSDavid du Colombier 		n = vtFdRead(z->fd, b, MaxFragSize);
295368c31abSDavid du Colombier 		if(n <= 0)
296368c31abSDavid du Colombier 			goto Err;
297368c31abSDavid du Colombier 		size += n;
298368c31abSDavid du Colombier 		packetTrim(p, 0, size);
299368c31abSDavid du Colombier 	}
300368c31abSDavid du Colombier 
301368c31abSDavid du Colombier 	if(!packetConsume(p, buf, 2))
302368c31abSDavid du Colombier 		goto Err;
303368c31abSDavid du Colombier 	len = (buf[0] << 8) | buf[1];
304368c31abSDavid du Colombier 	size -= 2;
305368c31abSDavid du Colombier 
306368c31abSDavid du Colombier 	while(size < len) {
307368c31abSDavid du Colombier 		n = len - size;
308368c31abSDavid du Colombier 		if(n > MaxFragSize)
309368c31abSDavid du Colombier 			n = MaxFragSize;
310368c31abSDavid du Colombier 		b = packetTrailer(p, n);
311368c31abSDavid du Colombier 		if(!vtFdReadFully(z->fd, b, n))
312368c31abSDavid du Colombier 			goto Err;
313368c31abSDavid du Colombier 		size += n;
314368c31abSDavid du Colombier 	}
315368c31abSDavid du Colombier 	p = packetSplit(p, len);
316368c31abSDavid du Colombier 	vtUnlock(z->inLock);
317368c31abSDavid du Colombier 	return p;
318368c31abSDavid du Colombier Err:
319368c31abSDavid du Colombier 	vtUnlock(z->inLock);
320368c31abSDavid du Colombier 	return nil;
321368c31abSDavid du Colombier }
322368c31abSDavid du Colombier 
323368c31abSDavid du Colombier int
vtSendPacket(VtSession * z,Packet * p)324368c31abSDavid du Colombier vtSendPacket(VtSession *z, Packet *p)
325368c31abSDavid du Colombier {
326368c31abSDavid du Colombier 	IOchunk ioc;
327368c31abSDavid du Colombier 	int n;
328368c31abSDavid du Colombier 	uchar buf[2];
329368c31abSDavid du Colombier 
330368c31abSDavid du Colombier 	/* add framing */
331368c31abSDavid du Colombier 	n = packetSize(p);
332368c31abSDavid du Colombier 	if(n >= (1<<16)) {
333368c31abSDavid du Colombier 		vtSetError(EBigPacket);
334368c31abSDavid du Colombier 		packetFree(p);
335368c31abSDavid du Colombier 		return 0;
336368c31abSDavid du Colombier 	}
337368c31abSDavid du Colombier 	buf[0] = n>>8;
338368c31abSDavid du Colombier 	buf[1] = n;
339368c31abSDavid du Colombier 	packetPrefix(p, buf, 2);
340368c31abSDavid du Colombier 
341368c31abSDavid du Colombier 	for(;;) {
342368c31abSDavid du Colombier 		n = packetFragments(p, &ioc, 1, 0);
343368c31abSDavid du Colombier 		if(n == 0)
344368c31abSDavid du Colombier 			break;
345368c31abSDavid du Colombier 		if(!vtFdWrite(z->fd, ioc.addr, ioc.len)) {
346368c31abSDavid du Colombier 			packetFree(p);
347368c31abSDavid du Colombier 			return 0;
348368c31abSDavid du Colombier 		}
349368c31abSDavid du Colombier 		packetConsume(p, nil, n);
350368c31abSDavid du Colombier 	}
351368c31abSDavid du Colombier 	packetFree(p);
352368c31abSDavid du Colombier 	return 1;
353368c31abSDavid du Colombier }
354368c31abSDavid du Colombier 
355368c31abSDavid du Colombier 
356368c31abSDavid du Colombier int
vtGetString(Packet * p,char ** ret)357368c31abSDavid du Colombier vtGetString(Packet *p, char **ret)
358368c31abSDavid du Colombier {
359368c31abSDavid du Colombier 	uchar buf[2];
360368c31abSDavid du Colombier 	int n;
361368c31abSDavid du Colombier 	char *s;
362368c31abSDavid du Colombier 
363368c31abSDavid du Colombier 	if(!packetConsume(p, buf, 2))
364368c31abSDavid du Colombier 		return 0;
365368c31abSDavid du Colombier 	n = (buf[0]<<8) + buf[1];
366368c31abSDavid du Colombier 	if(n > VtMaxStringSize) {
367368c31abSDavid du Colombier 		vtSetError(EBigString);
368368c31abSDavid du Colombier 		return 0;
369368c31abSDavid du Colombier 	}
370368c31abSDavid du Colombier 	s = vtMemAlloc(n+1);
371*225077b0SDavid du Colombier 	setmalloctag(s, getcallerpc(&p));
372368c31abSDavid du Colombier 	if(!packetConsume(p, (uchar*)s, n)) {
373368c31abSDavid du Colombier 		vtMemFree(s);
374368c31abSDavid du Colombier 		return 0;
375368c31abSDavid du Colombier 	}
376368c31abSDavid du Colombier 	s[n] = 0;
377368c31abSDavid du Colombier 	*ret = s;
378368c31abSDavid du Colombier 	return 1;
379368c31abSDavid du Colombier }
380368c31abSDavid du Colombier 
381368c31abSDavid du Colombier int
vtAddString(Packet * p,char * s)382368c31abSDavid du Colombier vtAddString(Packet *p, char *s)
383368c31abSDavid du Colombier {
384368c31abSDavid du Colombier 	uchar buf[2];
385368c31abSDavid du Colombier 	int n;
386368c31abSDavid du Colombier 
387368c31abSDavid du Colombier 	if(s == nil) {
388368c31abSDavid du Colombier 		vtSetError(ENullString);
389368c31abSDavid du Colombier 		return 0;
390368c31abSDavid du Colombier 	}
391368c31abSDavid du Colombier 	n = strlen(s);
392368c31abSDavid du Colombier 	if(n > VtMaxStringSize) {
393368c31abSDavid du Colombier 		vtSetError(EBigString);
394368c31abSDavid du Colombier 		return 0;
395368c31abSDavid du Colombier 	}
396368c31abSDavid du Colombier 	buf[0] = n>>8;
397368c31abSDavid du Colombier 	buf[1] = n;
398368c31abSDavid du Colombier 	packetAppend(p, buf, 2);
399368c31abSDavid du Colombier 	packetAppend(p, (uchar*)s, n);
400368c31abSDavid du Colombier 	return 1;
401368c31abSDavid du Colombier }
402368c31abSDavid du Colombier 
403368c31abSDavid du Colombier int
vtConnect(VtSession * z,char * password)404368c31abSDavid du Colombier vtConnect(VtSession *z, char *password)
405368c31abSDavid du Colombier {
406368c31abSDavid du Colombier 	char buf[VtMaxStringSize], *p, *ep, *prefix;
407368c31abSDavid du Colombier 	int i;
408368c31abSDavid du Colombier 
409368c31abSDavid du Colombier 	USED(password);
410368c31abSDavid du Colombier 	vtLock(z->lk);
411368c31abSDavid du Colombier 	if(z->cstate != VtStateAlloc) {
412368c31abSDavid du Colombier 		vtSetError("bad session state");
413368c31abSDavid du Colombier 		vtUnlock(z->lk);
414368c31abSDavid du Colombier 		return 0;
415368c31abSDavid du Colombier 	}
416368c31abSDavid du Colombier 	if(z->fd < 0){
417368c31abSDavid du Colombier 		vtSetError("%s", z->fderror);
418368c31abSDavid du Colombier 		vtUnlock(z->lk);
419368c31abSDavid du Colombier 		return 0;
420368c31abSDavid du Colombier 	}
421368c31abSDavid du Colombier 
422368c31abSDavid du Colombier 	/* be a little anal */
423368c31abSDavid du Colombier 	vtLock(z->inLock);
424368c31abSDavid du Colombier 	vtLock(z->outLock);
425368c31abSDavid du Colombier 
426368c31abSDavid du Colombier 	prefix = "venti-";
427368c31abSDavid du Colombier 	p = buf;
428368c31abSDavid du Colombier 	ep = buf + sizeof(buf);
429368c31abSDavid du Colombier 	p = seprint(p, ep, "%s", prefix);
430368c31abSDavid du Colombier 	p += strlen(p);
431368c31abSDavid du Colombier 	for(i=0; vtVersions[i].version; i++) {
432368c31abSDavid du Colombier 		if(i != 0)
433368c31abSDavid du Colombier 			*p++ = ':';
434368c31abSDavid du Colombier 		p = seprint(p, ep, "%s", vtVersions[i].s);
435368c31abSDavid du Colombier 	}
436368c31abSDavid du Colombier 	p = seprint(p, ep, "-libventi\n");
437368c31abSDavid du Colombier 	assert(p-buf < sizeof(buf));
438368c31abSDavid du Colombier 	if(z->outHash)
439368c31abSDavid du Colombier 		vtSha1Update(z->outHash, (uchar*)buf, p-buf);
440368c31abSDavid du Colombier 	if(!vtFdWrite(z->fd, (uchar*)buf, p-buf))
441368c31abSDavid du Colombier 		goto Err;
442368c31abSDavid du Colombier 
443368c31abSDavid du Colombier 	vtDebug(z, "version string out: %s", buf);
444368c31abSDavid du Colombier 
445368c31abSDavid du Colombier 	if(!vtVersionRead(z, prefix, &z->version))
446368c31abSDavid du Colombier 		goto Err;
447368c31abSDavid du Colombier 
448368c31abSDavid du Colombier 	vtDebug(z, "version = %d: %s\n", z->version, vtGetVersion(z));
449368c31abSDavid du Colombier 
450368c31abSDavid du Colombier 	vtUnlock(z->inLock);
451368c31abSDavid du Colombier 	vtUnlock(z->outLock);
452368c31abSDavid du Colombier 	z->cstate = VtStateConnected;
453368c31abSDavid du Colombier 	vtUnlock(z->lk);
454368c31abSDavid du Colombier 
455368c31abSDavid du Colombier 	if(z->vtbl)
456368c31abSDavid du Colombier 		return 1;
457368c31abSDavid du Colombier 
458368c31abSDavid du Colombier 	if(!vtHello(z))
459368c31abSDavid du Colombier 		goto Err;
460368c31abSDavid du Colombier 	return 1;
461368c31abSDavid du Colombier Err:
462368c31abSDavid du Colombier 	if(z->fd >= 0)
463368c31abSDavid du Colombier 		vtFdClose(z->fd);
464368c31abSDavid du Colombier 	z->fd = -1;
465368c31abSDavid du Colombier 	vtUnlock(z->inLock);
466368c31abSDavid du Colombier 	vtUnlock(z->outLock);
467368c31abSDavid du Colombier 	z->cstate = VtStateClosed;
468368c31abSDavid du Colombier 	vtUnlock(z->lk);
469368c31abSDavid du Colombier 	return 0;
470368c31abSDavid du Colombier }
471368c31abSDavid du Colombier 
472