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