PeerMessageUtil.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - a simple utility for downloading files faster
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. /* copyright --> */
  22. #include "PeerMessageUtil.h"
  23. #include "DlAbortEx.h"
  24. #include "Util.h"
  25. #include <netinet/in.h>
  26. PeerMessage* PeerMessageUtil::createPeerMessage(const char* msg, int len) {
  27. PeerMessage* peerMessage;
  28. if(len == 0) {
  29. // keep-alive
  30. peerMessage = new PeerMessage();
  31. peerMessage->setId(PeerMessage::KEEP_ALIVE);
  32. return peerMessage;
  33. }
  34. int id = getId(msg);
  35. switch(id) {
  36. case PeerMessage::CHOKE:
  37. case PeerMessage::UNCHOKE:
  38. case PeerMessage::INTERESTED:
  39. case PeerMessage::NOT_INTERESTED:
  40. peerMessage = createBasicMessage(id, msg, len);
  41. break;
  42. case PeerMessage::HAVE:
  43. peerMessage = createHaveMessage(id, msg, len);
  44. break;
  45. case PeerMessage::BITFIELD:
  46. peerMessage = createBitfieldMessage(id, msg, len);
  47. break;
  48. case PeerMessage::REQUEST:
  49. case PeerMessage::CANCEL:
  50. peerMessage = createRequestCancelMessage(id, msg, len);
  51. break;
  52. case PeerMessage::PIECE:
  53. peerMessage = createPieceMessage(id, msg, len);
  54. break;
  55. default:
  56. throw new DlAbortEx("invalid message id. id = %d", id);
  57. }
  58. return peerMessage;
  59. }
  60. PeerMessage* PeerMessageUtil::createBasicMessage(int id, const char* msg, int len) {
  61. if(len != 1) {
  62. throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 1);
  63. }
  64. PeerMessage* peerMessage = new PeerMessage();
  65. peerMessage->setId(id);
  66. return peerMessage;
  67. }
  68. PeerMessage* PeerMessageUtil::createHaveMessage(int id, const char* msg, int len) {
  69. if(len != 5) {
  70. throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 5);
  71. }
  72. PeerMessage* peerMessage = new PeerMessage();
  73. peerMessage->setId(id);
  74. peerMessage->setIndex(getIntParam(msg, 1));
  75. return peerMessage;
  76. }
  77. PeerMessage* PeerMessageUtil::createBitfieldMessage(int id, const char* msg, int len) {
  78. if(len <= 1) {
  79. throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be greater than %d", id, len, 1);
  80. }
  81. PeerMessage* peerMessage = new PeerMessage();
  82. peerMessage->setId(id);
  83. peerMessage->setBitfield((unsigned char*)msg+1, len-1);
  84. return peerMessage;
  85. }
  86. PeerMessage* PeerMessageUtil::createRequestCancelMessage(int id, const char* msg, int len) {
  87. if(len != 13) {
  88. throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 13);
  89. }
  90. PeerMessage* peerMessage = new PeerMessage();
  91. peerMessage->setId(id);
  92. peerMessage->setIndex(getIntParam(msg, 1));
  93. peerMessage->setBegin(getIntParam(msg, 5));
  94. peerMessage->setLength(getIntParam(msg, 9));
  95. return peerMessage;
  96. }
  97. PeerMessage* PeerMessageUtil::createPieceMessage(int id, const char* msg, int len) {
  98. if(len <= 9) {
  99. throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be greater than %d", id, len, 9);
  100. }
  101. PeerMessage* peerMessage = new PeerMessage();
  102. peerMessage->setId(id);
  103. peerMessage->setIndex(getIntParam(msg, 1));
  104. peerMessage->setBegin(getIntParam(msg, 5));
  105. peerMessage->setBlock(msg+9, len-9);
  106. return peerMessage;
  107. }
  108. int PeerMessageUtil::getId(const char* msg) {
  109. return (int)msg[0];
  110. }
  111. int PeerMessageUtil::getIntParam(const char* msg, int offset) {
  112. int nParam;
  113. memcpy(&nParam, msg+offset, 4);
  114. return ntohl(nParam);
  115. }
  116. void PeerMessageUtil::checkIndex(const PeerMessage* message, int pieces) {
  117. if(!(0 <= message->getIndex() && message->getIndex() < pieces)) {
  118. throw new DlAbortEx("invalid index = %d", message->getIndex());
  119. }
  120. }
  121. void PeerMessageUtil::checkBegin(const PeerMessage* message, int pieceLength) {
  122. if(!(0 <= message->getBegin() && message->getBegin() < pieceLength)) {
  123. throw new DlAbortEx("invalid begin = %d", message->getBegin());
  124. }
  125. }
  126. void PeerMessageUtil::checkPieceOffset(const PeerMessage* message, int pieceLength, int pieces, long long int totalLength) {
  127. if(!(0 <= message->getBegin() && 0 < message->getLength())) {
  128. throw new DlAbortEx("invalid offset, begin = %d, length = %d", message->getBegin(), message->getLength());
  129. }
  130. int offset = message->getBegin()+message->getLength();
  131. int currentPieceLength;
  132. if(message->getIndex()+1 == pieces) {
  133. currentPieceLength = pieceLength-(pieces*pieceLength-totalLength);
  134. } else {
  135. currentPieceLength = pieceLength;
  136. }
  137. if(!(0 < offset && offset <= currentPieceLength)) {
  138. throw new DlAbortEx("invalid offset, begin = %d, length = %d", message->getBegin(), message->getLength());
  139. }
  140. }
  141. void PeerMessageUtil::checkLength(const PeerMessage* message) {
  142. if(message->getLength() > 128*1024) {
  143. throw new DlAbortEx("too large length %d > 128KB", message->getLength());
  144. }
  145. }
  146. void PeerMessageUtil::checkBitfield(const PeerMessage* message, int pieces) {
  147. if(!(message->getBitfieldLength() == BITFIELD_LEN_FROM_PIECES(pieces))) {
  148. throw new DlAbortEx("invalid bitfield length = %d", message->getBitfieldLength());
  149. }
  150. char lastbyte = message->getBitfield()[message->getBitfieldLength()-1];
  151. for(int i = 0; i < 8-pieces%8 && pieces%8 != 0; i++) {
  152. if(!(((lastbyte >> i) & 1) == 0)) {
  153. throw new DlAbortEx("invalid bitfield");
  154. }
  155. }
  156. }
  157. void PeerMessageUtil::checkIntegrity(const PeerMessage* message, int pieceLength, int pieces, long long int totalLength) {
  158. // 0 <= index < pieces
  159. // 0 <= begin < pieceLength
  160. // 0 < begin+length <= pieceLength
  161. // len of bitfield == pieces/8+(pieces%8 ? 1 : 0)
  162. // for(int i = 0; i < 8-pieces%8; i++) { ((lastbyteofbitfield >> i) & 1) == 0 }
  163. switch(message->getId()) {
  164. case PeerMessage::KEEP_ALIVE:
  165. case PeerMessage::CHOKE:
  166. case PeerMessage::UNCHOKE:
  167. case PeerMessage::INTERESTED:
  168. case PeerMessage::NOT_INTERESTED:
  169. break;
  170. case PeerMessage::HAVE:
  171. checkIndex(message, pieces);
  172. break;
  173. case PeerMessage::BITFIELD:
  174. checkBitfield(message, pieces);
  175. break;
  176. case PeerMessage::REQUEST:
  177. case PeerMessage::CANCEL:
  178. checkIndex(message, pieces);
  179. checkBegin(message, pieceLength);
  180. checkLength(message);
  181. checkPieceOffset(message, pieceLength, pieces, totalLength);
  182. break;
  183. case PeerMessage::PIECE:
  184. checkIndex(message, pieces);
  185. checkBegin(message, pieceLength);
  186. break;
  187. default:
  188. throw new DlAbortEx("invalid message id. id = %d", message->getId());
  189. }
  190. }
  191. HandshakeMessage* PeerMessageUtil::createHandshakeMessage(const char* msg) {
  192. HandshakeMessage* message = new HandshakeMessage();
  193. message->pstrlen = msg[0];
  194. char pstr[20];
  195. memcpy(pstr, &msg[1], sizeof(pstr)-1);
  196. pstr[sizeof(pstr)-1] = '\0';
  197. message->pstr = pstr;
  198. memcpy(message->infoHash, &msg[28], 20);
  199. memcpy(message->peerId, &msg[48], 20);
  200. return message;
  201. }
  202. void PeerMessageUtil::checkHandshake(const HandshakeMessage* message, const unsigned char* infoHash) {
  203. if(message->pstrlen != 19) {
  204. throw new DlAbortEx("invalid handshake pstrlen = %d", (int)message->pstrlen);
  205. }
  206. if(message->pstr != PSTR) {
  207. throw new DlAbortEx("invalid handshake pstr");
  208. }
  209. string myInfoHash = Util::toHex(infoHash, 20);
  210. string peerInfoHash = Util::toHex(message->infoHash, 20);
  211. if(myInfoHash != peerInfoHash) {
  212. throw new DlAbortEx("invalid handshake info hash: expected:%s, actual:%s",
  213. myInfoHash.c_str(), peerInfoHash.c_str());
  214. }
  215. }