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 ();