diff --git a/HTTPServer.cpp b/HTTPServer.cpp index b6ec3522..f7efcba9 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -749,7 +749,7 @@ namespace util s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">"; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; s << "Streams:
\r\n"; - for (auto it: session->sockets) + for (auto it: session->ListSockets()) { switch (it->GetSocketType ()) { diff --git a/SAM.cpp b/SAM.cpp index 7b493eb3..ecdd513d 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -47,16 +47,19 @@ namespace client break; case eSAMSocketTypeStream: { - if (m_Session) - m_Session->sockets.remove (shared_from_this ()); + if (m_Session) { + m_Session->DelSocket (shared_from_this ()); + m_Session = nullptr; + } break; } case eSAMSocketTypeAcceptor: { if (m_Session) { - m_Session->sockets.remove (shared_from_this ()); + m_Session->DelSocket (shared_from_this ()); m_Session->localDestination->StopAcceptingStreams (); + m_Session = nullptr; } break; } @@ -64,7 +67,7 @@ namespace client ; } m_SocketType = eSAMSocketTypeTerminated; - m_Socket.close (); + if (m_Socket.is_open()) m_Socket.close (); } void SAMSocket::ReceiveHandshake () @@ -369,7 +372,7 @@ namespace client void SAMSocket::Connect (std::shared_ptr remote) { m_SocketType = eSAMSocketTypeStream; - m_Session->sockets.push_back (shared_from_this ()); + m_Session->AddSocket (shared_from_this ()); m_Stream = m_Session->localDestination->CreateStream (remote); m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect I2PReceive (); @@ -402,7 +405,7 @@ namespace client if (!m_Session->localDestination->IsAcceptingStreams ()) { m_SocketType = eSAMSocketTypeAcceptor; - m_Session->sockets.push_back (shared_from_this ()); + m_Session->AddSocket (shared_from_this ()); m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1)); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); } @@ -676,19 +679,20 @@ namespace client SAMSession::~SAMSession () { - for (auto it: sockets) - it->SetSocketType (eSAMSocketTypeTerminated); + CloseStreams(); i2p::client::context.DeleteLocalDestination (localDestination); } void SAMSession::CloseStreams () { - for (auto it: sockets) - { - it->CloseStream (); - it->SetSocketType (eSAMSocketTypeTerminated); - } - sockets.clear (); + { + std::lock_guard lock(m_SocketsMutex); + for (auto sock : m_Sockets) { + sock->CloseStream(); + } + } + // XXX: should this be done inside locked parts? + m_Sockets.clear(); } SAMBridge::SAMBridge (const std::string& address, int port): diff --git a/SAM.h b/SAM.h index 07142c8c..4cdea686 100644 --- a/SAM.h +++ b/SAM.h @@ -134,7 +134,30 @@ namespace client struct SAMSession { std::shared_ptr localDestination; - std::list > sockets; + std::list > m_Sockets; + std::mutex m_SocketsMutex; + + /** safely add a socket to this session */ + void AddSocket(std::shared_ptr sock) { + std::lock_guard lock(m_SocketsMutex); + m_Sockets.push_back(sock); + } + + /** safely remove a socket from this session */ + void DelSocket(std::shared_ptr sock) { + std::lock_guard lock(m_SocketsMutex); + m_Sockets.remove(sock); + } + + /** get a list holding a copy of all sam sockets from this session */ + std::list > ListSockets() { + std::list > l; + { + std::lock_guard lock(m_SocketsMutex); + for( auto & sock : m_Sockets ) l.push_back(sock); + } + return l; + } SAMSession (std::shared_ptr dest); ~SAMSession ();