xref: /plan9/sys/src/libventi/version.c (revision 368c31ab13393dea083228fdd1c3445076f83a4b)
1 #include <u.h>
2 #include <libc.h>
3 #include <venti.h>
4 
5 static char *okvers[] = {
6 	"02",
7 	nil,
8 };
9 
10 /*
11 static char EBigString[] = "string too long";
12 static char EBigPacket[] = "packet too long";
13 static char ENullString[] = "missing string";
14 */
15 static char EBadVersion[] = "bad format in version string";
16 
17 static int
vtreadversion(VtConn * z,char * q,char * v,int nv)18 vtreadversion(VtConn *z, char *q, char *v, int nv)
19 {
20 	int n;
21 
22 	for(;;){
23 		if(nv <= 1){
24 			werrstr("version too long");
25 			return -1;
26 		}
27 		n = read(z->infd, v, 1);
28 		if(n <= 0){
29 			if(n == 0)
30 				werrstr("unexpected eof");
31 			return -1;
32 		}
33 		if(*v == '\n'){
34 			*v = 0;
35 			break;
36 		}
37 		if((uchar)*v < ' ' || (uchar)*v > 0x7f || (*q && *v != *q)){
38 			werrstr(EBadVersion);
39 			return -1;
40 		}
41 		v++;
42 		nv--;
43 		if(*q)
44 			q++;
45 	}
46 	return 0;
47 }
48 
49 int
vtversion(VtConn * z)50 vtversion(VtConn *z)
51 {
52 	char buf[VtMaxStringSize], *p, *ep, *prefix, *pp;
53 	int i;
54 
55 	qlock(&z->lk);
56 	if(z->state != VtStateAlloc){
57 		werrstr("bad session state");
58 		qunlock(&z->lk);
59 		return -1;
60 	}
61 
62 	qlock(&z->inlk);
63 	qlock(&z->outlk);
64 
65 	p = buf;
66 	ep = buf + sizeof buf;
67 	prefix = "venti-";
68 	p = seprint(p, ep, "%s", prefix);
69 	p += strlen(p);
70 	for(i=0; okvers[i]; i++)
71 		p = seprint(p, ep, "%s%s", i ? ":" : "", okvers[i]);
72 	p = seprint(p, ep, "-libventi\n");
73 	assert(p-buf < sizeof buf);
74 
75 	if(write(z->outfd, buf, p-buf) != p-buf)
76 		goto Err;
77 	vtdebug(z, "version string out: %s", buf);
78 
79 	if(vtreadversion(z, prefix, buf, sizeof buf) < 0)
80 		goto Err;
81 	vtdebug(z, "version string in: %s", buf);
82 
83 	p = buf+strlen(prefix);
84 	for(; *p; p=pp){
85 		if(*p == ':' || *p == '-')
86 			p++;
87 		pp = strpbrk(p, ":-");
88 		if(pp == nil)
89 			pp = p+strlen(p);
90 		for(i=0; okvers[i]; i++)
91 			if(strlen(okvers[i]) == pp-p && memcmp(okvers[i], p, pp-p) == 0){
92 				*pp = 0;
93 				z->version = vtstrdup(p);
94 				goto Okay;
95 			}
96 	}
97 	werrstr("unable to negotiate version");
98 	goto Err;
99 
100 Okay:
101 	z->state = VtStateConnected;
102 	qunlock(&z->inlk);
103 	qunlock(&z->outlk);
104 	qunlock(&z->lk);
105 	return 0;
106 
107 Err:
108 	werrstr("vtversion: %r");
109 	if(z->infd >= 0)
110 		close(z->infd);
111 	if(z->outfd >= 0 && z->outfd != z->infd)
112 		close(z->outfd);
113 	z->infd = -1;
114 	z->outfd = -1;
115 	z->state = VtStateClosed;
116 	qunlock(&z->inlk);
117 	qunlock(&z->outlk);
118 	qunlock(&z->lk);
119 	return -1;
120 }
121