/* * 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::iterator it = _socketMap.begin(); UdpSocketWindows* s = static_cast(it->second); _socketMap.erase(it); delete s; } _removeList.erase(_removeList.begin(), _removeList.end()); while(!_addList.empty()) { std::list::iterator it = _addList.begin(); UdpSocketWindows* s = static_cast(*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::iterator it = _socketMap.find(id); if(it != _socketMap.end()) { UdpSocketWindows* s = static_cast(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::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(it->second)->HasIncoming(); num--; } if (FD_ISSET(it->first, &_writeFds)) { // Socket available for writing. static_cast(it->second)->SetWritable(); num--; } } return true; } bool UdpSocketManagerWindows::Run(ThreadObj obj) { UdpSocketManagerWindows* mgr = static_cast(obj); return mgr->Process(); }; bool UdpSocketManagerWindows::AddSocket(UdpSocketWrapper* s) { UdpSocketWindows* winSock = static_cast(s); _critSectList->Enter(); std::map::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::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(s); _critSectList->Enter(); // If socket is in the add list its safe to just remove it from the list. if (!_addList.empty()) { std::list::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::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