272 lines
7.3 KiB
C++
272 lines
7.3 KiB
C++
/*
|
|
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "udp_socket_manager_windows.h"
|
|
#include "udp_socket_windows.h"
|
|
|
|
namespace webrtc {
|
|
WebRtc_UWord32 UdpSocketManagerWindows::_numOfActiveManagers = 0;
|
|
|
|
UdpSocketManagerWindows::UdpSocketManagerWindows(
|
|
const WebRtc_Word32 id,
|
|
WebRtc_UWord8& numOfWorkThreads)
|
|
: _id(id),
|
|
UdpSocketManager(id, numOfWorkThreads)
|
|
{
|
|
const WebRtc_Word8* threadName = "UdpSocketManagerWindows_Thread";
|
|
_critSectList = CriticalSectionWrapper::CreateCriticalSection();
|
|
_thread = ThreadWrapper::CreateThread(UdpSocketManagerWindows::Run,
|
|
this, kRealtimePriority, threadName);
|
|
FD_ZERO(&_readFds);
|
|
FD_ZERO(&_writeFds);
|
|
FD_ZERO(&_exceptFds);
|
|
_numOfActiveManagers++;
|
|
}
|
|
|
|
UdpSocketManagerWindows::~UdpSocketManagerWindows()
|
|
{
|
|
if(_thread != NULL)
|
|
{
|
|
delete _thread;
|
|
}
|
|
|
|
if (_critSectList != NULL)
|
|
{
|
|
_critSectList->Enter();
|
|
|
|
while(!_socketMap.empty())
|
|
{
|
|
std::map<SOCKET, UdpSocketWindows*>::iterator it =
|
|
_socketMap.begin();
|
|
UdpSocketWindows* s = static_cast<UdpSocketWindows*>(it->second);
|
|
_socketMap.erase(it);
|
|
delete s;
|
|
}
|
|
_removeList.erase(_removeList.begin(), _removeList.end());
|
|
|
|
while(!_addList.empty())
|
|
{
|
|
std::list<UdpSocketWindows*>::iterator it = _addList.begin();
|
|
UdpSocketWindows* s = static_cast<UdpSocketWindows*>(*it);
|
|
_addList.erase(it);
|
|
delete s;
|
|
}
|
|
_critSectList->Leave();
|
|
|
|
delete _critSectList;
|
|
}
|
|
|
|
_numOfActiveManagers--;
|
|
|
|
if (_numOfActiveManagers == 0)
|
|
WSACleanup();
|
|
}
|
|
|
|
WebRtc_Word32 UdpSocketManagerWindows::ChangeUniqueId(const WebRtc_Word32 id)
|
|
{
|
|
_id = id;
|
|
return 0;
|
|
}
|
|
|
|
bool UdpSocketManagerWindows::Start()
|
|
{
|
|
unsigned int id;
|
|
if (_thread == NULL)
|
|
return false;
|
|
|
|
return _thread->Start(id);
|
|
}
|
|
|
|
bool UdpSocketManagerWindows::Stop()
|
|
{
|
|
if (_thread == NULL)
|
|
return true;
|
|
|
|
return _thread->Stop();
|
|
}
|
|
|
|
bool UdpSocketManagerWindows::Process()
|
|
{
|
|
bool doSelect = false;
|
|
// Timeout = 1 second.
|
|
timeval timeout;
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 10000;
|
|
|
|
FD_ZERO(&_readFds);
|
|
FD_ZERO(&_writeFds);
|
|
FD_ZERO(&_exceptFds);
|
|
|
|
_critSectList->Enter();
|
|
// Remove sockets that have been registered for removal.
|
|
while(!_removeList.empty())
|
|
{
|
|
SOCKET id = *_removeList.begin();
|
|
std::map<SOCKET, UdpSocketWindows*>::iterator it = _socketMap.find(id);
|
|
if(it != _socketMap.end())
|
|
{
|
|
UdpSocketWindows* s = static_cast<UdpSocketWindows*>(it->second);
|
|
_socketMap.erase(it);
|
|
_removeList.pop_front();
|
|
delete s;
|
|
}
|
|
}
|
|
|
|
// Add sockets that have been registered for being added.
|
|
while (!_addList.empty())
|
|
{
|
|
UdpSocketWindows* s = *_addList.begin();
|
|
if(s)
|
|
{
|
|
_socketMap[s->GetFd()] = s;
|
|
}
|
|
_addList.pop_front();
|
|
}
|
|
_critSectList->Leave();
|
|
|
|
std::map<SOCKET, UdpSocketWindows*>::iterator it = _socketMap.begin();
|
|
while(it != _socketMap.end())
|
|
{
|
|
UdpSocketWindows* s = it->second;
|
|
if (s->WantsIncoming())
|
|
{
|
|
doSelect = true;
|
|
FD_SET(it->first, &_readFds);
|
|
}
|
|
if(!s->IsWritable())
|
|
{
|
|
FD_SET(it->first, &_writeFds);
|
|
doSelect = true;
|
|
}
|
|
it++;
|
|
}
|
|
|
|
WebRtc_Word32 num = 0;
|
|
if (doSelect)
|
|
{
|
|
num = select(0, &_readFds, &_writeFds, &_exceptFds, &timeout);
|
|
if (num == SOCKET_ERROR)
|
|
{
|
|
Sleep(10);
|
|
return true;
|
|
}
|
|
}else
|
|
{
|
|
Sleep(10);
|
|
return true;
|
|
}
|
|
|
|
it = _socketMap.begin();
|
|
while (it != _socketMap.end() && num > 0)
|
|
{
|
|
if (FD_ISSET(it->first, &_readFds))
|
|
{
|
|
static_cast<UdpSocketWindows*>(it->second)->HasIncoming();
|
|
num--;
|
|
}
|
|
if (FD_ISSET(it->first, &_writeFds))
|
|
{
|
|
// Socket available for writing.
|
|
static_cast<UdpSocketWindows*>(it->second)->SetWritable();
|
|
num--;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool UdpSocketManagerWindows::Run(ThreadObj obj)
|
|
{
|
|
UdpSocketManagerWindows* mgr = static_cast<UdpSocketManagerWindows*>(obj);
|
|
return mgr->Process();
|
|
};
|
|
|
|
bool UdpSocketManagerWindows::AddSocket(UdpSocketWrapper* s)
|
|
{
|
|
UdpSocketWindows* winSock = static_cast<UdpSocketWindows*>(s);
|
|
|
|
_critSectList->Enter();
|
|
std::map<SOCKET, UdpSocketWindows*>::iterator it =
|
|
_socketMap.find(winSock->GetFd());
|
|
if (it != _socketMap.end())
|
|
{
|
|
if (!_removeList.empty())
|
|
{
|
|
// File descriptors are re-used so it's possible that a socket has
|
|
// been added with the same file descriptor as a socket that is to
|
|
// be removed. I.e. the socket that is to be removed is no longer
|
|
// in use, delete it.
|
|
// TODO (hellner): removing items from _socketMap may cause race
|
|
// condition. Fix this.
|
|
std::list<SOCKET>::iterator removeIt = _removeList.begin();
|
|
while(removeIt != _removeList.end())
|
|
{
|
|
if (*removeIt == winSock->GetFd())
|
|
{
|
|
it = _socketMap.find(*removeIt);
|
|
UdpSocketWindows* delete_socket = it->second;
|
|
_socketMap.erase(it);
|
|
_removeList.erase(removeIt);
|
|
delete delete_socket;
|
|
_addList.push_back(winSock);
|
|
_critSectList->Leave();
|
|
return true;
|
|
}
|
|
removeIt++;
|
|
}
|
|
}
|
|
_critSectList->Leave();
|
|
return false;
|
|
}
|
|
|
|
_addList.push_back(winSock);
|
|
_critSectList->Leave();
|
|
return true;
|
|
}
|
|
|
|
bool UdpSocketManagerWindows::RemoveSocket(UdpSocketWrapper* s)
|
|
{
|
|
UdpSocketWindows* winSock = static_cast<UdpSocketWindows*>(s);
|
|
|
|
_critSectList->Enter();
|
|
// If socket is in the add list its safe to just remove it from the list.
|
|
if (!_addList.empty())
|
|
{
|
|
std::list<UdpSocketWindows*>::iterator it = _addList.begin();
|
|
while(it != _addList.end())
|
|
{
|
|
UdpSocketWindows* tempSocket = (*it);
|
|
if (tempSocket->GetFd() == winSock->GetFd())
|
|
{
|
|
_addList.erase(it);
|
|
delete winSock;
|
|
_critSectList->Leave();
|
|
return true;
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
// If the socket is not even added to the UdpSocketManagerWindows it's
|
|
// safe to delete the socket.
|
|
std::map<SOCKET, UdpSocketWindows*>::iterator findIt =
|
|
_socketMap.find(winSock->GetFd());
|
|
if (findIt == _socketMap.end())
|
|
{
|
|
delete winSock;
|
|
_critSectList->Leave();
|
|
return false;
|
|
}
|
|
|
|
_removeList.push_back(winSock->GetFd());
|
|
_critSectList->Leave();
|
|
return true;
|
|
}
|
|
} // namespace webrtc
|