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