| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /* <!-- copyright */
- /*
- * aria2 - a simple utility for downloading files faster
- *
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- /* copyright --> */
- #include "PeerMessageUtil.h"
- #include "DlAbortEx.h"
- #include "Util.h"
- #include <netinet/in.h>
- PeerMessage* PeerMessageUtil::createPeerMessage(const char* msg, int len) {
- PeerMessage* peerMessage;
- if(len == 0) {
- // keep-alive
- peerMessage = new PeerMessage();
- peerMessage->setId(PeerMessage::KEEP_ALIVE);
- return peerMessage;
- }
- int id = getId(msg);
- switch(id) {
- case PeerMessage::CHOKE:
- case PeerMessage::UNCHOKE:
- case PeerMessage::INTERESTED:
- case PeerMessage::NOT_INTERESTED:
- peerMessage = createBasicMessage(id, msg, len);
- break;
- case PeerMessage::HAVE:
- peerMessage = createHaveMessage(id, msg, len);
- break;
- case PeerMessage::BITFIELD:
- peerMessage = createBitfieldMessage(id, msg, len);
- break;
- case PeerMessage::REQUEST:
- case PeerMessage::CANCEL:
- peerMessage = createRequestCancelMessage(id, msg, len);
- break;
- case PeerMessage::PIECE:
- peerMessage = createPieceMessage(id, msg, len);
- break;
- default:
- throw new DlAbortEx("invalid message id. id = %d", id);
- }
- return peerMessage;
- }
- PeerMessage* PeerMessageUtil::createBasicMessage(int id, const char* msg, int len) {
- if(len != 1) {
- throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 1);
- }
- PeerMessage* peerMessage = new PeerMessage();
- peerMessage->setId(id);
- return peerMessage;
- }
- PeerMessage* PeerMessageUtil::createHaveMessage(int id, const char* msg, int len) {
- if(len != 5) {
- throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 5);
- }
- PeerMessage* peerMessage = new PeerMessage();
- peerMessage->setId(id);
- peerMessage->setIndex(getIntParam(msg, 1));
- return peerMessage;
- }
- PeerMessage* PeerMessageUtil::createBitfieldMessage(int id, const char* msg, int len) {
- if(len <= 1) {
- throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be greater than %d", id, len, 1);
- }
- PeerMessage* peerMessage = new PeerMessage();
- peerMessage->setId(id);
- peerMessage->setBitfield((unsigned char*)msg+1, len-1);
- return peerMessage;
- }
- PeerMessage* PeerMessageUtil::createRequestCancelMessage(int id, const char* msg, int len) {
- if(len != 13) {
- throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 13);
- }
- PeerMessage* peerMessage = new PeerMessage();
- peerMessage->setId(id);
- peerMessage->setIndex(getIntParam(msg, 1));
- peerMessage->setBegin(getIntParam(msg, 5));
- peerMessage->setLength(getIntParam(msg, 9));
- return peerMessage;
- }
- PeerMessage* PeerMessageUtil::createPieceMessage(int id, const char* msg, int len) {
- if(len <= 9) {
- throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be greater than %d", id, len, 9);
- }
- PeerMessage* peerMessage = new PeerMessage();
- peerMessage->setId(id);
- peerMessage->setIndex(getIntParam(msg, 1));
- peerMessage->setBegin(getIntParam(msg, 5));
- peerMessage->setBlock(msg+9, len-9);
- return peerMessage;
- }
- int PeerMessageUtil::getId(const char* msg) {
- return (int)msg[0];
- }
- int PeerMessageUtil::getIntParam(const char* msg, int offset) {
- int nParam;
- memcpy(&nParam, msg+offset, 4);
- return ntohl(nParam);
- }
- void PeerMessageUtil::checkIndex(const PeerMessage* message, int pieces) {
- if(!(0 <= message->getIndex() && message->getIndex() < pieces)) {
- throw new DlAbortEx("invalid index = %d", message->getIndex());
- }
- }
- void PeerMessageUtil::checkBegin(const PeerMessage* message, int pieceLength) {
- if(!(0 <= message->getBegin() && message->getBegin() < pieceLength)) {
- throw new DlAbortEx("invalid begin = %d", message->getBegin());
- }
- }
- void PeerMessageUtil::checkPieceOffset(const PeerMessage* message, int pieceLength, int pieces, long long int totalLength) {
- if(!(0 <= message->getBegin() && 0 < message->getLength())) {
- throw new DlAbortEx("invalid offset, begin = %d, length = %d", message->getBegin(), message->getLength());
- }
- int offset = message->getBegin()+message->getLength();
- int currentPieceLength;
- if(message->getIndex()+1 == pieces) {
- currentPieceLength = pieceLength-(pieces*pieceLength-totalLength);
- } else {
- currentPieceLength = pieceLength;
- }
- if(!(0 < offset && offset <= currentPieceLength)) {
- throw new DlAbortEx("invalid offset, begin = %d, length = %d", message->getBegin(), message->getLength());
- }
- }
- void PeerMessageUtil::checkLength(const PeerMessage* message) {
- if(message->getLength() > 128*1024) {
- throw new DlAbortEx("too large length %d > 128KB", message->getLength());
- }
- }
- void PeerMessageUtil::checkBitfield(const PeerMessage* message, int pieces) {
- if(!(message->getBitfieldLength() == BITFIELD_LEN_FROM_PIECES(pieces))) {
- throw new DlAbortEx("invalid bitfield length = %d", message->getBitfieldLength());
- }
- char lastbyte = message->getBitfield()[message->getBitfieldLength()-1];
- for(int i = 0; i < 8-pieces%8 && pieces%8 != 0; i++) {
- if(!(((lastbyte >> i) & 1) == 0)) {
- throw new DlAbortEx("invalid bitfield");
- }
- }
- }
- void PeerMessageUtil::checkIntegrity(const PeerMessage* message, int pieceLength, int pieces, long long int totalLength) {
- // 0 <= index < pieces
- // 0 <= begin < pieceLength
- // 0 < begin+length <= pieceLength
- // len of bitfield == pieces/8+(pieces%8 ? 1 : 0)
- // for(int i = 0; i < 8-pieces%8; i++) { ((lastbyteofbitfield >> i) & 1) == 0 }
- switch(message->getId()) {
- case PeerMessage::KEEP_ALIVE:
- case PeerMessage::CHOKE:
- case PeerMessage::UNCHOKE:
- case PeerMessage::INTERESTED:
- case PeerMessage::NOT_INTERESTED:
- break;
- case PeerMessage::HAVE:
- checkIndex(message, pieces);
- break;
- case PeerMessage::BITFIELD:
- checkBitfield(message, pieces);
- break;
- case PeerMessage::REQUEST:
- case PeerMessage::CANCEL:
- checkIndex(message, pieces);
- checkBegin(message, pieceLength);
- checkLength(message);
- checkPieceOffset(message, pieceLength, pieces, totalLength);
- break;
- case PeerMessage::PIECE:
- checkIndex(message, pieces);
- checkBegin(message, pieceLength);
- break;
- default:
- throw new DlAbortEx("invalid message id. id = %d", message->getId());
- }
- }
- HandshakeMessage* PeerMessageUtil::createHandshakeMessage(const char* msg) {
- HandshakeMessage* message = new HandshakeMessage();
- message->pstrlen = msg[0];
- char pstr[20];
- memcpy(pstr, &msg[1], sizeof(pstr)-1);
- pstr[sizeof(pstr)-1] = '\0';
- message->pstr = pstr;
- memcpy(message->infoHash, &msg[28], 20);
- memcpy(message->peerId, &msg[48], 20);
- return message;
- }
- void PeerMessageUtil::checkHandshake(const HandshakeMessage* message, const unsigned char* infoHash) {
- if(message->pstrlen != 19) {
- throw new DlAbortEx("invalid handshake pstrlen = %d", (int)message->pstrlen);
- }
- if(message->pstr != PSTR) {
- throw new DlAbortEx("invalid handshake pstr");
- }
- string myInfoHash = Util::toHex(infoHash, 20);
- string peerInfoHash = Util::toHex(message->infoHash, 20);
- if(myInfoHash != peerInfoHash) {
- throw new DlAbortEx("invalid handshake info hash: expected:%s, actual:%s",
- myInfoHash.c_str(), peerInfoHash.c_str());
- }
- }
|