Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Applied a new way of socket ID generation #1076

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 124 additions & 11 deletions srtcore/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ CUDTUnited::CUDTUnited():
m_Sockets(),
m_GlobControlLock(),
m_IDLock(),
m_SocketIDGenerator(0),
m_TLSError(),
m_mMultiplexer(),
m_MultiplexerLock(),
Expand All @@ -135,9 +134,15 @@ m_ClosedSockets()
// a static member s_ullCPUFrequency with dynamic initialization.
// The order of initialization is not guaranteed.
timeval t;

gettimeofday(&t, 0);
srand((unsigned int)t.tv_usec);
m_SocketIDGenerator = 1 + (int)((1 << 30) * (double(rand()) / RAND_MAX));

const double rand1_0 = double(rand())/RAND_MAX;

m_SocketIDGenerator = 1 + int(MAX_SOCKET_VAL * rand1_0);
m_SocketIDGenerator_init = m_SocketIDGenerator;


pthread_key_create(&m_TLSError, TLSDestroy);

Expand Down Expand Up @@ -247,9 +252,102 @@ int CUDTUnited::cleanup()
return 0;
}

SRTSOCKET CUDTUnited::newSocket()
SRTSOCKET CUDTUnited::generateSocketID()
{
CGuard guard(m_IDLock);

int sockval = m_SocketIDGenerator - 1;

// First problem: zero-value should be avoided by various reasons.

if (sockval <= 0)
{
// We have a rollover on the socket value, so
// definitely we haven't made the Columbus mistake yet.
m_SocketIDGenerator = MAX_SOCKET_VAL-1;
}

// Check all sockets if any of them has this value.
// Socket IDs are begin created this way:
//
// Initial random
// |
// |
// |
// |
// ...
// The only problem might be if the number rolls over
// and reaches the same value from the opposite side.
// This is still a valid socket value, but this time
// we have to check, which sockets have been used already.
if ( sockval == m_SocketIDGenerator_init )
{
// Mark that since this point on the checks for
// whether the socket ID is in use must be done.
m_SocketIDGenerator_init = 0;
}

// This is when all socket numbers have been already used once.
// This may happen after many years of running an application
// constantly when the connection breaks and gets restored often.
if ( m_SocketIDGenerator_init == 0 )
{
int startval = sockval;
for (;;) // Roll until an unused value is found
{
bool exists = false;
{
CGuard cg(m_GlobControlLock);
exists = m_Sockets.count(sockval);
}

if (exists)
{
// The socket value is in use.
--sockval;
if (sockval <= 0)
sockval = MAX_SOCKET_VAL-1;

// Before continuing, check if we haven't rolled back to start again
// This is virtually impossible, so just make an RTI error.
if (sockval == startval)
{
// Of course, we don't lack memory, but actually this is so impossible
// that a complete memory extinction is much more possible than this.
// So treat this rather as a formal fallback for something that "should
// never happen". This should make the socket creation functions, from
// socket_create and accept, return this error.

m_SocketIDGenerator = sockval+1; // so that any next call will cause the same error
throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
}

// try again, if this is a free socket
continue;
}

// No socket found, this ID is free to use
m_SocketIDGenerator = sockval;
break;
}
}
else
{
m_SocketIDGenerator = sockval;
}

// The socket value counter remains with the value rolled
// without the group bit set; only the returned value may have
// the group bit set.

return m_SocketIDGenerator;
}

SRTSOCKET CUDTUnited::newSocket()
{
// XXX consider using some replacement of std::unique_ptr
// so that exceptions will clean up the object without the
// need for a dedicated code.
CUDTSocket* ns = NULL;

try
Expand All @@ -263,10 +361,15 @@ SRTSOCKET CUDTUnited::newSocket()
throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
}

enterCS(m_IDLock);
ns->m_SocketID = -- m_SocketIDGenerator;
leaveCS(m_IDLock);

try
{
ns->m_SocketID = generateSocketID();
}
catch (...)
{
delete ns;
throw;
}
Comment on lines +368 to +372
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for catching any exception?
generateSocketID() only throws CUDTException
What are other possible exceptions?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a simple passthrough - whatever exception (altho' yes, currently it's only CUDTException) is thrown, it only gets intercepted here, but then propagated further.

This instruction simply intercepts everything and complements the logical requirements of this function. It doesn't take part in any exception handling at all. If you want to put any real name here, then it would be needed to be treated as this action is specific for the exception - whereas it's not. Whatever gets through it, the handling is completely general.

It's not the matter of being strict, it's the matter of level of details that this very function focuses on.

ns->m_Status = SRTS_INIT;
ns->m_ListenSocket = 0;
ns->m_pUDT->m_SocketID = ns->m_SocketID;
Expand Down Expand Up @@ -370,10 +473,20 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& peer,
return -1;
}

enterCS(m_IDLock);
ns->m_SocketID = -- m_SocketIDGenerator;
HLOGF(mglog.Debug, "newConnection: generated socket id %d", ns->m_SocketID);
leaveCS(m_IDLock);
try
{
ns->m_SocketID = generateSocketID();
}
catch (CUDTException& e)
{
maxsharabayko marked this conversation as resolved.
Show resolved Hide resolved
LOGF(mglog.Fatal, "newConnection: IPE: all sockets occupied? Last gen=%d", m_SocketIDGenerator);
// generateSocketID throws exception, which can be naturally handled
// when the call is derived from the API call, but here it's called
// internally in response to receiving a handshake. It must be handled
// here and turned into an erroneous return value.
delete ns;
return -1;
}

ns->m_ListenSocket = listen;
ns->m_pUDT->m_SocketID = ns->m_SocketID;
Expand Down
6 changes: 6 additions & 0 deletions srtcore/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,19 @@ friend class CRendezvousQueue;
private:
// void init();

SRTSOCKET generateSocketID();

private:
std::map<SRTSOCKET, CUDTSocket*> m_Sockets; // stores all the socket structures

srt::sync::Mutex m_GlobControlLock; // used to synchronize UDT API

srt::sync::Mutex m_IDLock; // used to synchronize ID generation

static const int32_t MAX_SOCKET_VAL = 1 << 29; // maximum value for a regular socket

SRTSOCKET m_SocketIDGenerator; // seed to generate a new unique socket ID
SRTSOCKET m_SocketIDGenerator_init; // Keeps track of the very first one

std::map<int64_t, std::set<SRTSOCKET> > m_PeerRec;// record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn

Expand Down