| #include <u.h> |
| #include <libc.h> |
| #include <venti.h> |
| |
| int ventidoublechecksha1 = 1; |
| |
| static int |
| vtfcallrpc(VtConn *z, VtFcall *ou, VtFcall *in) |
| { |
| Packet *p; |
| |
| p = vtfcallpack(ou); |
| if(p == nil) |
| return -1; |
| if((p = _vtrpc(z, p, ou)) == nil) |
| return -1; |
| if(vtfcallunpack(in, p) < 0){ |
| packetfree(p); |
| return -1; |
| } |
| if(chattyventi) |
| fprint(2, "%s <- %F\n", argv0, in); |
| if(in->msgtype == VtRerror){ |
| werrstr(in->error); |
| vtfcallclear(in); |
| packetfree(p); |
| return -1; |
| } |
| if(in->msgtype != ou->msgtype+1){ |
| werrstr("type mismatch: sent %c%d got %c%d", |
| "TR"[ou->msgtype&1], ou->msgtype>>1, |
| "TR"[in->msgtype&1], in->msgtype>>1); |
| vtfcallclear(in); |
| packetfree(p); |
| return -1; |
| } |
| packetfree(p); |
| return 0; |
| } |
| |
| int |
| vthello(VtConn *z) |
| { |
| VtFcall tx, rx; |
| |
| memset(&tx, 0, sizeof tx); |
| tx.msgtype = VtThello; |
| tx.version = z->version; |
| tx.uid = z->uid; |
| if(tx.uid == nil) |
| tx.uid = "anonymous"; |
| if(vtfcallrpc(z, &tx, &rx) < 0) |
| return -1; |
| z->sid = rx.sid; |
| rx.sid = 0; |
| vtfcallclear(&rx); |
| return 0; |
| } |
| |
| Packet* |
| vtreadpacket(VtConn *z, uchar score[VtScoreSize], uint type, int n) |
| { |
| VtFcall tx, rx; |
| |
| if(memcmp(score, vtzeroscore, VtScoreSize) == 0) |
| return packetalloc(); |
| |
| if(z == nil){ |
| werrstr("not connected"); |
| return nil; |
| } |
| |
| if(z->version[1] == '2' && n >= (1<<16)) { |
| werrstr("read count too large for protocol"); |
| return nil; |
| } |
| memset(&tx, 0, sizeof tx); |
| tx.msgtype = VtTread; |
| tx.blocktype = type; |
| tx.count = n; |
| memmove(tx.score, score, VtScoreSize); |
| if(vtfcallrpc(z, &tx, &rx) < 0) |
| return nil; |
| if(packetsize(rx.data) > n){ |
| werrstr("read returned too much data"); |
| packetfree(rx.data); |
| return nil; |
| } |
| if(ventidoublechecksha1){ |
| packetsha1(rx.data, tx.score); |
| if(memcmp(score, tx.score, VtScoreSize) != 0){ |
| werrstr("read asked for %V got %V", score, tx.score); |
| packetfree(rx.data); |
| return nil; |
| } |
| } |
| return rx.data; |
| } |
| |
| int |
| vtread(VtConn *z, uchar score[VtScoreSize], uint type, uchar *buf, int n) |
| { |
| int nn; |
| Packet *p; |
| |
| if((p = vtreadpacket(z, score, type, n)) == nil) |
| return -1; |
| nn = packetsize(p); |
| if(packetconsume(p, buf, nn) < 0) |
| abort(); |
| packetfree(p); |
| return nn; |
| } |
| |
| int |
| vtwritepacket(VtConn *z, uchar score[VtScoreSize], uint type, Packet *p) |
| { |
| VtFcall tx, rx; |
| |
| if(packetsize(p) == 0){ |
| memmove(score, vtzeroscore, VtScoreSize); |
| return 0; |
| } |
| tx.msgtype = VtTwrite; |
| tx.blocktype = type; |
| tx.data = p; |
| if(ventidoublechecksha1) |
| packetsha1(p, score); |
| if(vtfcallrpc(z, &tx, &rx) < 0) |
| return -1; |
| if(ventidoublechecksha1){ |
| if(memcmp(score, rx.score, VtScoreSize) != 0){ |
| werrstr("sha1 hash mismatch: want %V got %V", score, rx.score); |
| return -1; |
| } |
| }else |
| memmove(score, rx.score, VtScoreSize); |
| return 0; |
| } |
| |
| int |
| vtwrite(VtConn *z, uchar score[VtScoreSize], uint type, uchar *buf, int n) |
| { |
| Packet *p; |
| int nn; |
| |
| p = packetforeign(buf, n, 0, nil); |
| nn = vtwritepacket(z, score, type, p); |
| packetfree(p); |
| return nn; |
| } |
| |
| int |
| vtsync(VtConn *z) |
| { |
| VtFcall tx, rx; |
| |
| tx.msgtype = VtTsync; |
| return vtfcallrpc(z, &tx, &rx); |
| } |
| |
| int |
| vtping(VtConn *z) |
| { |
| VtFcall tx, rx; |
| |
| tx.msgtype = VtTping; |
| return vtfcallrpc(z, &tx, &rx); |
| } |
| |
| int |
| vtconnect(VtConn *z) |
| { |
| if(vtversion(z) < 0) |
| return -1; |
| if(vthello(z) < 0) |
| return -1; |
| return 0; |
| } |
| |
| int |
| vtgoodbye(VtConn *z) |
| { |
| VtFcall tx, rx; |
| |
| tx.msgtype = VtTgoodbye; |
| vtfcallrpc(z, &tx, &rx); /* always fails: no VtRgoodbye */ |
| return 0; |
| } |