120 lines
2.1 KiB
C
120 lines
2.1 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <venti.h>
|
|
|
|
static char *okvers[] = {
|
|
"02",
|
|
nil,
|
|
};
|
|
|
|
/*
|
|
static char EBigString[] = "string too long";
|
|
static char EBigPacket[] = "packet too long";
|
|
static char ENullString[] = "missing string";
|
|
*/
|
|
static char EBadVersion[] = "bad format in version string";
|
|
|
|
static int
|
|
vtreadversion(VtConn *z, char *q, char *v, int nv)
|
|
{
|
|
int n;
|
|
|
|
for(;;){
|
|
if(nv <= 1){
|
|
werrstr("version too long");
|
|
return -1;
|
|
}
|
|
n = read(z->infd, v, 1);
|
|
if(n <= 0){
|
|
if(n == 0)
|
|
werrstr("unexpected eof");
|
|
return -1;
|
|
}
|
|
if(*v == '\n'){
|
|
*v = 0;
|
|
break;
|
|
}
|
|
if((uchar)*v < ' ' || (uchar)*v > 0x7f || (*q && *v != *q)){
|
|
werrstr(EBadVersion);
|
|
return -1;
|
|
}
|
|
v++;
|
|
nv--;
|
|
if(*q)
|
|
q++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
vtversion(VtConn *z)
|
|
{
|
|
char buf[VtMaxStringSize], *p, *ep, *prefix, *pp;
|
|
int i;
|
|
|
|
qlock(&z->lk);
|
|
if(z->state != VtStateAlloc){
|
|
werrstr("bad session state");
|
|
qunlock(&z->lk);
|
|
return -1;
|
|
}
|
|
|
|
qlock(&z->inlk);
|
|
qlock(&z->outlk);
|
|
|
|
p = buf;
|
|
ep = buf + sizeof buf;
|
|
prefix = "venti-";
|
|
p = seprint(p, ep, "%s", prefix);
|
|
p += strlen(p);
|
|
for(i=0; okvers[i]; i++)
|
|
p = seprint(p, ep, "%s%s", i ? ":" : "", okvers[i]);
|
|
p = seprint(p, ep, "-libventi\n");
|
|
assert(p-buf < sizeof buf);
|
|
|
|
if(write(z->outfd, buf, p-buf) != p-buf)
|
|
goto Err;
|
|
vtdebug(z, "version string out: %s", buf);
|
|
|
|
if(vtreadversion(z, prefix, buf, sizeof buf) < 0)
|
|
goto Err;
|
|
vtdebug(z, "version string in: %s", buf);
|
|
|
|
p = buf+strlen(prefix);
|
|
for(; *p; p=pp){
|
|
if(*p == ':' || *p == '-')
|
|
p++;
|
|
pp = strpbrk(p, ":-");
|
|
if(pp == nil)
|
|
pp = p+strlen(p);
|
|
for(i=0; okvers[i]; i++)
|
|
if(strlen(okvers[i]) == pp-p && memcmp(okvers[i], p, pp-p) == 0){
|
|
*pp = 0;
|
|
z->version = vtstrdup(p);
|
|
goto Okay;
|
|
}
|
|
}
|
|
werrstr("unable to negotiate version");
|
|
goto Err;
|
|
|
|
Okay:
|
|
z->state = VtStateConnected;
|
|
qunlock(&z->inlk);
|
|
qunlock(&z->outlk);
|
|
qunlock(&z->lk);
|
|
return 0;
|
|
|
|
Err:
|
|
werrstr("vtversion: %r");
|
|
if(z->infd >= 0)
|
|
close(z->infd);
|
|
if(z->outfd >= 0 && z->outfd != z->infd)
|
|
close(z->outfd);
|
|
z->infd = -1;
|
|
z->outfd = -1;
|
|
z->state = VtStateClosed;
|
|
qunlock(&z->inlk);
|
|
qunlock(&z->outlk);
|
|
qunlock(&z->lk);
|
|
return -1;
|
|
}
|