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