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