| #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; | 
 | } |