1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "platform/impl/udp_socket_reader_posix.h"
6 
7 #include <chrono>
8 #include <functional>
9 
10 #include "platform/impl/socket_handle_posix.h"
11 #include "platform/impl/udp_socket_posix.h"
12 #include "util/osp_logging.h"
13 
14 namespace openscreen {
15 
UdpSocketReaderPosix(SocketHandleWaiter * waiter)16 UdpSocketReaderPosix::UdpSocketReaderPosix(SocketHandleWaiter* waiter)
17     : waiter_(waiter) {}
18 
~UdpSocketReaderPosix()19 UdpSocketReaderPosix::~UdpSocketReaderPosix() {
20   waiter_->UnsubscribeAll(this);
21 }
22 
ProcessReadyHandle(SocketHandleRef handle,uint32_t flags)23 void UdpSocketReaderPosix::ProcessReadyHandle(SocketHandleRef handle,
24                                               uint32_t flags) {
25   if (flags & SocketHandleWaiter::Flags::kReadable) {
26     std::lock_guard<std::mutex> lock(mutex_);
27     // NOTE: Because sockets_ is expected to remain small, the performance here
28     // is better than using an unordered_set.
29     for (UdpSocketPosix* socket : sockets_) {
30       if (socket->GetHandle() == handle) {
31         socket->ReceiveMessage();
32         break;
33       }
34     }
35   }
36 }
37 
OnCreate(UdpSocket * socket)38 void UdpSocketReaderPosix::OnCreate(UdpSocket* socket) {
39   UdpSocketPosix* read_socket = static_cast<UdpSocketPosix*>(socket);
40   {
41     std::lock_guard<std::mutex> lock(mutex_);
42     sockets_.push_back(read_socket);
43   }
44   waiter_->Subscribe(this, std::cref(read_socket->GetHandle()));
45 }
46 
OnDestroy(UdpSocket * socket)47 void UdpSocketReaderPosix::OnDestroy(UdpSocket* socket) {
48   UdpSocketPosix* destroyed_socket = static_cast<UdpSocketPosix*>(socket);
49   OnDelete(destroyed_socket);
50 }
51 
OnDelete(UdpSocketPosix * socket,bool disable_locking_for_testing)52 void UdpSocketReaderPosix::OnDelete(UdpSocketPosix* socket,
53                                     bool disable_locking_for_testing) {
54   {
55     std::unique_lock<std::mutex> lock(mutex_);
56     auto it = std::find(sockets_.begin(), sockets_.end(), socket);
57     if (it != sockets_.end()) {
58       sockets_.erase(it);
59     }
60   }
61 
62   waiter_->OnHandleDeletion(this, std::cref(socket->GetHandle()),
63                             disable_locking_for_testing);
64 }
65 
IsMappedReadForTesting(UdpSocketPosix * socket) const66 bool UdpSocketReaderPosix::IsMappedReadForTesting(
67     UdpSocketPosix* socket) const {
68   return std::find(sockets_.begin(), sockets_.end(), socket) != sockets_.end();
69 }
70 
71 }  // namespace openscreen
72