Plan 9 from Bell Labs’s /usr/web/sources/contrib/mjl/wip/deluge/msg.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "deluge.h"

static int
readint(Biobuf *bp, ulong *i)
{
	char buf[4];
	if(Bread(bp, buf, sizeof buf) != sizeof buf)
		return 0;
	*i = GET32(buf);
	return 1;
}


Msg *
msgnew(int type, int peern)
{
	Msg *m;

	m = emalloc(sizeof m[0]);
	m->msglength = -1;
	m->peern = peern;
	m->type = type;
	m->next = nil;
	return m;
}


void
msgfree(Msg *m)
{
	switch(m->type){
	default:
		break;
	case MBitfield:
		bitfree(m->haves);
		break;
	case MPiece:
		free(m->piece);
		break;
	}
	free(m);
}


void
msgappend(Msg **f, Msg *m)
{
	Msg *p;

	if(*f == nil){
		*f = m;
	}else{
		for(p = *f; p->next; p = p->next)
			;
		p->next = m;
	}
	m->next = nil;
}

void
msgprepend(Msg **f, Msg *m)
{
	m->next = *f;
	*f = m;
}

int
msgremove(Msg **mp, Msg *m)
{
	Msg *p;

	if(*mp == nil)
		return 0;

	if(*mp == m){
		*mp = m->next;
		return 1;
	}

	for(p = *mp; p->next; p = p->next){
		if(p->next == m){
			p->next = m->next;
			return 1;
		}
	}
	return 0;
}

int
msglen(Msg *m)
{
	int i = 0;
	while(m){
		m = m->next;
		i++;
	}
	return i;
}

int
msgmaxlen(int nbytes)
{
	return MAX(1+4+4+4, MAX(1+nbytes, 1+4+4+Bitelength));
}


char *
msgparse(char *p, int len, Msg *m, int nbytes)
{
	uchar *haves;
	int lens[] = {
	[MChoke]			1,
	[MUnchoke]		1,
	[MInterested]		1,
	[MNotinterested]	1,
	[MHave]			1+4,
	[MBitfield]			1+nbytes,
	[MRequest]		1+4+4+4,
	[MCancel]			1+4+4+4,
	[MPiece]			1+4+4+Bitelength,
	};

	m->msglength = len;
	if(len == 0){
		m->type = MKeepalive;
		return nil;
	}

	m->type = (uchar)p[0];
	p += 1;
	if(m->type > MLast)
		return smprint("unknown message type: %d", m->type);
	if(m->type != MPiece && len != lens[m->type] || m->type == MPiece && len > lens[m->type])
		return smprint("wrong message length: type=%d have=%d need=%d", m->type, len, lens[m->type]);

	switch(m->type){
	case MChoke:
	case MUnchoke:
	case MInterested:
	case MNotinterested:
		break;
	case MHave:
		m->have = GET32(p);
		break;
	case MBitfield:
		haves = emalloc(len-1);
		memmove(haves, p, len-1);
		m->haves = bitnew((len-1)*8, haves);
		p += len-1;
		USED(p);
		break;
	case MRequest:
	case MCancel:
		m->index = GET32(p);
		p += 4;
		m->begin = GET32(p);
		p += 4;
		m->length = GET32(p);
		p += 4;
		USED(p);
		break;
	case MPiece:
		m->index = GET32(p);
		p += 4;
		m->begin = GET32(p);
		p += 4;
		m->length = len-1-4-4;
		m->piece = emalloc(m->length);
		memmove(m->piece, p, m->length);
		break;
	default:
		sysfatal("cannot happen in msgparse");
	};
	return nil;
}


char *
msgwrite(int fd, Msg *m)
{
	uchar buf[4*3];
	uchar start[4+1];
	char *p = nil;
	int plen = 0;

	switch(m->type){
	case MKeepalive:
		PUT32(start, 0);
		if(write(fd, start, 4) != 4)
			return smprint("writing message: %r");
		return nil;
	case MChoke:
	case MUnchoke:
	case MInterested:
	case MNotinterested:
		break;
	case MHave:
		PUT32(buf, m->have);
		p = (char*)buf;
		plen = 4;
		break;
	case MBitfield:
		p = (char*)m->haves->p;
		plen = bitnbytes(m->haves);
		break;
	case MRequest:
	case MCancel:
		PUT32(buf, m->index);
		PUT32(buf+4, m->begin);
		PUT32(buf+8, m->length);
		p = (char*)buf;
		plen = 3*4;
		break;
	case MPiece:
		sysfatal("msgwrite should not be called for msgtype MPiece");
		break;
	default:
		return smprint("msgwrite: invalid message type: %d", m->type);
	}

	PUT32(start, 1+plen);
	start[4] = m->type;

	if(write(fd, (char*)start, sizeof start) != sizeof start
			|| (p && write(fd, p, plen) != plen))
		return smprint("writing message: %r");
	return nil;
}


char *
msgwritepiece(int fd, Msg *m)
{
	uchar start[4+1+4+4];

	assert(m->type == MPiece);

	PUT32(start, 1+4+4+m->length);
	start[4] = m->type;
	PUT32(start+5, m->index);
	PUT32(start+9, m->begin);

	if(write(fd, (char*)start, sizeof start) != sizeof start
			|| write(fd, m->piece, m->length) != m->length)
		return smprint("writing piece: %r");
	return nil;
}

char *
peerreadstart(int fd, uchar *infohash, uchar *peerid)
{
	char buf[20+8+Infohashlen+Peeridlen];
	char *p;

	if(readn(fd, buf, sizeof buf) != sizeof buf)
		return smprint("reading handshake: %r");
	p = buf;

	if(memcmp(p, "\x13BitTorrent protocol", 20) != 0)
		return smprint("wrong magic");
	p += 20;
	if(memcmp(p, "\0\0\0\0\0\0\0\0", 8) != 0)
		DEBUG(2, "peerreadstart: eight zeros not zero in handshake, peer is using extensions\n");
	p += 8;
	if(memcmp(p, infohash, Infohashlen) != 0)
		return smprint("infohash does not match (remote=%H)", p);
	p += Infohashlen;

	memmove(peerid, p, Peeridlen);
	p += Peeridlen;
	USED(p);

	return nil;
}


char *
peerwritestart(int fd, uchar *infohash, uchar *peerid)
{
	uchar *p;
	uchar buf[20+8+Infohashlen+Peeridlen];

	p = buf;
	memmove(p, "\x13BitTorrent protocol", 20);
	p += 20;
	memset(p, 0, 8);
	p += 8;
	memmove(p, infohash, Infohashlen);
	p += Infohashlen;
	memmove(p, peerid, Peeridlen);
	p += Peeridlen;
	USED(p);

	if(write(fd, (char*)buf, sizeof buf) != sizeof buf)
		return smprint("writing handshake: %r");

	return nil;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].