blob: d817d74a78a9e99dcbff330449d77558b78d7786 [file] [log] [blame]
/*
* 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()
: UdpSocketManager(),
_id(-1)
{
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++;
}
bool UdpSocketManagerWindows::Init(WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads) {
CriticalSectionScoped cs(_critSectList);
if ((_id != -1) || (_numOfWorkThreads != 0)) {
assert(_id == -1);
assert(_numOfWorkThreads == 0);
return false;
}
_id = id;
_numOfWorkThreads = numOfWorkThreads;
return true;
}
UdpSocketManagerWindows::~UdpSocketManagerWindows()
{
Stop();
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