| #include <u.h> | 
 | #include <libc.h> | 
 | #include <venti.h> | 
 |  | 
 | static char *okvers[] = { | 
 | 	"04", | 
 | 	"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; | 
 | } |