noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 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" |
vitalybuka@chromium.org | e4411fbe | 2013-09-26 21:10:11 | [diff] [blame] | 14 | #include "base/memory/scoped_vector.h" |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 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 | |
| 24 | namespace net { |
| 25 | |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 26 | class 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 | |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 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. |
noamsml@chromium.org | ba77c27f | 2013-07-02 22:34:32 | [diff] [blame] | 40 | class NET_EXPORT_PRIVATE MDnsConnection { |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 41 | public: |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 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 | |
vitalybuka@chromium.org | e4411fbe | 2013-09-26 21:10:11 | [diff] [blame] | 50 | explicit MDnsConnection(MDnsConnection::Delegate* delegate); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 51 | virtual ~MDnsConnection(); |
| 52 | |
vitalybuka@chromium.org | e4411fbe | 2013-09-26 21:10:11 | [diff] [blame] | 53 | // Both methods return true if at least one of the socket handlers succeeded. |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 54 | bool Init(MDnsSocketFactory* socket_factory); |
vitalybuka@chromium.org | e4411fbe | 2013-09-26 21:10:11 | [diff] [blame] | 55 | bool Send(IOBuffer* buffer, unsigned size); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 56 | |
| 57 | private: |
| 58 | class SocketHandler { |
| 59 | public: |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 60 | SocketHandler(scoped_ptr<DatagramServerSocket> socket, |
| 61 | MDnsConnection* connection); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 62 | ~SocketHandler(); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 63 | |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 64 | int Start(); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 65 | int Send(IOBuffer* buffer, unsigned size); |
| 66 | |
| 67 | private: |
vitalybuka@chromium.org | 03dd9425 | 2013-09-01 23:25:31 | [diff] [blame] | 68 | int DoLoop(int rv); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 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_; |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 75 | MDnsConnection* connection_; |
| 76 | IPEndPoint recv_addr_; |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 77 | DnsResponse response_; |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 78 | IPEndPoint multicast_addr_; |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 79 | |
| 80 | DISALLOW_COPY_AND_ASSIGN(SocketHandler); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 81 | }; |
| 82 | |
| 83 | // Callback for handling a datagram being received on either ipv4 or ipv6. |
| 84 | void OnDatagramReceived(DnsResponse* response, |
| 85 | const IPEndPoint& recv_addr, |
| 86 | int bytes_read); |
| 87 | |
| 88 | void OnError(SocketHandler* loop, int error); |
| 89 | |
vitalybuka@chromium.org | e4411fbe | 2013-09-26 21:10:11 | [diff] [blame] | 90 | // Only socket handlers which successfully bound and started are kept. |
| 91 | ScopedVector<SocketHandler> socket_handlers_; |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 92 | |
| 93 | Delegate* delegate_; |
| 94 | |
| 95 | DISALLOW_COPY_AND_ASSIGN(MDnsConnection); |
| 96 | }; |
| 97 | |
| 98 | class MDnsListenerImpl; |
| 99 | |
noamsml@chromium.org | ba77c27f | 2013-07-02 22:34:32 | [diff] [blame] | 100 | class NET_EXPORT_PRIVATE MDnsClientImpl : public MDnsClient { |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 101 | public: |
noamsml@chromium.org | 21df1696 | 2013-07-01 17:39:53 | [diff] [blame] | 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. |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 106 | class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate { |
| 107 | public: |
vitalybuka@chromium.org | e4411fbe | 2013-09-26 21:10:11 | [diff] [blame] | 108 | explicit Core(MDnsClientImpl* client); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 109 | virtual ~Core(); |
| 110 | |
| 111 | // Initialize the core. Returns true on success. |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 112 | bool Init(MDnsSocketFactory* socket_factory); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 113 | |
| 114 | // Send a query with a specific rrtype and name. Returns true on success. |
| 115 | bool SendQuery(uint16 rrtype, std::string name); |
| 116 | |
noamsml@chromium.org | 21df1696 | 2013-07-01 17:39:53 | [diff] [blame] | 117 | // Add/remove a listener to the list of listeners. |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 118 | void AddListener(MDnsListenerImpl* listener); |
| 119 | void RemoveListener(MDnsListenerImpl* listener); |
| 120 | |
| 121 | // Query the cache for records of a specific type and name. |
| 122 | void QueryCache(uint16 rrtype, const std::string& name, |
| 123 | std::vector<const RecordParsed*>* records) const; |
| 124 | |
| 125 | // Parse the response and alert relevant listeners. |
| 126 | virtual void HandlePacket(DnsResponse* response, int bytes_read) OVERRIDE; |
| 127 | |
| 128 | virtual void OnConnectionError(int error) OVERRIDE; |
| 129 | |
| 130 | private: |
noamsml@chromium.org | 21df1696 | 2013-07-01 17:39:53 | [diff] [blame] | 131 | typedef std::pair<std::string, uint16> ListenerKey; |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 132 | typedef std::map<ListenerKey, ObserverList<MDnsListenerImpl>* > |
| 133 | ListenerMap; |
| 134 | |
| 135 | // Alert listeners of an update to the cache. |
| 136 | void AlertListeners(MDnsListener::UpdateType update_type, |
| 137 | const ListenerKey& key, const RecordParsed* record); |
| 138 | |
| 139 | // Schedule a cache cleanup to a specific time, cancelling other cleanups. |
| 140 | void ScheduleCleanup(base::Time cleanup); |
| 141 | |
| 142 | // Clean up the cache and schedule a new cleanup. |
| 143 | void DoCleanup(); |
| 144 | |
| 145 | // Callback for when a record is removed from the cache. |
| 146 | void OnRecordRemoved(const RecordParsed* record); |
noamsml@chromium.org | 21df1696 | 2013-07-01 17:39:53 | [diff] [blame] | 147 | |
| 148 | void NotifyNsecRecord(const RecordParsed* record); |
| 149 | |
| 150 | // Delete and erase the observer list for |key|. Only deletes the observer |
| 151 | // list if is empty. |
| 152 | void CleanupObserverList(const ListenerKey& key); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 153 | |
| 154 | ListenerMap listeners_; |
| 155 | |
| 156 | MDnsClientImpl* client_; |
| 157 | MDnsCache cache_; |
| 158 | |
| 159 | base::CancelableCallback<void()> cleanup_callback_; |
| 160 | base::Time scheduled_cleanup_; |
| 161 | |
| 162 | scoped_ptr<MDnsConnection> connection_; |
| 163 | |
| 164 | DISALLOW_COPY_AND_ASSIGN(Core); |
| 165 | }; |
| 166 | |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 167 | MDnsClientImpl(); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 168 | virtual ~MDnsClientImpl(); |
| 169 | |
| 170 | // MDnsClient implementation: |
| 171 | virtual scoped_ptr<MDnsListener> CreateListener( |
| 172 | uint16 rrtype, |
| 173 | const std::string& name, |
| 174 | MDnsListener::Delegate* delegate) OVERRIDE; |
| 175 | |
| 176 | virtual scoped_ptr<MDnsTransaction> CreateTransaction( |
| 177 | uint16 rrtype, |
| 178 | const std::string& name, |
| 179 | int flags, |
| 180 | const MDnsTransaction::ResultCallback& callback) OVERRIDE; |
| 181 | |
vitalybuka@chromium.org | 95b331b4 | 2013-12-02 06:26:31 | [diff] [blame^] | 182 | virtual bool StartListening(MDnsSocketFactory* socket_factory) OVERRIDE; |
noamsml@chromium.org | 9c61d25 | 2013-07-02 23:26:22 | [diff] [blame] | 183 | virtual void StopListening() OVERRIDE; |
| 184 | virtual bool IsListening() const OVERRIDE; |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 185 | |
| 186 | Core* core() { return core_.get(); } |
| 187 | |
| 188 | private: |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 189 | scoped_ptr<Core> core_; |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 190 | |
| 191 | DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl); |
| 192 | }; |
| 193 | |
| 194 | class MDnsListenerImpl : public MDnsListener, |
| 195 | public base::SupportsWeakPtr<MDnsListenerImpl> { |
| 196 | public: |
| 197 | MDnsListenerImpl(uint16 rrtype, |
| 198 | const std::string& name, |
| 199 | MDnsListener::Delegate* delegate, |
| 200 | MDnsClientImpl* client); |
| 201 | |
| 202 | virtual ~MDnsListenerImpl(); |
| 203 | |
| 204 | // MDnsListener implementation: |
| 205 | virtual bool Start() OVERRIDE; |
| 206 | |
| 207 | virtual const std::string& GetName() const OVERRIDE; |
| 208 | |
| 209 | virtual uint16 GetType() const OVERRIDE; |
| 210 | |
| 211 | MDnsListener::Delegate* delegate() { return delegate_; } |
| 212 | |
| 213 | // Alert the delegate of a record update. |
| 214 | void AlertDelegate(MDnsListener::UpdateType update_type, |
| 215 | const RecordParsed* record_parsed); |
noamsml@chromium.org | 21df1696 | 2013-07-01 17:39:53 | [diff] [blame] | 216 | |
| 217 | // Alert the delegate of the existence of an Nsec record. |
| 218 | void AlertNsecRecord(); |
| 219 | |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 220 | private: |
| 221 | uint16 rrtype_; |
| 222 | std::string name_; |
| 223 | MDnsClientImpl* client_; |
| 224 | MDnsListener::Delegate* delegate_; |
| 225 | |
| 226 | bool started_; |
| 227 | DISALLOW_COPY_AND_ASSIGN(MDnsListenerImpl); |
| 228 | }; |
| 229 | |
| 230 | class MDnsTransactionImpl : public base::SupportsWeakPtr<MDnsTransactionImpl>, |
| 231 | public MDnsTransaction, |
| 232 | public MDnsListener::Delegate { |
| 233 | public: |
| 234 | MDnsTransactionImpl(uint16 rrtype, |
| 235 | const std::string& name, |
| 236 | int flags, |
| 237 | const MDnsTransaction::ResultCallback& callback, |
| 238 | MDnsClientImpl* client); |
| 239 | virtual ~MDnsTransactionImpl(); |
| 240 | |
| 241 | // MDnsTransaction implementation: |
| 242 | virtual bool Start() OVERRIDE; |
| 243 | |
| 244 | virtual const std::string& GetName() const OVERRIDE; |
| 245 | virtual uint16 GetType() const OVERRIDE; |
| 246 | |
| 247 | // MDnsListener::Delegate implementation: |
| 248 | virtual void OnRecordUpdate(MDnsListener::UpdateType update, |
| 249 | const RecordParsed* record) OVERRIDE; |
| 250 | virtual void OnNsecRecord(const std::string& name, unsigned type) OVERRIDE; |
| 251 | |
| 252 | virtual void OnCachePurged() OVERRIDE; |
| 253 | |
| 254 | private: |
| 255 | bool is_active() { return !callback_.is_null(); } |
| 256 | |
| 257 | void Reset(); |
| 258 | |
| 259 | // Trigger the callback and reset all related variables. |
| 260 | void TriggerCallback(MDnsTransaction::Result result, |
| 261 | const RecordParsed* record); |
| 262 | |
| 263 | // Internal callback for when a cache record is found. |
| 264 | void CacheRecordFound(const RecordParsed* record); |
| 265 | |
| 266 | // Signal the transactionis over and release all related resources. |
| 267 | void SignalTransactionOver(); |
| 268 | |
noamsml@chromium.org | f3c0999 | 2013-06-25 00:40:48 | [diff] [blame] | 269 | // Reads records from the cache and calls the callback for every |
| 270 | // record read. |
| 271 | void ServeRecordsFromCache(); |
| 272 | |
| 273 | // Send a query to the network and set up a timeout to time out the |
| 274 | // transaction. Returns false if it fails to start listening on the network |
| 275 | // or if it fails to send a query. |
| 276 | bool QueryAndListen(); |
| 277 | |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 278 | uint16 rrtype_; |
| 279 | std::string name_; |
| 280 | MDnsTransaction::ResultCallback callback_; |
| 281 | |
| 282 | scoped_ptr<MDnsListener> listener_; |
| 283 | base::CancelableCallback<void()> timeout_; |
| 284 | |
| 285 | MDnsClientImpl* client_; |
| 286 | |
| 287 | bool started_; |
| 288 | int flags_; |
| 289 | |
| 290 | DISALLOW_COPY_AND_ASSIGN(MDnsTransactionImpl); |
| 291 | }; |
| 292 | |
| 293 | } // namespace net |
| 294 | #endif // NET_DNS_MDNS_CLIENT_IMPL_H_ |