[go: nahoru, domu]

blob: 14facc3f1fee834f2b11bdd7fc53f3e5fe745fd9 [file] [log] [blame]
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_SERVICE_IMPL_H_
#define CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_SERVICE_IMPL_H_
#include <memory>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/media/router/discovery/dial/dial_service.h"
#include "net/base/ip_address.h"
#include "net/socket/udp_socket.h"
namespace net {
class IPEndPoint;
class StringIOBuffer;
class NetLog;
} // namespace net
namespace media_router {
// Implements DialService using net::UdpSocket.
class DialServiceImpl : public DialService {
public:
DialServiceImpl(DialService::Client& client,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
net::NetLog* net_log);
DialServiceImpl(const DialServiceImpl&) = delete;
DialServiceImpl(DialServiceImpl&&) = delete;
DialServiceImpl& operator=(const DialServiceImpl&) = delete;
DialServiceImpl& operator=(DialServiceImpl&&) = delete;
~DialServiceImpl() override;
// DialService implementation
bool Discover() override;
private:
friend void PostSendNetworkList(
base::WeakPtr<DialServiceImpl> impl,
scoped_refptr<base::SequencedTaskRunner> task_runner,
const absl::optional<net::NetworkInterfaceList>& networks);
// Represents a socket binding to a single network interface.
class DialSocket {
public:
explicit DialSocket(DialServiceImpl* dial_service);
DialSocket(const DialSocket&) = delete;
DialSocket& operator=(const DialSocket&) = delete;
~DialSocket();
// Creates a socket using |net_log| and binds it to |bind_ip_address|.
bool CreateAndBindSocket(const net::IPAddress& bind_ip_address,
net::NetLog* net_log);
// Sends a single discovery request |send_buffer| to |send_address|
// over the socket.
void SendOneRequest(const net::IPEndPoint& send_address,
const scoped_refptr<net::StringIOBuffer>& send_buffer);
// Returns true if the socket is closed.
bool IsClosed();
private:
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestNotifyOnError);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestOnDeviceDiscovered);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestOnDiscoveryRequest);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestResponseParsing);
// Checks the result of a socket operation. The name of the socket
// operation is given by |operation| and the result of the operation is
// given by |result|. If the result is an error, closes the socket,
// calls |on_error_cb_|, and returns |false|. Returns
// |true| otherwise. |operation| and |result| are logged.
bool CheckResult(const char* operation, int result);
// Closes the socket.
void Close();
// Callback invoked for socket writes.
void OnSocketWrite(int buffer_size, int result);
// Establishes the callback to read from the socket. Returns true if
// successful.
bool ReadSocket();
// Callback invoked for socket reads.
void OnSocketRead(int result);
// Callback invoked for socket reads.
void HandleResponse(int bytes_read);
// Parses a response into a DialDeviceData object. If the DIAL response is
// invalid or does not contain enough information, then the return
// value will be false and |device| is not changed.
bool ParseResponse(const std::string& response,
const base::Time& response_time,
DialDeviceData* device);
// The UDP socket.
std::unique_ptr<net::UDPSocket> socket_;
// Buffer for socket reads.
scoped_refptr<net::IOBufferWithSize> recv_buffer_;
// The source of of the last socket read.
net::IPEndPoint recv_address_;
// Marks whether there is an active write callback.
bool is_writing_;
// Marks whether there is an active read callback.
bool is_reading_;
// Pointer to the DialServiceImpl that owns this socket.
const raw_ptr<DialServiceImpl> dial_service_;
SEQUENCE_CHECKER(sequence_checker_);
};
// Starts the control flow for one discovery cycle.
void StartDiscovery();
// For each network interface in |list|, finds all unique IPv4 network
// interfaces and call |DiscoverOnAddresses()| with their IP addresses.
void SendNetworkList(const absl::optional<net::NetworkInterfaceList>& list);
// Calls |BindAndAddSocket()| for each address in |ip_addresses|, calls
// |SendOneRequest()|, and start the timer to finish discovery if needed.
// The (Address family, interface index) of each address in |ip_addresses|
// must be unique. If |ip_address| is empty, calls |FinishDiscovery()|.
void DiscoverOnAddresses(const net::IPAddressList& ip_addresses);
// Creates a DialSocket, binds it to |bind_ip_address| and if
// successful, add the DialSocket to |dial_sockets_|.
void BindAndAddSocket(const net::IPAddress& bind_ip_address);
// Creates a DialSocket with callbacks to this object.
std::unique_ptr<DialSocket> CreateDialSocket();
// Sends a single discovery request to every socket that are currently open.
void SendOneRequest();
// Notify observers that a discovery request was made.
void NotifyOnDiscoveryRequest();
// Notify observers a device has been discovered.
void NotifyOnDeviceDiscovered(const DialDeviceData& device_data);
// Notify observers that there has been an error with one of the DialSockets.
void NotifyOnError();
// Called from finish_timer_ when we are done with the current round of
// discovery.
void FinishDiscovery();
// Returns |true| if there are open sockets.
bool HasOpenSockets();
// Unowned reference to the DialService::Client.
DialService::Client& client_;
// Task runner for the DialServiceImpl. Currently must be bound to the IO
// thread because of socket use, but this may change in the future.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// DialSockets for each network interface whose ip address was
// successfully bound.
std::vector<std::unique_ptr<DialSocket>> dial_sockets_;
// The NetLog for this service.
const raw_ptr<net::NetLog> net_log_;
// The multicast address:port for search requests.
net::IPEndPoint send_address_;
// Buffer for socket writes.
scoped_refptr<net::StringIOBuffer> send_buffer_;
// True when we are currently doing discovery.
bool discovery_active_;
// The number of requests that have been sent in the current discovery.
int num_requests_sent_;
// The maximum number of requests to send per discovery cycle.
int max_requests_;
// Timer for finishing discovery.
base::OneShotTimer finish_timer_;
// The delay for |finish_timer_|; how long to wait for discovery to finish.
// Setting this to zero disables the timer.
base::TimeDelta finish_delay_;
// Timer for sending multiple requests at fixed intervals.
base::RepeatingTimer request_timer_;
// The delay for |request_timer_|; how long to wait between successive
// requests.
base::TimeDelta request_interval_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<DialServiceImpl> weak_ptr_factory_{this};
friend class DialServiceImplTest;
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestSendMultipleRequests);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestMultipleNetworkInterfaces);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestNotifyOnError);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestOnDeviceDiscovered);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestOnDiscoveryFinished);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestOnDiscoveryRequest);
FRIEND_TEST_ALL_PREFIXES(DialServiceImplTest, TestResponseParsing);
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DIAL_SERVICE_IMPL_H_