diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 0d3f69b7e..b837ba469 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -194,8 +194,19 @@ void p3GxsTunnelService::flush() time_t now = time(NULL) ; - for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) + for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();) { + // Remove any tunnel that was remotely closed, since we cannot use it anymore. + + if(it->second.status == RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED && it->second.last_contact + 20 < now) + { + std::map::iterator tmp = it ; + ++tmp ; + _gxs_tunnel_contacts.erase(it) ; + it=tmp ; + continue ; + } + if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { #ifdef DEBUG_GXS_TUNNEL @@ -233,6 +244,7 @@ void p3GxsTunnelService::flush() std::cerr << "(II) GxsTunnelService:: Sending keep alive packet to gxs id " << it->first << std::endl; #endif } + ++it ; } } @@ -340,98 +352,98 @@ void p3GxsTunnelService::handleRecvTunnelDataItem(const RsGxsTunnelId& tunnel_id void p3GxsTunnelService::handleRecvStatusItem(const RsGxsTunnelId& tunnel_id, RsGxsTunnelStatusItem *cs) { - std::vector notifications ; - std::set clients ; + std::vector notifications ; + std::set clients ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; + std::cerr << "p3GxsTunnelService::handleRecvStatusItem(): tunnel_id=" << tunnel_id << " status=" << cs->status << std::endl; #endif - switch(cs->status) - { - case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + switch(cs->status) + { + case RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION: + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; - if(it == _gxs_tunnel_contacts.end()) - { - std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; - return ; - } + if(it == _gxs_tunnel_contacts.end()) + { + std::cerr << "(EE) Cannot mark tunnel connection as closed. No connection openned for tunnel id " << tunnel_id << ". Unexpected situation." << std::endl; + return ; + } - if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) - { + if(it->second.direction == RsTurtleGenericDataItem::DIRECTION_CLIENT) + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; + std::cerr << " This is server side. Marking distant chat as remotely closed for tunnel id " << tunnel_id << std::endl; #endif - it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; - notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; - } - } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. - break ; + it->second.status = RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED ; + notifications.push_back(RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED) ; + } + } // nothing more to do, because the decryption routing will update the last_contact time when decrypting. + break ; - case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: + case RS_GXS_TUNNEL_FLAG_KEEP_ALIVE: #ifdef DEBUG_GXS_TUNNEL - std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; + std::cerr << "GxsTunnelService::handleRecvGxsTunnelStatusItem(): received keep alive packet for inactive tunnel! peerId=" << cs->PeerId() << " tunnel=" << tunnel_id << std::endl; #endif - break ; + break ; - case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: - { + case RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION: + { #ifdef DEBUG_GXS_TUNNEL - std::cerr << "Received ACK item from the distant peer!" << std::endl; + std::cerr << "Received ACK item from the distant peer!" << std::endl; #endif - // in this case we notify the clients using this tunnel. + // in this case we notify the clients using this tunnel. - notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; - } - break ; + notifications.push_back(RS_GXS_TUNNEL_STATUS_CAN_TALK) ; + } + break ; - default: - std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; - break ; - } + default: + std::cerr << "(EE) unhandled tunnel status " << std::hex << cs->status << std::dec << std::endl; + break ; + } - // notify all clients + // notify all clients #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; + std::cerr << " notifying clients. Prending notifications: " << notifications.size() << std::endl; #endif - - if(notifications.size() > 0) - { - RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; + if(notifications.size() > 0) + { + RS_STACK_MUTEX(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; + std::cerr << " " << it->second.client_services.size() << " client services for tunnel id " << tunnel_id << std::endl; #endif - - for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) - { - std::map::const_iterator it3=mRegisteredServices.find(*it2) ; - if(it3 != mRegisteredServices.end()) - clients.insert(it3->second) ; - } - } + for(std::set::const_iterator it2(it->second.client_services.begin());it2!=it->second.client_services.end();++it2) + { + std::map::const_iterator it3=mRegisteredServices.find(*it2) ; + + if(it3 != mRegisteredServices.end()) + clients.insert(it3->second) ; + } + } #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying " << clients.size() << " clients." << std::endl; + std::cerr << " notifying " << clients.size() << " clients." << std::endl; #endif - - for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) - for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; + + for(std::set::const_iterator it(clients.begin());it!=clients.end();++it) + for(uint32_t i=0;inotifyTunnelStatus(tunnel_id,notifications[i]) ; #ifdef DEBUG_GXS_TUNNEL - std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; + std::cerr << " notifying client " << (void*)(*it) << " of status " << notifications[i] << std::endl; #endif - } + } } bool p3GxsTunnelService::handleTunnelRequest(const RsFileHash& hash,const RsPeerId& /*peer_id*/) @@ -1417,7 +1429,8 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin TurtleFileHash hash ; TurtleVirtualPeerId vpid ; - bool close_tunnel = false ; + bool close_tunnel = false ; + int direction ; { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; @@ -1432,49 +1445,49 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin } vpid = it->second.virtual_peer_id ; - if(it->second.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) // nothing more to do for server side. - return true ; - std::map::const_iterator it2 = _gxs_tunnel_virtual_peer_ids.find(vpid) ; if(it2 != _gxs_tunnel_virtual_peer_ids.end()) hash = it2->second.hash ; - - // check how many clients are used. If empty, close the tunnel - - std::set::iterator it3 = it->second.client_services.find(service_id) ; - - if(it3 == it->second.client_services.end()) - { - std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; - return false; - } - - it->second.client_services.erase(it3) ; - - if(it->second.client_services.empty()) - close_tunnel = true ; + + // check how many clients are used. If empty, close the tunnel + + std::set::iterator it3 = it->second.client_services.find(service_id) ; + + if(it3 == it->second.client_services.end()) + { + std::cerr << "(EE) service id not currently using that tunnel. This is an error." << std::endl; + return false; + } + + it->second.client_services.erase(it3) ; + direction = it->second.direction ; + + if(it->second.client_services.empty()) + close_tunnel = true ; } - if(!close_tunnel) - return true ; - - // send a status item saying that we're closing the connection + if(close_tunnel && direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER) // nothing more to do for server side. + { + // send a status item saying that we're closing the connection #ifdef DEBUG_GXS_TUNNEL - std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; + std::cerr << " Sending a ACK to close the tunnel since we're managing it and it's not used by any service. tunnel id=." << tunnel_id << std::endl; #endif - RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; + RsGxsTunnelStatusItem *cs = new RsGxsTunnelStatusItem ; - cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; - cs->PeerId(RsPeerId(tunnel_id)) ; + cs->status = RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION; + cs->PeerId(RsPeerId(tunnel_id)) ; - locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. + locked_sendEncryptedTunnelData(cs) ; // that needs to be done off-mutex and before we close the tunnel also ignoring failure. #ifdef DEBUG_GXS_TUNNEL - std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; + std::cerr << " This is client side. Stopping tunnel manageement for tunnel_id " << tunnel_id << std::endl; #endif - mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null + mTurtle->stopMonitoringTunnels( hash ) ; // still valid if the hash is null + } + + if(close_tunnel) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ std::map::iterator it = _gxs_tunnel_contacts.find(tunnel_id) ; @@ -1489,7 +1502,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id, uin // GxsTunnelService::removeVirtualPeerId() will be called by the turtle service. } - return true ; + return true ; } bool p3GxsTunnelService::getTunnelsInfo(std::vector &infos) diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 0aa3c0657..f8be00f33 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -104,7 +104,7 @@ void PopupDistantChatDialog::updateDisplay() { case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl; _status_label->setPixmap(QPixmap(IMAGE_GRY_LED)) ; - msg = tr("Hash Error. No tunnel."); + msg = tr("Chat remotely closed. Please close this window."); _status_label->setToolTip(msg) ; getChatWidget()->updateStatusString("%1", msg, true); getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel."));