Skip to content

Commit

Permalink
[core] A new way of socket ID generation (#1076)
Browse files Browse the repository at this point in the history
  • Loading branch information
ethouris authored and maxsharabayko committed Jan 23, 2020
1 parent 712119f commit 4f41130
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 11 deletions.
135 changes: 124 additions & 11 deletions srtcore/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ CUDTUnited::CUDTUnited():
m_Sockets(),
m_GlobControlLock(),
m_IDLock(),
m_SocketIDGenerator(0),
m_TLSError(),
m_mMultiplexer(),
m_MultiplexerLock(),
Expand All @@ -174,9 +173,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 @@ -286,9 +291,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 @@ -302,10 +400,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;
}
ns->m_Status = SRTS_INIT;
ns->m_ListenSocket = 0;
ns->m_pUDT->m_SocketID = ns->m_SocketID;
Expand Down Expand Up @@ -414,10 +517,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 (const CUDTException& e)
{
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 @@ -235,13 +235,19 @@ friend class CRendezvousQueue;
private:
// void init();

SRTSOCKET generateSocketID();

private:
typedef std::map<SRTSOCKET, CUDTSocket*> sockets_t; // stores all the socket structures
sockets_t m_Sockets;
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

0 comments on commit 4f41130

Please sign in to comment.