1// Copyright 2013 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#ifndef NET_DNS_MDNS_CLIENT_IMPL_H_
6#define NET_DNS_MDNS_CLIENT_IMPL_H_
7
8#include <map>
9#include <string>
10#include <utility>
11#include <vector>
12
13#include "base/cancelable_callback.h"
14#include "base/memory/scoped_vector.h"
15#include "base/observer_list.h"
16#include "net/base/io_buffer.h"
17#include "net/base/ip_endpoint.h"
18#include "net/dns/mdns_cache.h"
19#include "net/dns/mdns_client.h"
20#include "net/udp/datagram_server_socket.h"
21#include "net/udp/udp_server_socket.h"
22#include "net/udp/udp_socket.h"
23
24namespace net {
25
26class MDnsSocketFactoryImpl : public MDnsSocketFactory {
27 public:
28  MDnsSocketFactoryImpl() {};
29  virtual ~MDnsSocketFactoryImpl() {};
30
31  virtual void CreateSockets(
32      ScopedVector<DatagramServerSocket>* sockets) OVERRIDE;
33
34 private:
35  DISALLOW_COPY_AND_ASSIGN(MDnsSocketFactoryImpl);
36};
37
38// A connection to the network for multicast DNS clients. It reads data into
39// DnsResponse objects and alerts the delegate that a packet has been received.
40class NET_EXPORT_PRIVATE MDnsConnection {
41 public:
42  class Delegate {
43   public:
44    // Handle an mDNS packet buffered in |response| with a size of |bytes_read|.
45    virtual void HandlePacket(DnsResponse* response, int bytes_read) = 0;
46    virtual void OnConnectionError(int error) = 0;
47    virtual ~Delegate() {}
48  };
49
50  explicit MDnsConnection(MDnsConnection::Delegate* delegate);
51  virtual ~MDnsConnection();
52
53  // Both methods return true if at least one of the socket handlers succeeded.
54  bool Init(MDnsSocketFactory* socket_factory);
55  void Send(const scoped_refptr<IOBuffer>& buffer, unsigned size);
56
57 private:
58  class SocketHandler {
59   public:
60    SocketHandler(scoped_ptr<DatagramServerSocket> socket,
61                  MDnsConnection* connection);
62    ~SocketHandler();
63
64    int Start();
65    void Send(const scoped_refptr<IOBuffer>& buffer, unsigned size);
66
67   private:
68    int DoLoop(int rv);
69    void OnDatagramReceived(int rv);
70
71    // Callback for when sending a query has finished.
72    void SendDone(int rv);
73
74    scoped_ptr<DatagramServerSocket> socket_;
75    MDnsConnection* connection_;
76    IPEndPoint recv_addr_;
77    DnsResponse response_;
78    IPEndPoint multicast_addr_;
79    bool send_in_progress_;
80    std::queue<std::pair<scoped_refptr<IOBuffer>, unsigned> > send_queue_;
81
82    DISALLOW_COPY_AND_ASSIGN(SocketHandler);
83  };
84
85  // Callback for handling a datagram being received on either ipv4 or ipv6.
86  void OnDatagramReceived(DnsResponse* response,
87                          const IPEndPoint& recv_addr,
88                          int bytes_read);
89
90  void PostOnError(SocketHandler* loop, int rv);
91  void OnError(int rv);
92
93  // Only socket handlers which successfully bound and started are kept.
94  ScopedVector<SocketHandler> socket_handlers_;
95
96  Delegate* delegate_;
97
98  base::WeakPtrFactory<MDnsConnection> weak_ptr_factory_;
99
100  DISALLOW_COPY_AND_ASSIGN(MDnsConnection);
101};
102
103class MDnsListenerImpl;
104
105class NET_EXPORT_PRIVATE MDnsClientImpl : public MDnsClient {
106 public:
107  // The core object exists while the MDnsClient is listening, and is deleted
108  // whenever the number of listeners reaches zero. The deletion happens
109  // asychronously, so destroying the last listener does not immediately
110  // invalidate the core.
111  class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate {
112   public:
113    explicit Core(MDnsClientImpl* client);
114    virtual ~Core();
115
116    // Initialize the core. Returns true on success.
117    bool Init(MDnsSocketFactory* socket_factory);
118
119    // Send a query with a specific rrtype and name. Returns true on success.
120    bool SendQuery(uint16 rrtype, std::string name);
121
122    // Add/remove a listener to the list of listeners.
123    void AddListener(MDnsListenerImpl* listener);
124    void RemoveListener(MDnsListenerImpl* listener);
125
126    // Query the cache for records of a specific type and name.
127    void QueryCache(uint16 rrtype, const std::string& name,
128                    std::vector<const RecordParsed*>* records) const;
129
130    // Parse the response and alert relevant listeners.
131    virtual void HandlePacket(DnsResponse* response, int bytes_read) OVERRIDE;
132
133    virtual void OnConnectionError(int error) OVERRIDE;
134
135   private:
136    typedef std::pair<std::string, uint16> ListenerKey;
137    typedef std::map<ListenerKey, ObserverList<MDnsListenerImpl>* >
138    ListenerMap;
139
140    // Alert listeners of an update to the cache.
141    void AlertListeners(MDnsCache::UpdateType update_type,
142                        const ListenerKey& key, const RecordParsed* record);
143
144    // Schedule a cache cleanup to a specific time, cancelling other cleanups.
145    void ScheduleCleanup(base::Time cleanup);
146
147    // Clean up the cache and schedule a new cleanup.
148    void DoCleanup();
149
150    // Callback for when a record is removed from the cache.
151    void OnRecordRemoved(const RecordParsed* record);
152
153    void NotifyNsecRecord(const RecordParsed* record);
154
155    // Delete and erase the observer list for |key|. Only deletes the observer
156    // list if is empty.
157    void CleanupObserverList(const ListenerKey& key);
158
159    ListenerMap listeners_;
160
161    MDnsClientImpl* client_;
162    MDnsCache cache_;
163
164    base::CancelableClosure cleanup_callback_;
165    base::Time scheduled_cleanup_;
166
167    scoped_ptr<MDnsConnection> connection_;
168
169    DISALLOW_COPY_AND_ASSIGN(Core);
170  };
171
172  MDnsClientImpl();
173  virtual ~MDnsClientImpl();
174
175  // MDnsClient implementation:
176  virtual scoped_ptr<MDnsListener> CreateListener(
177      uint16 rrtype,
178      const std::string& name,
179      MDnsListener::Delegate* delegate) OVERRIDE;
180
181  virtual scoped_ptr<MDnsTransaction> CreateTransaction(
182      uint16 rrtype,
183      const std::string& name,
184      int flags,
185      const MDnsTransaction::ResultCallback& callback) OVERRIDE;
186
187  virtual bool StartListening(MDnsSocketFactory* socket_factory) OVERRIDE;
188  virtual void StopListening() OVERRIDE;
189  virtual bool IsListening() const OVERRIDE;
190
191  Core* core() { return core_.get(); }
192
193 private:
194  scoped_ptr<Core> core_;
195
196  DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl);
197};
198
199class MDnsListenerImpl : public MDnsListener,
200                         public base::SupportsWeakPtr<MDnsListenerImpl> {
201 public:
202  MDnsListenerImpl(uint16 rrtype,
203                   const std::string& name,
204                   MDnsListener::Delegate* delegate,
205                   MDnsClientImpl* client);
206
207  virtual ~MDnsListenerImpl();
208
209  // MDnsListener implementation:
210  virtual bool Start() OVERRIDE;
211
212  // Actively refresh any received records.
213  virtual void SetActiveRefresh(bool active_refresh) OVERRIDE;
214
215  virtual const std::string& GetName() const OVERRIDE;
216
217  virtual uint16 GetType() const OVERRIDE;
218
219  MDnsListener::Delegate* delegate() { return delegate_; }
220
221  // Alert the delegate of a record update.
222  void HandleRecordUpdate(MDnsCache::UpdateType update_type,
223                          const RecordParsed* record_parsed);
224
225  // Alert the delegate of the existence of an Nsec record.
226  void AlertNsecRecord();
227
228 private:
229  void ScheduleNextRefresh();
230  void DoRefresh();
231
232  uint16 rrtype_;
233  std::string name_;
234  MDnsClientImpl* client_;
235  MDnsListener::Delegate* delegate_;
236
237  base::Time last_update_;
238  uint32 ttl_;
239  bool started_;
240  bool active_refresh_;
241
242  base::CancelableClosure next_refresh_;
243  DISALLOW_COPY_AND_ASSIGN(MDnsListenerImpl);
244};
245
246class MDnsTransactionImpl : public base::SupportsWeakPtr<MDnsTransactionImpl>,
247                            public MDnsTransaction,
248                            public MDnsListener::Delegate {
249 public:
250  MDnsTransactionImpl(uint16 rrtype,
251                      const std::string& name,
252                      int flags,
253                      const MDnsTransaction::ResultCallback& callback,
254                      MDnsClientImpl* client);
255  virtual ~MDnsTransactionImpl();
256
257  // MDnsTransaction implementation:
258  virtual bool Start() OVERRIDE;
259
260  virtual const std::string& GetName() const OVERRIDE;
261  virtual uint16 GetType() const OVERRIDE;
262
263  // MDnsListener::Delegate implementation:
264  virtual void OnRecordUpdate(MDnsListener::UpdateType update,
265                              const RecordParsed* record) OVERRIDE;
266  virtual void OnNsecRecord(const std::string& name, unsigned type) OVERRIDE;
267
268  virtual void OnCachePurged() OVERRIDE;
269
270 private:
271  bool is_active() { return !callback_.is_null(); }
272
273  void Reset();
274
275  // Trigger the callback and reset all related variables.
276  void TriggerCallback(MDnsTransaction::Result result,
277                       const RecordParsed* record);
278
279  // Internal callback for when a cache record is found.
280  void CacheRecordFound(const RecordParsed* record);
281
282  // Signal the transactionis over and release all related resources.
283  void SignalTransactionOver();
284
285  // Reads records from the cache and calls the callback for every
286  // record read.
287  void ServeRecordsFromCache();
288
289  // Send a query to the network and set up a timeout to time out the
290  // transaction. Returns false if it fails to start listening on the network
291  // or if it fails to send a query.
292  bool QueryAndListen();
293
294  uint16 rrtype_;
295  std::string name_;
296  MDnsTransaction::ResultCallback callback_;
297
298  scoped_ptr<MDnsListener> listener_;
299  base::CancelableCallback<void()> timeout_;
300
301  MDnsClientImpl* client_;
302
303  bool started_;
304  int flags_;
305
306  DISALLOW_COPY_AND_ASSIGN(MDnsTransactionImpl);
307};
308
309}  // namespace net
310#endif  // NET_DNS_MDNS_CLIENT_IMPL_H_
311