| #include <u.h> |
| #include <libc.h> |
| #include <venti.h> |
| |
| Packet* |
| vtfcallpack(VtFcall *f) |
| { |
| uchar buf[10]; |
| Packet *p; |
| |
| p = packetalloc(); |
| |
| buf[0] = f->msgtype; |
| buf[1] = f->tag; |
| packetappend(p, buf, 2); |
| |
| switch(f->msgtype){ |
| default: |
| werrstr("vtfcallpack: unknown packet type %d", f->msgtype); |
| goto Err; |
| |
| case VtRerror: |
| if(vtputstring(p, f->error) < 0) |
| goto Err; |
| break; |
| |
| case VtTping: |
| break; |
| |
| case VtRping: |
| break; |
| |
| case VtThello: |
| if(vtputstring(p, f->version) < 0 |
| || vtputstring(p, f->uid) < 0) |
| goto Err; |
| buf[0] = f->strength; |
| buf[1] = f->ncrypto; |
| packetappend(p, buf, 2); |
| packetappend(p, f->crypto, f->ncrypto); |
| buf[0] = f->ncodec; |
| packetappend(p, buf, 1); |
| packetappend(p, f->codec, f->ncodec); |
| break; |
| |
| case VtRhello: |
| if(vtputstring(p, f->sid) < 0) |
| goto Err; |
| buf[0] = f->rcrypto; |
| buf[1] = f->rcodec; |
| packetappend(p, buf, 2); |
| break; |
| |
| case VtTgoodbye: |
| break; |
| |
| case VtTread: |
| packetappend(p, f->score, VtScoreSize); |
| buf[0] = vttodisktype(f->blocktype); |
| if(~buf[0] == 0) |
| goto Err; |
| buf[1] = 0; |
| if(f->count >= (1<<16)) { |
| buf[2] = f->count >> 24; |
| buf[3] = f->count >> 16; |
| buf[4] = f->count >> 8; |
| buf[5] = f->count; |
| packetappend(p, buf, 6); |
| } else { |
| buf[2] = f->count >> 8; |
| buf[3] = f->count; |
| packetappend(p, buf, 4); |
| } |
| break; |
| |
| case VtRread: |
| packetconcat(p, f->data); |
| break; |
| |
| case VtTwrite: |
| buf[0] = vttodisktype(f->blocktype); |
| if(~buf[0] == 0) |
| goto Err; |
| buf[1] = 0; |
| buf[2] = 0; |
| buf[3] = 0; |
| packetappend(p, buf, 4); |
| packetconcat(p, f->data); |
| break; |
| |
| case VtRwrite: |
| packetappend(p, f->score, VtScoreSize); |
| break; |
| |
| case VtTsync: |
| break; |
| |
| case VtRsync: |
| break; |
| } |
| |
| return p; |
| |
| Err: |
| packetfree(p); |
| return nil; |
| } |
| |
| int |
| vtfcallunpack(VtFcall *f, Packet *p) |
| { |
| uchar buf[4]; |
| |
| memset(f, 0, sizeof *f); |
| |
| if(packetconsume(p, buf, 2) < 0) |
| return -1; |
| |
| f->msgtype = buf[0]; |
| f->tag = buf[1]; |
| |
| switch(f->msgtype){ |
| default: |
| werrstr("vtfcallunpack: unknown bad packet type %d", f->msgtype); |
| vtfcallclear(f); |
| return -1; |
| |
| case VtRerror: |
| if(vtgetstring(p, &f->error) < 0) |
| goto Err; |
| break; |
| |
| case VtTping: |
| break; |
| |
| case VtRping: |
| break; |
| |
| case VtThello: |
| if(vtgetstring(p, &f->version) < 0 |
| || vtgetstring(p, &f->uid) < 0 |
| || packetconsume(p, buf, 2) < 0) |
| goto Err; |
| f->strength = buf[0]; |
| f->ncrypto = buf[1]; |
| if(f->ncrypto){ |
| f->crypto = vtmalloc(f->ncrypto); |
| if(packetconsume(p, buf, f->ncrypto) < 0) |
| goto Err; |
| } |
| if(packetconsume(p, buf, 1) < 0) |
| goto Err; |
| f->ncodec = buf[0]; |
| if(f->ncodec){ |
| f->codec = vtmalloc(f->ncodec); |
| if(packetconsume(p, buf, f->ncodec) < 0) |
| goto Err; |
| } |
| break; |
| |
| case VtRhello: |
| if(vtgetstring(p, &f->sid) < 0 |
| || packetconsume(p, buf, 2) < 0) |
| goto Err; |
| f->rcrypto = buf[0]; |
| f->rcodec = buf[1]; |
| break; |
| |
| case VtTgoodbye: |
| break; |
| |
| case VtTread: |
| if(packetconsume(p, f->score, VtScoreSize) < 0 |
| || packetconsume(p, buf, 2) < 0) |
| goto Err; |
| f->blocktype = vtfromdisktype(buf[0]); |
| if(~f->blocktype == 0) |
| goto Err; |
| switch(packetsize(p)) { |
| default: |
| goto Err; |
| case 2: |
| if(packetconsume(p, buf, 2) < 0) |
| goto Err; |
| f->count = (buf[0] << 8) | buf[1]; |
| break; |
| case 4: |
| if(packetconsume(p, buf, 4) < 0) |
| goto Err; |
| f->count = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; |
| break; |
| } |
| break; |
| |
| case VtRread: |
| f->data = packetalloc(); |
| packetconcat(f->data, p); |
| break; |
| |
| case VtTwrite: |
| if(packetconsume(p, buf, 4) < 0) |
| goto Err; |
| f->blocktype = vtfromdisktype(buf[0]); |
| if(~f->blocktype == 0) |
| goto Err; |
| f->data = packetalloc(); |
| packetconcat(f->data, p); |
| break; |
| |
| case VtRwrite: |
| if(packetconsume(p, f->score, VtScoreSize) < 0) |
| goto Err; |
| break; |
| |
| case VtTsync: |
| break; |
| |
| case VtRsync: |
| break; |
| } |
| |
| if(packetsize(p) != 0) |
| goto Err; |
| |
| return 0; |
| |
| Err: |
| werrstr("bad packet"); |
| vtfcallclear(f); |
| return -1; |
| } |
| |
| void |
| vtfcallclear(VtFcall *f) |
| { |
| vtfree(f->error); |
| f->error = nil; |
| vtfree(f->uid); |
| f->uid = nil; |
| vtfree(f->sid); |
| f->sid = nil; |
| vtfree(f->version); |
| f->version = nil; |
| vtfree(f->crypto); |
| f->crypto = nil; |
| vtfree(f->codec); |
| f->codec = nil; |
| vtfree(f->auth); |
| f->auth = nil; |
| packetfree(f->data); |
| f->data = nil; |
| } |