Remember the last time when the peer was unchoked.
[tairent.git] / src / main / connection.cpp
blob11805065d40d0e5aaec6426437e0d2cab49b10d1
1 /***************************************************************************
2 * *
3 * Copyright (C) 2006 David Brodsky *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation and appearing *
8 * in the file LICENSE.GPL included in the packaging of this file. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * General Public License for more details. *
14 * *
15 ***************************************************************************/
17 #include <arpa/inet.h>
19 #include <tairon/core/log.h>
20 #include <tairon/core/thread.h>
21 #include <tairon/net/ireader.h>
22 #include <tairon/net/limiter.h>
23 #include <tairon/net/socket.h>
24 #include <tairon/net/swriter.h>
25 #include <tairon/net/timer.h>
27 #include "connection.h"
29 #include "core/bencode.h"
30 #include "core/bitfield.h"
31 #include "ratemeasurer.h"
32 #include "storage.h"
33 #include "torrentclient.h"
34 #include "torrentmanager.h"
35 #include "torrentserver.h"
37 namespace Tairent
40 namespace Main
43 const unsigned int handshakeLength = 48; // without peer id
44 const char *protocolName = "BitTorrent protocol";
46 Tairon::Net::Limiter *rlimiter = 0;
47 Tairon::Net::Limiter *wlimiter = 0;
49 /* {{{ Connection::Connection(int) */
50 Connection::Connection(int fd) : bitfield(0), choked(true), client(0), commandReader(0), deleteReader(true), interested(false), lastPieceTime(0), lengthReader(0), peerChoked(true), peerInterested(false), pieceReaders(0), pieceWriters(0), reader(0)
52 socket = new Tairon::Net::Socket(fd);
53 init();
55 incomingRate = new RateMeasurer(10);
56 outgoingRate = new RateMeasurer(10);
58 /* }}} */
60 /* {{{ Connection::Connection(const String &, uint16_t, const String &, TorrentClient *) */
61 Connection::Connection(const String &ip, uint16_t port, const String &pID, TorrentClient *c) : bitfield(0), choked(true), client(c), commandReader(0), deleteReader(true), interested(false), lastPieceTime(0), lengthReader(0), peerChoked(true), peerID(pID), peerInterested(false), pieceReaders(0), pieceWriters(0), reader(0)
63 Tairon::Core::Thread *current = Tairon::Core::Thread::current();
65 socket = new Tairon::Net::Socket(Tairon::Net::Socket::Stream);
66 socket->connectedSignal.connect(Tairon::Core::threadMethodDFunctor(current, this, &Connection::socketConnected));
67 socket->errorSignal.connect(Tairon::Core::threadMethodDFunctor(current, this, &Connection::connectingError));
69 incomingRate = new RateMeasurer(10);
70 outgoingRate = new RateMeasurer(10);
72 socket->connect(ip, port);
74 /* }}} */
76 /* {{{ Connection::~Connection() */
77 Connection::~Connection()
79 delete incomingRate;
80 delete outgoingRate;
81 delete bitfield;
82 if (deleteReader)
83 delete reader;
84 delete commandReader;
85 delete lengthReader;
86 delete pieceReaders;
87 delete pieceWriters;
89 for (std::list<Tairon::Net::Writer *>::const_iterator it = commandQueue.begin(); it != commandQueue.end(); ++it)
90 delete *it;
92 /* }}} */
94 /* {{{ Connection::readBitField(Tairon::Net::Reader *) */
95 void Connection::readBitField(Tairon::Net::Reader *)
97 DEBUG("bitfield read");
98 bitfield = new Tairent::Core::BitField(reader->getBuffer(), client->getMetaInfo()["info"]["pieces"].asString().length() / 20);
99 delete reader;
100 reader = lengthReader;
101 deleteReader = false;
103 client->gotBitField(this);
105 /* }}} */
107 /* {{{ Connection::readCancel(Tairon::Net::Reader *) */
108 void Connection::readCancel(Tairon::Net::Reader *)
110 uint32_t index = htonl(*(uint32_t *) reader->getBuffer());
111 uint32_t start = htonl(*(uint32_t *) (reader->getBuffer() + 4));
113 for (std::list<PieceRequestStruct>::iterator it = peersRequests.begin(); it != peersRequests.end(); ++it)
114 if ((it->index == index) && (it->start == start)) {
115 peersRequests.erase(it);
116 break;
119 delete reader;
120 reader = lengthReader;
121 deleteReader = false;
123 /* }}} */
125 /* {{{ Connection::readCommand(Tairon::Net::Reader *) */
126 void Connection::readCommand(Tairon::Net::Reader *)
128 commandReader->reset();
129 switch (*reader->getBuffer()) {
130 case 0:
131 DEBUG("choke");
132 reader = lengthReader;
133 if (choked) // we're already choked
134 break;
135 choked = true;
136 client->gotChoke(this);
137 break;
138 case 1:
139 DEBUG("unchoke");
140 reader = lengthReader;
141 if (!choked) // we're already unchoked
142 break;
143 choked = false;
144 client->gotUnchoke(this);
145 break;
146 case 2:
147 DEBUG("interested");
148 reader = lengthReader;
149 peerInterested = true;
150 client->gotInterestedChange(this);
151 break;
152 case 3:
153 DEBUG("not interested");
154 reader = lengthReader;
155 peerInterested = false;
156 client->gotInterestedChange(this);
157 break;
158 case 4:
159 DEBUG("have");
160 reader = new Tairon::Net::IReader(4, socket, rlimiter);
161 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readHave));
162 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
163 deleteReader = true;
164 break;
165 case 5:
166 DEBUG("bitfield");
167 close();
168 closedSignal.emit(this);
169 return;
170 case 6:
171 DEBUG("request");
172 reader = new Tairon::Net::IReader(12, socket, rlimiter);
173 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readRequest));
174 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
175 deleteReader = true;
176 break;
177 case 7:
178 DEBUG("piece");
179 reader = new Tairon::Net::IReader(8, socket, rlimiter);
180 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readPiece));
181 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
182 lastPieceTime = Tairon::Net::Timer::currentTime();
183 deleteReader = true;
184 break;
185 case 8:
186 DEBUG("cancel");
187 reader = new Tairon::Net::IReader(8, socket, rlimiter);
188 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readCancel));
189 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
190 deleteReader = true;
191 break;
192 default:
193 DEBUG((const char *) String("unknown message" + String::number(*reader->getBuffer())));
194 close();
195 closedSignal.emit(this);
198 /* }}} */
200 /* {{{ Connection::readFirstCommand(Tairon::Net::Reader *) */
201 void Connection::readFirstCommand(Tairon::Net::Reader *)
203 commandReader->bufferFullSignal.clear();
204 commandReader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readCommand));
205 commandReader->reset();
207 if (*reader->getBuffer() == 5) { // bitfield
208 DEBUG("bitfield");
210 // check if the peer isn't sending fake data
211 uint32_t len = client->getMetaInfo()["info"]["pieces"].asString().length() / 20;
212 if ((commandLength - 1) != (len / 8 + (len % 8 ? 1 : 0))) {
213 ERROR("Peer sent an invalid bitfield length");
214 socket->close();
215 closedSignal.emit(this);
216 return;
219 reader = new Tairon::Net::IReader(commandLength - 1, socket, rlimiter);
220 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readBitField));
221 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
223 deleteReader = true;
224 } else {
225 bitfield = new Tairent::Core::BitField(client->getMetaInfo()["info"]["pieces"].asString().length() / 20);
226 readCommand(reader);
229 /* }}} */
231 /* {{{ Connection::readHandshake(Tairon::Net::Reader *) */
232 void Connection::readHandshake(Tairon::Net::Reader *)
234 DEBUG("got handshake 1");
236 const char *buffer = reader->getBuffer();
238 // check the protocol length (in the case that reader emitted
239 // bufferFullSignal instead of dataReadSignal.
240 if (*buffer != 19) {
241 WARNING("Invalid protocol length");
242 close();
243 closedSignal.emit(this);
244 return;
247 if (strstr(buffer + 1, protocolName) != (buffer + 1)) { // invalid protocol name
248 WARNING("Invalid protocol name");
249 close();
250 closedSignal.emit(this);
251 return;
254 DEBUG("Protocol ok");
256 if (!client) {
257 String infoHash(buffer + 28, 20);
258 DEBUG("sending handshake");
259 client = TorrentManager::self()->getClient(infoHash);
260 if (!client) {
261 WARNING("Got unknown infohash");
262 close();
263 closedSignal.emit(this);
264 return;
266 sendHandshake(infoHash);
269 delete reader;
271 reader = new Tairon::Net::IReader(20, socket, rlimiter);
272 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readPeerID));
273 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
275 /* }}} */
277 /* {{{ Connection::readHave(Tairon::Net::Reader *) */
278 void Connection::readHave(Tairon::Net::Reader *)
280 uint32_t index = htonl(*(uint32_t *) reader->getBuffer());
282 if (index > bitfield->getLength()) {
283 WARNING("Peer sent invalid have index");
284 close();
285 closedSignal.emit(this);
286 return;
289 delete reader;
290 reader = lengthReader;
291 deleteReader = false;
293 bitfield->setBit(index);
294 client->gotHave(index, this);
296 /* }}} */
298 /* {{{ Connection::readLength(Tairon::Net::Reader *) */
299 void Connection::readLength(Tairon::Net::Reader *)
301 commandLength = ntohl(*(uint32_t *) lengthReader->getBuffer());
302 DEBUG((const char *) String("Got message of length " + String::number(commandLength)));
304 lengthReader->reset();
306 if (commandLength)
307 reader = commandReader;
308 // else keepalive
310 /* }}} */
312 /* {{{ Connection::readPeerID(Tairon::Net::Reader *) */
313 void Connection::readPeerID(Tairon::Net::Reader *)
315 DEBUG("got peer id");
316 String pID(reader->getBuffer(), 20);
318 if (peerID.length() && (peerID != pID)) { // we are connecting to a peer and it's ID doesn't match
319 WARNING("Peer's ID doesn't match");
320 close();
321 closedSignal.emit(this);
322 return;
325 delete reader;
327 lengthReader = new Tairon::Net::IReader(4, socket, rlimiter);
328 lengthReader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readLength));
329 lengthReader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
331 commandReader = new Tairon::Net::IReader(1, socket, rlimiter);
332 commandReader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readFirstCommand));
333 commandReader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
335 reader = lengthReader;
336 deleteReader = false;
338 TorrentServer::self()->connectionCompleted(this);
339 client->newConnection(this);
341 /* }}} */
343 /* {{{ Connection::readPiece(Tairon::Net::Reader *) */
344 void Connection::readPiece(Tairon::Net::Reader *)
346 pieceIndex = ntohl(*(uint32_t *) reader->getBuffer());
347 pieceStart = ntohl(*(uint32_t *) (reader->getBuffer() + 4));
348 delete reader;
350 std::set<uint32_t> &r = requests[pieceIndex];
351 r.erase(pieceStart);
352 if (!r.size())
353 requests.erase(pieceIndex);
355 deleteReader = false;
356 client->gotPiece(pieceIndex, pieceStart, this);
358 /* }}} */
360 /* {{{ Connection::readProtocolLength(Tairon::Net::Reader *, size_t) */
361 void Connection::readProtocolLength(Tairon::Net::Reader *, size_t)
363 if (*reader->getBuffer() != 19) { // length of the protocol name
364 WARNING("Invalid protocol length");
365 close();
366 closedSignal.emit(this);
367 return;
370 reader->dataReadSignal.clear();
372 /* }}} */
374 /* {{{ Connection::readRequest(Tairon::Net::Reader *) */
375 void Connection::readRequest(Tairon::Net::Reader *)
377 if (peerChoked) // don't send anything to the choked peer
378 return;
380 PieceRequestStruct rs;
381 rs.index = htonl(*(uint32_t *) reader->getBuffer());
382 rs.start = htonl(*(uint32_t *) (reader->getBuffer() + 4));
383 rs.length = htonl(*(uint32_t *) (reader->getBuffer() + 8));
385 if (rs.length > 16384) {
386 WARNING((const char *) String("Client requested too big chunk: " + String::number(rs.length)));
387 close();
388 closedSignal.emit(this);
389 return;
392 delete reader;
393 reader = lengthReader;
394 deleteReader = false;
396 if (pieceWriters || commandQueue.size()) // we are sending something
397 peersRequests.push_back(rs);
398 else
399 client->getStorage()->gotRequest(rs.index, rs.start, rs.length, this);
401 /* }}} */
403 /* {{{ Connection::readyRead(Tairon::Net::Socket *) */
404 void Connection::readyRead(Tairon::Net::Socket *)
406 try {
407 reader->read();
408 } catch (const Tairon::Net::SocketException &) { // connection closed or other error
409 close();
410 closedSignal.emit(this);
413 /* }}} */
415 /* {{{ Connection::readyWrite(Tairon::Net::Socket *) */
416 void Connection::readyWrite(Tairon::Net::Socket *)
418 if (pieceWriters)
419 pieceWriters->writers.front()->write();
420 else
421 commandQueue.front()->write();
423 /* }}} */
425 /* {{{ Connection::addCommandWriter(Tairon::Net::Writer *) */
426 void Connection::addCommandWriter(Tairon::Net::Writer *writer)
428 commandQueue.push_back(writer);
429 if ((commandQueue.size() == 1) && !pieceWriters) // don't send anything if we are sending something
430 writer->write();
432 /* }}} */
434 /* {{{ Connection::connectingError(Tairon::Net::Socket *, int) */
435 void Connection::connectingError(Tairon::Net::Socket *, int)
437 socket->close();
438 client->connectingFailed(this);
440 /* }}} */
442 /* {{{ Connection::close() */
443 void Connection::close()
445 socket->close();
447 /* }}} */
449 /* {{{ Connection::clearRequested() */
450 void Connection::clearRequested()
452 requests.clear();
454 /* }}} */
456 /* {{{ Connection::dataWritten(Tairon::Net::Writer *) */
457 void Connection::dataWritten(Tairon::Net::Writer *writer)
459 DEBUG("dataWritten");
461 Tairon::Net::Writer *w = commandQueue.front();
462 if (w == writer) // is this writer in the queue?
463 commandQueue.pop_front(); // remove it
464 delete writer;
466 if (commandQueue.size()) // are there some commands to send?
467 commandQueue.front()->write();
468 else if (peersRequests.size()) { // let's try to send some piece
469 PieceRequestStruct rs = peersRequests.front();
470 peersRequests.pop_front();
471 client->getStorage()->gotRequest(rs.index, rs.start, rs.length, this);
474 /* }}} */
476 /* {{{ Connection::destroyPieceReaders() */
477 void Connection::destroyPieceReaders()
479 if (!pieceReaders)
480 return;
482 for (std::list<Tairon::Net::Reader *>::iterator it = pieceReaders->readers.begin(); it != pieceReaders->readers.end(); ++it)
483 delete *it;
484 delete pieceReaders;
485 pieceReaders = 0;
487 /* }}} */
489 /* {{{ Connection::destroyPieceWriters() */
490 void Connection::destroyPieceWriters()
492 if (!pieceWriters)
493 return;
495 for (std::list<Tairon::Net::Writer *>::iterator it = pieceWriters->writers.begin(); it != pieceWriters->writers.end(); ++it)
496 delete *it;
497 delete pieceWriters;
498 pieceWriters = 0;
500 /* }}} */
502 /* {{{ Connection::getIncomingRate() */
503 double Connection::getIncomingRate()
505 return incomingRate->getRate();
507 /* }}} */
509 /* {{{ Connection::getOutgoingRate() */
510 double Connection::getOutgoingRate()
512 return outgoingRate->getRate();
514 /* }}} */
516 /* {{{ Connection::getPieceLength() */
517 uint32_t Connection::getPieceLength()
519 // 1 byte message type, 4 bytes index, 4 bytes start
520 return commandLength - 9;
522 /* }}} */
524 /* {{{ Connection::getReadingLimiter() */
525 Tairon::Net::Limiter *Connection::getReadingLimiter()
527 return rlimiter;
529 /* }}} */
531 /* {{{ Connection::getRequestsCount() */
532 unsigned int Connection::getRequestsCount()
534 unsigned int ret = 0;
535 for (std::map<uint32_t, std::set<uint32_t> >::const_iterator it = requests.begin(); it != requests.end(); ++it)
536 ret += it->second.size();
537 return ret;
539 /* }}} */
541 /* {{{ Connection::getWritingLimiter() */
542 Tairon::Net::Limiter *Connection::getWritingLimiter()
544 return wlimiter;
546 /* }}} */
548 /* {{{ Connection::init() */
549 void Connection::init()
551 Tairon::Core::Thread *current = Tairon::Core::Thread::current();
553 socket->errorSignal.connect(Tairon::Core::threadMethodDFunctor(current, this, &Connection::socketError));
554 socket->readyReadSignal.connect(Tairon::Core::threadMethodDFunctor(current, this, &Connection::readyRead));
555 socket->readyWriteSignal.connect(Tairon::Core::threadMethodDFunctor(current, this, &Connection::readyWrite));
556 socket->ready();
558 reader = new Tairon::Net::IReader(handshakeLength, socket, rlimiter);
559 reader->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readHandshake));
560 // it is safe to do this, we just want to check the first byte
561 reader->dataReadSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readProtocolLength));
562 reader->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
564 /* }}} */
566 /* {{{ Connection::isSnubbed() */
567 bool Connection::isSnubbed()
569 return Tairon::Net::Timer::currentTime() - lastPieceTime > 10000; // 10 seconds, should be configurable
571 /* }}} */
573 /* {{{ Connection::pieceDataWritten(Tairon::Net::Writer *) */
574 void Connection::pieceDataWritten(Tairon::Net::Writer *writer)
576 pieceWriters->writers.pop_front();
578 if (pieceWriters->writers.size()) { // there is still something to send from the piece
579 delete writer; // delete the current writer
580 pieceWriters->writers.front()->write();
581 } else { // whole piece has been sent
582 outgoingRate->update(pieceWriters->length);
583 client->pieceSent(pieceWriters->index, pieceWriters->length, this);
584 // the last piece's writer will be deleted in dataWritten() method
585 delete pieceWriters;
586 pieceWriters = 0;
588 dataWritten(writer);
591 /* }}} */
593 /* {{{ Connection::readerError(Tairon::Net::Reader *, Tairon::Net::Socket *) */
594 void Connection::readerError(Tairon::Net::Reader *, Tairon::Net::Socket *)
596 closedSignal.emit(this);
598 /* }}} */
600 /* {{{ Connection::sendChoke() */
601 void Connection::sendChoke()
603 DEBUG("sending choke");
605 if (peerChoked)
606 return;
608 peersRequests.clear();
610 peerChoked = true;
611 Tairon::Net::SWriter *writer = new Tairon::Net::SWriter(String("\x00\x00\x00\x01\x00", 5), socket, wlimiter);
612 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
613 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
615 addCommandWriter(writer);
617 /* }}} */
619 /* {{{ Connection::sendHandshake(const String &) */
620 void Connection::sendHandshake(const String &infoHash)
622 char handshake[68];
623 handshake[0] = (char) 19;
624 memcpy(handshake + 1, protocolName, 19);
625 memset(handshake + 20, 0, 8);
626 memcpy(handshake + 28, infoHash.data(), 20);
627 memcpy(handshake + 48, TorrentManager::self()->getClientID().data(), 20);
629 String h(handshake, 68);
631 Tairon::Net::Writer *writer = new Tairon::Net::SWriter(h, socket, wlimiter);
632 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
633 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
635 addCommandWriter(writer);
637 if (client->getStorage()->hasSomething()) { // we have already downloaded some piece, send bitfield as well
638 DEBUG("sending bitfield");
639 // count length of the bitfield
640 size_t length = client->getStorage()->getBitField()->getLength();
641 length = length / 8 + (length % 8 ? 1 : 0);
643 char *bf = new char[5 + length];
645 uint32_t l = htonl(1 + length); // 1 byte message type, rest is bitfield
646 memcpy(bf, (const char *) (&l), 4);
647 bf[4] = 5; // bitfield message
648 memcpy(bf + 5, client->getStorage()->getBitField()->getData(), length);
650 String b(bf, 5 + length);
651 writer = new Tairon::Net::SWriter(b, socket, wlimiter);
652 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
653 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
655 addCommandWriter(writer);
657 delete [] bf;
660 /* }}} */
662 /* {{{ Connection::sendHave(uint32_t) */
663 void Connection::sendHave(uint32_t index)
665 DEBUG("sending have");
667 uint32_t i = htonl(index);
668 Tairon::Net::SWriter *writer = new Tairon::Net::SWriter(String("\x00\x00\x00\x05\x04", 5) + String((const char *) (&i), 4), socket, wlimiter);
669 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
670 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
672 addCommandWriter(writer);
674 /* }}} */
676 /* {{{ Connection::sendInterested() */
677 void Connection::sendInterested()
679 DEBUG("sending interested");
681 if (interested)
682 return;
684 interested = true;
685 Tairon::Net::SWriter *writer = new Tairon::Net::SWriter(String("\x00\x00\x00\x01\x02", 5), socket, wlimiter);
686 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
687 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
689 addCommandWriter(writer);
691 /* }}} */
693 /* {{{ Connection::sendNotInterested() */
694 void Connection::sendNotInterested()
696 DEBUG("sending not interested");
698 if (!interested)
699 return;
701 interested = false;
702 Tairon::Net::SWriter *writer = new Tairon::Net::SWriter(String("\x00\x00\x00\x01\x03", 5), socket, wlimiter);
703 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
704 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
706 addCommandWriter(writer);
708 /* }}} */
710 /* {{{ Connection::sendRequest(uint32_t, uint32_t, uint32_t) */
711 void Connection::sendRequest(uint32_t index, uint32_t start, uint32_t length)
713 requests[index].insert(start);
715 char msg[17];
716 memcpy(msg, "\x00\x00\x00\x0d\x06", 5);
717 *(uint32_t *) (msg + 5) = htonl(index);
718 *(uint32_t *) (msg + 9) = htonl(start);
719 *(uint32_t *) (msg + 13) = htonl(length);
721 Tairon::Net::SWriter *writer = new Tairon::Net::SWriter(String(msg, 17), socket, wlimiter);
722 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
723 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
725 addCommandWriter(writer);
727 /* }}} */
729 /* {{{ Connection::sendUnchoke(int) */
730 void Connection::sendUnchoke(int time)
732 DEBUG("sending unchoke");
734 if (!peerChoked)
735 return;
737 unchokeTime = time;
739 peerChoked = false;
740 Tairon::Net::SWriter *writer = new Tairon::Net::SWriter(String("\x00\x00\x00\x01\x01", 5), socket, wlimiter);
741 writer->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::dataWritten));
742 writer->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
744 addCommandWriter(writer);
746 /* }}} */
748 /* {{{ Connection::setNextReader(Tairon::Net::Reader *) */
749 void Connection::setNextReader(Tairon::Net::Reader *)
751 delete pieceReaders->readers.front();
752 pieceReaders->readers.pop_front();
754 if (pieceReaders->readers.size()) {
755 DEBUG("Setting next piece reader");
756 reader = pieceReaders->readers.front();
757 } else {
758 DEBUG("Piece downloaded");
760 incomingRate->update(pieceReaders->length);
762 bool fake = pieceReaders->fake;
763 delete pieceReaders;
764 pieceReaders = 0;
765 reader = lengthReader;
766 deleteReader = false;
767 if (!fake)
768 client->pieceDownloaded(pieceIndex, pieceStart, this);
771 /* }}} */
773 /* {{{ Connection::setReaders(PieceReadersStruct *) */
774 void Connection::setReaders(PieceReadersStruct *readers)
776 for (std::list<Tairon::Net::Reader *>::iterator it = readers->readers.begin(); it != readers->readers.end(); ++it) {
777 (*it)->bufferFullSignal.connect(Tairon::Core::methodFunctor(this, &Connection::setNextReader));
778 (*it)->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::readerError));
780 pieceReaders = readers;
781 reader = pieceReaders->readers.front();
783 /* }}} */
785 /* {{{ Connection::setWriters(PieceWritersStruct *) */
786 void Connection::setWriters(PieceWritersStruct *writers)
788 for (std::list<Tairon::Net::Writer *>::iterator it = writers->writers.begin(); it != writers->writers.end(); ++it) {
789 (*it)->dataWrittenSignal.connect(Tairon::Core::methodFunctor(this, &Connection::pieceDataWritten));
790 (*it)->errorSignal.connect(Tairon::Core::methodFunctor(this, &Connection::writerError));
793 pieceWriters = writers;
794 writers->writers.front()->write();
796 /* }}} */
798 /* {{{ Connection::socketConnected(Tairon::Net::Socket *) */
799 void Connection::socketConnected(Tairon::Net::Socket *)
801 socket->connectedSignal.clear();
802 socket->errorSignal.clear();
804 init();
806 sendHandshake(client->getInfoHash());
808 /* }}} */
810 /* {{{ Connection::socketError(Tairon::Net::Socket *, int) */
811 void Connection::socketError(Tairon::Net::Socket *, int)
813 socket->close();
814 closedSignal.emit(this);
816 /* }}} */
818 /* {{{ Connection::writerError(Tairon::Net::Writer *, Tairon::Net::Socket *) */
819 void Connection::writerError(Tairon::Net::Writer *, Tairon::Net::Socket *)
821 closedSignal.emit(this);
823 /* }}} */
825 }; // namespace Main
827 }; // namespace Tairent
829 // vim: ai sw=4 ts=4 noet fdm=marker