1 // Copyright (c) 2012 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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_SERVICE_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_SERVICE_H_
10 #include "base/gtest_prod_util.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/observer_list.h"
15 #include "base/threading/thread_checker.h"
16 #include "base/timer/timer.h"
17 #include "net/log/net_log.h"
18 #include "net/udp/udp_socket.h"
25 struct NetworkInterface
;
28 namespace extensions
{
32 // DialService accepts requests to discover devices, sends multiple M-SEARCH
33 // requests via UDP multicast, and notifies observers when a DIAL-compliant
36 // Each time Discover() is called, kDialNumRequests M-SEARCH requests are sent
37 // (with a delay of kDialRequestIntervalMillis in between):
41 // T1 Request 1 sent, OnDiscoveryReqest() called
43 // Tk Request kDialNumRequests sent, OnDiscoveryReqest() called
44 // Tf OnDiscoveryFinished() called
46 // Any time a valid response is received between T1 and Tf, it is parsed and
47 // OnDeviceDiscovered() is called with the result. Tf is set to Tk +
48 // kDialResponseTimeoutSecs (the response timeout passed in each request).
50 // Calling Discover() again between T1 and Tf has no effect.
52 // All relevant constants are defined in dial_service.cc.
54 // TODO(mfoltz): Port this into net/.
55 // See https://code.google.com/p/chromium/issues/detail?id=164473
58 enum DialServiceErrorCode
{
59 DIAL_SERVICE_NO_INTERFACES
= 0,
60 DIAL_SERVICE_SOCKET_ERROR
65 // Called when a single discovery request was sent.
66 virtual void OnDiscoveryRequest(DialService
* service
) = 0;
68 // Called when a device responds to a request.
69 virtual void OnDeviceDiscovered(DialService
* service
,
70 const DialDeviceData
& device
) = 0;
72 // Called when we have all responses from the last discovery request.
73 virtual void OnDiscoveryFinished(DialService
* service
) = 0;
75 // Called when an error occurs.
76 virtual void OnError(DialService
* service
,
77 const DialServiceErrorCode
& code
) = 0;
80 virtual ~Observer() {}
83 virtual ~DialService() {}
85 // Starts a new round of discovery. Returns |true| if discovery was started
86 // successfully or there is already one active. Returns |false| on error.
87 virtual bool Discover() = 0;
89 // Called by listeners to this service to add/remove themselves as observers.
90 virtual void AddObserver(Observer
* observer
) = 0;
91 virtual void RemoveObserver(Observer
* observer
) = 0;
92 virtual bool HasObserver(const Observer
* observer
) const = 0;
95 // Implements DialService.
97 // NOTE(mfoltz): It would make this class cleaner to refactor most of the state
98 // associated with a single discovery cycle into its own |DiscoveryOperation|
99 // object. This would also simplify lifetime of the object w.r.t. DialRegistry;
100 // the Registry would not need to create/destroy the Service on demand.
101 class DialServiceImpl
: public DialService
,
102 public base::SupportsWeakPtr
<DialServiceImpl
> {
104 explicit DialServiceImpl(net::NetLog
* net_log
);
105 ~DialServiceImpl() override
;
107 // DialService implementation
108 bool Discover() override
;
109 void AddObserver(Observer
* observer
) override
;
110 void RemoveObserver(Observer
* observer
) override
;
111 bool HasObserver(const Observer
* observer
) const override
;
114 // Represents a socket binding to a single network interface.
117 // TODO(imcheng): Consider writing a DialSocket::Delegate interface that
118 // declares methods for these callbacks, and taking a ptr to the delegate
121 const base::Closure
& discovery_request_cb
,
122 const base::Callback
<void(const DialDeviceData
&)>& device_discovered_cb
,
123 const base::Closure
& on_error_cb
);
126 // Creates a socket using |net_log| and |net_log_source| and binds it to
127 // |bind_ip_address|.
128 bool CreateAndBindSocket(const net::IPAddressNumber
& bind_ip_address
,
129 net::NetLog
* net_log
,
130 net::NetLog::Source net_log_source
);
132 // Sends a single discovery request |send_buffer| to |send_address|
134 void SendOneRequest(const net::IPEndPoint
& send_address
,
135 const scoped_refptr
<net::StringIOBuffer
>& send_buffer
);
137 // Returns true if the socket is closed.
141 // Checks the result of a socket operation. The name of the socket
142 // operation is given by |operation| and the result of the operation is
143 // given by |result|. If the result is an error, closes the socket,
144 // calls |on_error_cb_|, and returns |false|. Returns
145 // |true| otherwise. |operation| and |result| are logged.
146 bool CheckResult(const char* operation
, int result
);
148 // Closes the socket.
151 // Callback invoked for socket writes.
152 void OnSocketWrite(int buffer_size
, int result
);
154 // Establishes the callback to read from the socket. Returns true if
158 // Callback invoked for socket reads.
159 void OnSocketRead(int result
);
161 // Callback invoked for socket reads.
162 void HandleResponse(int bytes_read
);
164 // Parses a response into a DialDeviceData object. If the DIAL response is
165 // invalid or does not contain enough information, then the return
166 // value will be false and |device| is not changed.
167 static bool ParseResponse(const std::string
& response
,
168 const base::Time
& response_time
,
169 DialDeviceData
* device
);
172 scoped_ptr
<net::UDPSocket
> socket_
;
174 // Buffer for socket reads.
175 scoped_refptr
<net::IOBufferWithSize
> recv_buffer_
;
177 // The source of of the last socket read.
178 net::IPEndPoint recv_address_
;
181 base::ThreadChecker thread_checker_
;
183 // The callback to be invoked when a discovery request was made.
184 base::Closure discovery_request_cb_
;
186 // The callback to be invoked when a device has been discovered.
187 base::Callback
<void(const DialDeviceData
&)> device_discovered_cb_
;
189 // The callback to be invoked when there is an error with socket operations.
190 base::Closure on_error_cb_
;
192 // Marks whether there is an active write callback.
195 // Marks whether there is an active read callback.
198 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestNotifyOnError
);
199 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestOnDeviceDiscovered
);
200 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestOnDiscoveryRequest
);
201 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestResponseParsing
);
202 DISALLOW_COPY_AND_ASSIGN(DialSocket
);
205 // Starts the control flow for one discovery cycle.
206 void StartDiscovery();
208 // For each network interface in |list|, finds all unqiue IPv4 network
209 // interfaces and call |DiscoverOnAddresses()| with their IP addresses.
210 void SendNetworkList(const net::NetworkInterfaceList
& list
);
212 // Calls |BindAndAddSocket()| for each address in |ip_addresses|, calls
213 // |SendOneRequest()|, and start the timer to finish discovery if needed.
214 // The (Address family, interface index) of each address in |ip_addresses|
215 // must be unique. If |ip_address| is empty, calls |FinishDiscovery()|.
216 void DiscoverOnAddresses(
217 const std::vector
<net::IPAddressNumber
>& ip_addresses
);
219 // Creates a DialSocket, binds it to |bind_ip_address| and if
220 // successful, add the DialSocket to |dial_sockets_|.
221 void BindAndAddSocket(const net::IPAddressNumber
& bind_ip_address
);
223 // Creates a DialSocket with callbacks to this object.
224 scoped_ptr
<DialSocket
> CreateDialSocket();
226 // Sends a single discovery request to every socket that are currently open.
227 void SendOneRequest();
229 // Notify observers that a discovery request was made.
230 void NotifyOnDiscoveryRequest();
232 // Notify observers a device has been discovered.
233 void NotifyOnDeviceDiscovered(const DialDeviceData
& device_data
);
235 // Notify observers that there has been an error with one of the DialSockets.
236 void NotifyOnError();
238 // Called from finish_timer_ when we are done with the current round of
240 void FinishDiscovery();
242 // Returns |true| if there are open sockets.
243 bool HasOpenSockets();
245 // DialSockets for each network interface whose ip address was
246 // successfully bound.
247 ScopedVector
<DialSocket
> dial_sockets_
;
249 // The NetLog for this service.
250 net::NetLog
* net_log_
;
252 // The NetLog source for this service.
253 net::NetLog::Source net_log_source_
;
255 // The multicast address:port for search requests.
256 net::IPEndPoint send_address_
;
258 // Buffer for socket writes.
259 scoped_refptr
<net::StringIOBuffer
> send_buffer_
;
261 // True when we are currently doing discovery.
262 bool discovery_active_
;
264 // The number of requests that have been sent in the current discovery.
265 int num_requests_sent_
;
267 // The maximum number of requests to send per discovery cycle.
270 // Timer for finishing discovery.
271 base::OneShotTimer
<DialServiceImpl
> finish_timer_
;
273 // The delay for |finish_timer_|; how long to wait for discovery to finish.
274 // Setting this to zero disables the timer.
275 base::TimeDelta finish_delay_
;
277 // Timer for sending multiple requests at fixed intervals.
278 base::RepeatingTimer
<DialServiceImpl
> request_timer_
;
280 // The delay for |request_timer_|; how long to wait between successive
282 base::TimeDelta request_interval_
;
284 // List of observers.
285 base::ObserverList
<Observer
> observer_list_
;
288 base::ThreadChecker thread_checker_
;
290 friend class DialServiceTest
;
291 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestSendMultipleRequests
);
292 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestMultipleNetworkInterfaces
);
293 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestNotifyOnError
);
294 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestOnDeviceDiscovered
);
295 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestOnDiscoveryFinished
);
296 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestOnDiscoveryRequest
);
297 FRIEND_TEST_ALL_PREFIXES(DialServiceTest
, TestResponseParsing
);
298 DISALLOW_COPY_AND_ASSIGN(DialServiceImpl
);
301 } // namespace extensions
303 #endif // CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_SERVICE_H_