@@ -137,14 +137,10 @@ namespace detail {
137137
138138 // Check that this peer is seller,
139139 protocol_statemachine::ModeAnnounced m = a.modeAnnounced ();
140+
140141 assert (m != protocol_statemachine::ModeAnnounced::none);
141142
142- // and has good enough terms to warrant an invitation,
143- // then send invitation
144- if (m == protocol_statemachine::ModeAnnounced::sell && _terms.satisfiedBy (a.sellModeTerms ())) {
145- c->processEvent (protocol_statemachine::event::InviteSeller ());
146- std::cout << " Invited: " << IdToString (id) << std::endl;
147- }
143+ maybeInviteSeller (c);
148144 }
149145 }
150146
@@ -210,14 +206,68 @@ namespace detail {
210206 template <class ConnectionIdType >
211207 void Buying<ConnectionIdType>::remoteMessageOverflow(const ConnectionIdType & id) {
212208 std::clog << " Error: remoteMessageOverflow from seller connection " << id << std::endl;
209+
213210 removeConnection (id, DisconnectCause::seller_message_overflow);
211+
212+ // Notify state machine about deletion
213+ throw protocol_statemachine::exception::StateMachineDeletedException ();
214+ }
215+
216+ template <class ConnectionIdType >
217+ void Buying<ConnectionIdType>::sellerCompletedSpeedTest(const ConnectionIdType & id, bool successful) {
218+
219+ detail::Connection<ConnectionIdType> * c = _session->get (id);
220+
221+ if (!successful) {
222+ // Remove connection
223+ removeConnection (id, DisconnectCause::seller_failed_speed_test);
224+
225+ // Notify state machine about deletion
226+ throw protocol_statemachine::exception::StateMachineDeletedException ();
227+
228+ } else {
229+ // record completion time
230+ c->endingSpeedTest ();
231+
232+ if (!_session->speedTestPolicy ().disconnectIfSlow ()) {
233+ maybeInviteSeller (c);
234+ } else {
235+
236+ if (c->speedTestCompletedInLessThan (_session->speedTestPolicy ().maxTimeToRespond ())) {
237+ // Invite seller if they met the speedTestPolicy requirement
238+ maybeInviteSeller (c);
239+
240+ } else {
241+ // otherwise disconnect them
242+ removeConnection (id, DisconnectCause::seller_failed_speed_test);
243+
244+ // Notify state machine about deletion
245+ throw protocol_statemachine::exception::StateMachineDeletedException ();
246+ }
247+ }
248+
249+ }
250+
214251 }
215252
216253 template <class ConnectionIdType >
217254 void Buying<ConnectionIdType>::leavingState() {
218255
219256 // Prepare sellers before we interrupt with new mode
220257 politeSellerCompensation ();
258+
259+ // Reset speed testing state for all connections that have not completed a speed test
260+ // This is to ensure when the session comes back to buying mode it will make sure to send a speed test request
261+ // to sellers that have not completed yet.
262+ for (auto itr = _session->_connections .cbegin ();itr != _session->_connections .cend ();) {
263+ auto connection = itr->second ;
264+
265+ if (!connection->hasCompletedSpeedTest ()) {
266+ connection->abandonSpeedTest ();
267+ }
268+
269+ itr++;
270+ }
221271 }
222272
223273 template <class ConnectionIdType >
@@ -506,18 +556,36 @@ namespace detail {
506556
507557 detail::Connection<ConnectionIdType> * c = mapping.second ;
508558
509- // Check that this peer is seller,
510- protocol_statemachine::AnnouncedModeAndTerms a = c-> announcedModeAndTermsFromPeer ();
559+ maybeInviteSeller (c);
560+ }
511561
512- // and has good enough terms to warrant an invitation,
513- // then send invitation
514- if (a.modeAnnounced () == protocol_statemachine::ModeAnnounced::sell && _terms.satisfiedBy (a.sellModeTerms ())) {
562+ }
515563
516- c->processEvent (protocol_statemachine::event::InviteSeller ());
564+ template <class ConnectionIdType >
565+ void Buying<ConnectionIdType>::maybeInviteSeller(detail::Connection<ConnectionIdType> * c) const {
517566
518- std::cout << " Invited: " << IdToString (mapping.first ) << std::endl;
519- }
520- }
567+ assert (_session->_state == SessionState::started);
568+ assert (_state == BuyingState::sending_invitations);
569+
570+ // Check that this peer is seller,
571+ protocol_statemachine::AnnouncedModeAndTerms a = c->announcedModeAndTermsFromPeer ();
572+
573+ // Do not send invitations if peer is not announcing sell mode or has incompatible terms
574+ if (a.modeAnnounced () != protocol_statemachine::ModeAnnounced::sell || !_terms.satisfiedBy (a.sellModeTerms ())) {
575+ return ;
576+ }
577+
578+ // Does seller need to complete a speed test to be invited?
579+ if (_session->_speedTestPolicy .isEnabled () && !c->hasCompletedSpeedTest ()) {
580+ if (c->hasStartedSpeedTest ()) return ;
581+ c->startingSpeedTest (); // record starting time
582+ c->processEvent (protocol_statemachine::event::TestSellerSpeed (_session->_speedTestPolicy .payloadSize ()));
583+ return ;
584+ }
585+
586+ // Seller has previously completed a speed test/or no speed test was required.. invite them
587+ c->processEvent (protocol_statemachine::event::InviteSeller ());
588+ std::cout << " Invited: " << IdToString (c->connectionId ()) << std::endl;
521589 }
522590
523591 template <class ConnectionIdType >
@@ -590,8 +658,8 @@ namespace detail {
590658 void Buying<ConnectionIdType>::removeSeller(detail::Seller<ConnectionIdType> & s) {
591659 if (s.isGone ()) return ;
592660
593- // we must be downloading
594- assert (_state == BuyingState::downloading);
661+ // we must be downloading or just finish downloading
662+ assert (_state == BuyingState::downloading || _state == BuyingState::download_completed );
595663
596664 // If this seller has assigned piecees, then we must unassign them
597665 for (uint i = 0 ;i < _pieces.size ();i++) {
0 commit comments