| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/dns/mdns_client_impl.h" | 5 #include "net/dns/mdns_client_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/time/default_clock.h" | 10 #include "base/time/default_clock.h" |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 92 |
| 93 void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) { | 93 void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) { |
| 94 if (rv >= OK) | 94 if (rv >= OK) |
| 95 rv = DoLoop(rv); | 95 rv = DoLoop(rv); |
| 96 | 96 |
| 97 if (rv != OK) | 97 if (rv != OK) |
| 98 connection_->OnError(this, rv); | 98 connection_->OnError(this, rv); |
| 99 } | 99 } |
| 100 | 100 |
| 101 int MDnsConnection::SocketHandler::Send(IOBuffer* buffer, unsigned size) { | 101 int MDnsConnection::SocketHandler::Send(IOBuffer* buffer, unsigned size) { |
| 102 return socket_->SendTo(buffer, size, multicast_addr_, | 102 return socket_->SendTo(buffer, |
| 103 size, |
| 104 multicast_addr_, |
| 103 base::Bind(&MDnsConnection::SocketHandler::SendDone, | 105 base::Bind(&MDnsConnection::SocketHandler::SendDone, |
| 104 base::Unretained(this) )); | 106 base::Unretained(this))); |
| 105 } | 107 } |
| 106 | 108 |
| 107 void MDnsConnection::SocketHandler::SendDone(int rv) { | 109 void MDnsConnection::SocketHandler::SendDone(int rv) { |
| 108 // TODO(noamsml): Retry logic. | 110 // TODO(noamsml): Retry logic. |
| 109 } | 111 } |
| 110 | 112 |
| 111 MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) : | 113 MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) |
| 112 delegate_(delegate) { | 114 : delegate_(delegate) { |
| 113 } | 115 } |
| 114 | 116 |
| 115 MDnsConnection::~MDnsConnection() { | 117 MDnsConnection::~MDnsConnection() { |
| 116 } | 118 } |
| 117 | 119 |
| 118 bool MDnsConnection::Init(MDnsSocketFactory* socket_factory) { | 120 bool MDnsConnection::Init(MDnsSocketFactory* socket_factory) { |
| 119 ScopedVector<DatagramServerSocket> sockets; | 121 ScopedVector<DatagramServerSocket> sockets; |
| 120 socket_factory->CreateSockets(&sockets); | 122 socket_factory->CreateSockets(&sockets); |
| 121 | 123 |
| 122 for (size_t i = 0; i < sockets.size(); ++i) { | 124 for (size_t i = 0; i < sockets.size(); ++i) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 147 int rv = socket_handlers_[i]->Send(buffer, size); | 149 int rv = socket_handlers_[i]->Send(buffer, size); |
| 148 if (rv >= OK || rv == ERR_IO_PENDING) { | 150 if (rv >= OK || rv == ERR_IO_PENDING) { |
| 149 success = true; | 151 success = true; |
| 150 } else { | 152 } else { |
| 151 VLOG(1) << "Send failed, socket=" << i << ", error=" << rv; | 153 VLOG(1) << "Send failed, socket=" << i << ", error=" << rv; |
| 152 } | 154 } |
| 153 } | 155 } |
| 154 return success; | 156 return success; |
| 155 } | 157 } |
| 156 | 158 |
| 157 void MDnsConnection::OnError(SocketHandler* loop, | 159 void MDnsConnection::OnError(SocketHandler* loop, int error) { |
| 158 int error) { | |
| 159 // TODO(noamsml): Specific handling of intermittent errors that can be handled | 160 // TODO(noamsml): Specific handling of intermittent errors that can be handled |
| 160 // in the connection. | 161 // in the connection. |
| 161 delegate_->OnConnectionError(error); | 162 delegate_->OnConnectionError(error); |
| 162 } | 163 } |
| 163 | 164 |
| 164 void MDnsConnection::OnDatagramReceived( | 165 void MDnsConnection::OnDatagramReceived(DnsResponse* response, |
| 165 DnsResponse* response, | 166 const IPEndPoint& recv_addr, |
| 166 const IPEndPoint& recv_addr, | 167 int bytes_read) { |
| 167 int bytes_read) { | |
| 168 // TODO(noamsml): More sophisticated error handling. | 168 // TODO(noamsml): More sophisticated error handling. |
| 169 DCHECK_GT(bytes_read, 0); | 169 DCHECK_GT(bytes_read, 0); |
| 170 delegate_->HandlePacket(response, bytes_read); | 170 delegate_->HandlePacket(response, bytes_read); |
| 171 } | 171 } |
| 172 | 172 |
| 173 MDnsClientImpl::Core::Core(MDnsClientImpl* client) | 173 MDnsClientImpl::Core::Core(MDnsClientImpl* client) |
| 174 : client_(client), connection_(new MDnsConnection(this)) { | 174 : client_(client), connection_(new MDnsConnection(this)) { |
| 175 } | 175 } |
| 176 | 176 |
| 177 MDnsClientImpl::Core::~Core() { | 177 MDnsClientImpl::Core::~Core() { |
| 178 STLDeleteValues(&listeners_); | 178 STLDeleteValues(&listeners_); |
| 179 } | 179 } |
| 180 | 180 |
| 181 bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) { | 181 bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) { |
| 182 return connection_->Init(socket_factory); | 182 return connection_->Init(socket_factory); |
| 183 } | 183 } |
| 184 | 184 |
| 185 bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) { | 185 bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) { |
| 186 std::string name_dns; | 186 std::string name_dns; |
| 187 if (!DNSDomainFromDot(name, &name_dns)) | 187 if (!DNSDomainFromDot(name, &name_dns)) |
| 188 return false; | 188 return false; |
| 189 | 189 |
| 190 DnsQuery query(0, name_dns, rrtype); | 190 DnsQuery query(0, name_dns, rrtype); |
| 191 query.set_flags(0); // Remove the RD flag from the query. It is unneeded. | 191 query.set_flags(0); // Remove the RD flag from the query. It is unneeded. |
| 192 | 192 |
| 193 return connection_->Send(query.io_buffer(), query.io_buffer()->size()); | 193 return connection_->Send(query.io_buffer(), query.io_buffer()->size()); |
| 194 } | 194 } |
| 195 | 195 |
| 196 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response, | 196 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response, int bytes_read) { |
| 197 int bytes_read) { | |
| 198 unsigned offset; | 197 unsigned offset; |
| 199 // Note: We store cache keys rather than record pointers to avoid | 198 // Note: We store cache keys rather than record pointers to avoid |
| 200 // erroneous behavior in case a packet contains multiple exclusive | 199 // erroneous behavior in case a packet contains multiple exclusive |
| 201 // records with the same type and name. | 200 // records with the same type and name. |
| 202 std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys; | 201 std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys; |
| 203 | 202 |
| 204 if (!response->InitParseWithoutQuery(bytes_read)) { | 203 if (!response->InitParseWithoutQuery(bytes_read)) { |
| 205 DVLOG(1) << "Could not understand an mDNS packet."; | 204 DVLOG(1) << "Could not understand an mDNS packet."; |
| 206 return; // Message is unreadable. | 205 return; // Message is unreadable. |
| 207 } | 206 } |
| 208 | 207 |
| 209 // TODO(noamsml): duplicate query suppression. | 208 // TODO(noamsml): duplicate query suppression. |
| 210 if (!(response->flags() & dns_protocol::kFlagResponse)) | 209 if (!(response->flags() & dns_protocol::kFlagResponse)) |
| 211 return; // Message is a query. ignore it. | 210 return; // Message is a query. ignore it. |
| 212 | 211 |
| 213 DnsRecordParser parser = response->Parser(); | 212 DnsRecordParser parser = response->Parser(); |
| 214 unsigned answer_count = response->answer_count() + | 213 unsigned answer_count = |
| 215 response->additional_answer_count(); | 214 response->answer_count() + response->additional_answer_count(); |
| 216 | 215 |
| 217 for (unsigned i = 0; i < answer_count; i++) { | 216 for (unsigned i = 0; i < answer_count; i++) { |
| 218 offset = parser.GetOffset(); | 217 offset = parser.GetOffset(); |
| 219 scoped_ptr<const RecordParsed> record = RecordParsed::CreateFrom( | 218 scoped_ptr<const RecordParsed> record = |
| 220 &parser, base::Time::Now()); | 219 RecordParsed::CreateFrom(&parser, base::Time::Now()); |
| 221 | 220 |
| 222 if (!record) { | 221 if (!record) { |
| 223 DVLOG(1) << "Could not understand an mDNS record."; | 222 DVLOG(1) << "Could not understand an mDNS record."; |
| 224 | 223 |
| 225 if (offset == parser.GetOffset()) { | 224 if (offset == parser.GetOffset()) { |
| 226 DVLOG(1) << "Abandoned parsing the rest of the packet."; | 225 DVLOG(1) << "Abandoned parsing the rest of the packet."; |
| 227 return; // The parser did not advance, abort reading the packet. | 226 return; // The parser did not advance, abort reading the packet. |
| 228 } else { | 227 } else { |
| 229 continue; // We may be able to extract other records from the packet. | 228 continue; // We may be able to extract other records from the packet. |
| 230 } | 229 } |
| 231 } | 230 } |
| 232 | 231 |
| 233 if ((record->klass() & dns_protocol::kMDnsClassMask) != | 232 if ((record->klass() & dns_protocol::kMDnsClassMask) != |
| 234 dns_protocol::kClassIN) { | 233 dns_protocol::kClassIN) { |
| 235 DVLOG(1) << "Received an mDNS record with non-IN class. Ignoring."; | 234 DVLOG(1) << "Received an mDNS record with non-IN class. Ignoring."; |
| 236 continue; // Ignore all records not in the IN class. | 235 continue; // Ignore all records not in the IN class. |
| 237 } | 236 } |
| 238 | 237 |
| 239 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get()); | 238 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get()); |
| 240 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass()); | 239 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass()); |
| 241 | 240 |
| 242 // Cleanup time may have changed. | 241 // Cleanup time may have changed. |
| 243 ScheduleCleanup(cache_.next_expiration()); | 242 ScheduleCleanup(cache_.next_expiration()); |
| 244 | 243 |
| 245 update_keys.insert(std::make_pair(update_key, update)); | 244 update_keys.insert(std::make_pair(update_key, update)); |
| 246 } | 245 } |
| 247 | 246 |
| 248 for (std::map<MDnsCache::Key, MDnsCache::UpdateType>::iterator i = | 247 for (std::map<MDnsCache::Key, MDnsCache::UpdateType>::iterator i = |
| 249 update_keys.begin(); i != update_keys.end(); i++) { | 248 update_keys.begin(); |
| 249 i != update_keys.end(); |
| 250 i++) { |
| 250 const RecordParsed* record = cache_.LookupKey(i->first); | 251 const RecordParsed* record = cache_.LookupKey(i->first); |
| 251 if (!record) | 252 if (!record) |
| 252 continue; | 253 continue; |
| 253 | 254 |
| 254 if (record->type() == dns_protocol::kTypeNSEC) { | 255 if (record->type() == dns_protocol::kTypeNSEC) { |
| 255 #if defined(ENABLE_NSEC) | 256 #if defined(ENABLE_NSEC) |
| 256 NotifyNsecRecord(record); | 257 NotifyNsecRecord(record); |
| 257 #endif | 258 #endif |
| 258 } else { | 259 } else { |
| 259 AlertListeners(i->second, ListenerKey(record->name(), record->type()), | 260 AlertListeners( |
| 260 record); | 261 i->second, ListenerKey(record->name(), record->type()), record); |
| 261 } | 262 } |
| 262 } | 263 } |
| 263 } | 264 } |
| 264 | 265 |
| 265 void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) { | 266 void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) { |
| 266 DCHECK_EQ(dns_protocol::kTypeNSEC, record->type()); | 267 DCHECK_EQ(dns_protocol::kTypeNSEC, record->type()); |
| 267 const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>(); | 268 const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>(); |
| 268 DCHECK(rdata); | 269 DCHECK(rdata); |
| 269 | 270 |
| 270 // Remove all cached records matching the nonexistent RR types. | 271 // Remove all cached records matching the nonexistent RR types. |
| 271 std::vector<const RecordParsed*> records_to_remove; | 272 std::vector<const RecordParsed*> records_to_remove; |
| 272 | 273 |
| 273 cache_.FindDnsRecords(0, record->name(), &records_to_remove, | 274 cache_.FindDnsRecords( |
| 274 base::Time::Now()); | 275 0, record->name(), &records_to_remove, base::Time::Now()); |
| 275 | 276 |
| 276 for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin(); | 277 for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin(); |
| 277 i != records_to_remove.end(); i++) { | 278 i != records_to_remove.end(); |
| 279 i++) { |
| 278 if ((*i)->type() == dns_protocol::kTypeNSEC) | 280 if ((*i)->type() == dns_protocol::kTypeNSEC) |
| 279 continue; | 281 continue; |
| 280 if (!rdata->GetBit((*i)->type())) { | 282 if (!rdata->GetBit((*i)->type())) { |
| 281 scoped_ptr<const RecordParsed> record_removed = cache_.RemoveRecord((*i)); | 283 scoped_ptr<const RecordParsed> record_removed = cache_.RemoveRecord((*i)); |
| 282 DCHECK(record_removed); | 284 DCHECK(record_removed); |
| 283 OnRecordRemoved(record_removed.get()); | 285 OnRecordRemoved(record_removed.get()); |
| 284 } | 286 } |
| 285 } | 287 } |
| 286 | 288 |
| 287 // Alert all listeners waiting for the nonexistent RR types. | 289 // Alert all listeners waiting for the nonexistent RR types. |
| 288 ListenerMap::iterator i = | 290 ListenerMap::iterator i = |
| 289 listeners_.upper_bound(ListenerKey(record->name(), 0)); | 291 listeners_.upper_bound(ListenerKey(record->name(), 0)); |
| 290 for (; i != listeners_.end() && i->first.first == record->name(); i++) { | 292 for (; i != listeners_.end() && i->first.first == record->name(); i++) { |
| 291 if (!rdata->GetBit(i->first.second)) { | 293 if (!rdata->GetBit(i->first.second)) { |
| 292 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); | 294 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); |
| 293 } | 295 } |
| 294 } | 296 } |
| 295 } | 297 } |
| 296 | 298 |
| 297 void MDnsClientImpl::Core::OnConnectionError(int error) { | 299 void MDnsClientImpl::Core::OnConnectionError(int error) { |
| 298 // TODO(noamsml): On connection error, recreate connection and flush cache. | 300 // TODO(noamsml): On connection error, recreate connection and flush cache. |
| 299 } | 301 } |
| 300 | 302 |
| 301 void MDnsClientImpl::Core::AlertListeners( | 303 void MDnsClientImpl::Core::AlertListeners(MDnsCache::UpdateType update_type, |
| 302 MDnsCache::UpdateType update_type, | 304 const ListenerKey& key, |
| 303 const ListenerKey& key, | 305 const RecordParsed* record) { |
| 304 const RecordParsed* record) { | |
| 305 ListenerMap::iterator listener_map_iterator = listeners_.find(key); | 306 ListenerMap::iterator listener_map_iterator = listeners_.find(key); |
| 306 if (listener_map_iterator == listeners_.end()) return; | 307 if (listener_map_iterator == listeners_.end()) |
| 308 return; |
| 307 | 309 |
| 308 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second, | 310 FOR_EACH_OBSERVER(MDnsListenerImpl, |
| 311 *listener_map_iterator->second, |
| 309 HandleRecordUpdate(update_type, record)); | 312 HandleRecordUpdate(update_type, record)); |
| 310 } | 313 } |
| 311 | 314 |
| 312 void MDnsClientImpl::Core::AddListener( | 315 void MDnsClientImpl::Core::AddListener(MDnsListenerImpl* listener) { |
| 313 MDnsListenerImpl* listener) { | |
| 314 ListenerKey key(listener->GetName(), listener->GetType()); | 316 ListenerKey key(listener->GetName(), listener->GetType()); |
| 315 std::pair<ListenerMap::iterator, bool> observer_insert_result = | 317 std::pair<ListenerMap::iterator, bool> observer_insert_result = |
| 316 listeners_.insert( | 318 listeners_.insert( |
| 317 make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL))); | 319 make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL))); |
| 318 | 320 |
| 319 // If an equivalent key does not exist, actually create the observer list. | 321 // If an equivalent key does not exist, actually create the observer list. |
| 320 if (observer_insert_result.second) | 322 if (observer_insert_result.second) |
| 321 observer_insert_result.first->second = new ObserverList<MDnsListenerImpl>(); | 323 observer_insert_result.first->second = new ObserverList<MDnsListenerImpl>(); |
| 322 | 324 |
| 323 ObserverList<MDnsListenerImpl>* observer_list = | 325 ObserverList<MDnsListenerImpl>* observer_list = |
| 324 observer_insert_result.first->second; | 326 observer_insert_result.first->second; |
| 325 | 327 |
| 326 observer_list->AddObserver(listener); | 328 observer_list->AddObserver(listener); |
| 327 } | 329 } |
| 328 | 330 |
| 329 void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) { | 331 void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) { |
| 330 ListenerKey key(listener->GetName(), listener->GetType()); | 332 ListenerKey key(listener->GetName(), listener->GetType()); |
| 331 ListenerMap::iterator observer_list_iterator = listeners_.find(key); | 333 ListenerMap::iterator observer_list_iterator = listeners_.find(key); |
| 332 | 334 |
| 333 DCHECK(observer_list_iterator != listeners_.end()); | 335 DCHECK(observer_list_iterator != listeners_.end()); |
| 334 DCHECK(observer_list_iterator->second->HasObserver(listener)); | 336 DCHECK(observer_list_iterator->second->HasObserver(listener)); |
| 335 | 337 |
| 336 observer_list_iterator->second->RemoveObserver(listener); | 338 observer_list_iterator->second->RemoveObserver(listener); |
| 337 | 339 |
| 338 // Remove the observer list from the map if it is empty | 340 // Remove the observer list from the map if it is empty |
| 339 if (!observer_list_iterator->second->might_have_observers()) { | 341 if (!observer_list_iterator->second->might_have_observers()) { |
| 340 // Schedule the actual removal for later in case the listener removal | 342 // Schedule the actual removal for later in case the listener removal |
| 341 // happens while iterating over the observer list. | 343 // happens while iterating over the observer list. |
| 342 base::MessageLoop::current()->PostTask( | 344 base::MessageLoop::current()->PostTask( |
| 343 FROM_HERE, base::Bind( | 345 FROM_HERE, |
| 346 base::Bind( |
| 344 &MDnsClientImpl::Core::CleanupObserverList, AsWeakPtr(), key)); | 347 &MDnsClientImpl::Core::CleanupObserverList, AsWeakPtr(), key)); |
| 345 } | 348 } |
| 346 } | 349 } |
| 347 | 350 |
| 348 void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) { | 351 void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) { |
| 349 ListenerMap::iterator found = listeners_.find(key); | 352 ListenerMap::iterator found = listeners_.find(key); |
| 350 if (found != listeners_.end() && !found->second->might_have_observers()) { | 353 if (found != listeners_.end() && !found->second->might_have_observers()) { |
| 351 delete found->second; | 354 delete found->second; |
| 352 listeners_.erase(found); | 355 listeners_.erase(found); |
| 353 } | 356 } |
| 354 } | 357 } |
| 355 | 358 |
| 356 void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) { | 359 void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) { |
| 357 // Cleanup is already scheduled, no need to do anything. | 360 // Cleanup is already scheduled, no need to do anything. |
| 358 if (cleanup == scheduled_cleanup_) return; | 361 if (cleanup == scheduled_cleanup_) |
| 362 return; |
| 359 scheduled_cleanup_ = cleanup; | 363 scheduled_cleanup_ = cleanup; |
| 360 | 364 |
| 361 // This cancels the previously scheduled cleanup. | 365 // This cancels the previously scheduled cleanup. |
| 362 cleanup_callback_.Reset(base::Bind( | 366 cleanup_callback_.Reset( |
| 363 &MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); | 367 base::Bind(&MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); |
| 364 | 368 |
| 365 // If |cleanup| is empty, then no cleanup necessary. | 369 // If |cleanup| is empty, then no cleanup necessary. |
| 366 if (cleanup != base::Time()) { | 370 if (cleanup != base::Time()) { |
| 367 base::MessageLoop::current()->PostDelayedTask( | 371 base::MessageLoop::current()->PostDelayedTask( |
| 368 FROM_HERE, | 372 FROM_HERE, cleanup_callback_.callback(), cleanup - base::Time::Now()); |
| 369 cleanup_callback_.callback(), | |
| 370 cleanup - base::Time::Now()); | |
| 371 } | 373 } |
| 372 } | 374 } |
| 373 | 375 |
| 374 void MDnsClientImpl::Core::DoCleanup() { | 376 void MDnsClientImpl::Core::DoCleanup() { |
| 375 cache_.CleanupRecords(base::Time::Now(), base::Bind( | 377 cache_.CleanupRecords(base::Time::Now(), |
| 376 &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this))); | 378 base::Bind(&MDnsClientImpl::Core::OnRecordRemoved, |
| 379 base::Unretained(this))); |
| 377 | 380 |
| 378 ScheduleCleanup(cache_.next_expiration()); | 381 ScheduleCleanup(cache_.next_expiration()); |
| 379 } | 382 } |
| 380 | 383 |
| 381 void MDnsClientImpl::Core::OnRecordRemoved( | 384 void MDnsClientImpl::Core::OnRecordRemoved(const RecordParsed* record) { |
| 382 const RecordParsed* record) { | |
| 383 AlertListeners(MDnsCache::RecordRemoved, | 385 AlertListeners(MDnsCache::RecordRemoved, |
| 384 ListenerKey(record->name(), record->type()), record); | 386 ListenerKey(record->name(), record->type()), |
| 387 record); |
| 385 } | 388 } |
| 386 | 389 |
| 387 void MDnsClientImpl::Core::QueryCache( | 390 void MDnsClientImpl::Core::QueryCache( |
| 388 uint16 rrtype, const std::string& name, | 391 uint16 rrtype, |
| 392 const std::string& name, |
| 389 std::vector<const RecordParsed*>* records) const { | 393 std::vector<const RecordParsed*>* records) const { |
| 390 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); | 394 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); |
| 391 } | 395 } |
| 392 | 396 |
| 393 MDnsClientImpl::MDnsClientImpl() { | 397 MDnsClientImpl::MDnsClientImpl() { |
| 394 } | 398 } |
| 395 | 399 |
| 396 MDnsClientImpl::~MDnsClientImpl() { | 400 MDnsClientImpl::~MDnsClientImpl() { |
| 397 } | 401 } |
| 398 | 402 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 424 | 428 |
| 425 scoped_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction( | 429 scoped_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction( |
| 426 uint16 rrtype, | 430 uint16 rrtype, |
| 427 const std::string& name, | 431 const std::string& name, |
| 428 int flags, | 432 int flags, |
| 429 const MDnsTransaction::ResultCallback& callback) { | 433 const MDnsTransaction::ResultCallback& callback) { |
| 430 return scoped_ptr<MDnsTransaction>( | 434 return scoped_ptr<MDnsTransaction>( |
| 431 new MDnsTransactionImpl(rrtype, name, flags, callback, this)); | 435 new MDnsTransactionImpl(rrtype, name, flags, callback, this)); |
| 432 } | 436 } |
| 433 | 437 |
| 434 MDnsListenerImpl::MDnsListenerImpl( | 438 MDnsListenerImpl::MDnsListenerImpl(uint16 rrtype, |
| 435 uint16 rrtype, | 439 const std::string& name, |
| 436 const std::string& name, | 440 MDnsListener::Delegate* delegate, |
| 437 MDnsListener::Delegate* delegate, | 441 MDnsClientImpl* client) |
| 438 MDnsClientImpl* client) | 442 : rrtype_(rrtype), |
| 439 : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate), | 443 name_(name), |
| 440 started_(false), active_refresh_(false) { | 444 client_(client), |
| 445 delegate_(delegate), |
| 446 started_(false), |
| 447 active_refresh_(false) { |
| 441 } | 448 } |
| 442 | 449 |
| 443 MDnsListenerImpl::~MDnsListenerImpl() { | 450 MDnsListenerImpl::~MDnsListenerImpl() { |
| 444 if (started_) { | 451 if (started_) { |
| 445 DCHECK(client_->core()); | 452 DCHECK(client_->core()); |
| 446 client_->core()->RemoveListener(this); | 453 client_->core()->RemoveListener(this); |
| 447 } | 454 } |
| 448 } | 455 } |
| 449 | 456 |
| 450 bool MDnsListenerImpl::Start() { | 457 bool MDnsListenerImpl::Start() { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 | 531 |
| 525 if (!active_refresh_) | 532 if (!active_refresh_) |
| 526 return; | 533 return; |
| 527 | 534 |
| 528 // A zero TTL is a goodbye packet and should not be refreshed. | 535 // A zero TTL is a goodbye packet and should not be refreshed. |
| 529 if (ttl_ == 0) { | 536 if (ttl_ == 0) { |
| 530 next_refresh_.Cancel(); | 537 next_refresh_.Cancel(); |
| 531 return; | 538 return; |
| 532 } | 539 } |
| 533 | 540 |
| 534 next_refresh_.Reset(base::Bind(&MDnsListenerImpl::DoRefresh, | 541 next_refresh_.Reset(base::Bind(&MDnsListenerImpl::DoRefresh, AsWeakPtr())); |
| 535 AsWeakPtr())); | |
| 536 | 542 |
| 537 // Schedule refreshes at both 85% and 95% of the original TTL. These will both | 543 // Schedule refreshes at both 85% and 95% of the original TTL. These will both |
| 538 // be canceled and rescheduled if the record's TTL is updated due to a | 544 // be canceled and rescheduled if the record's TTL is updated due to a |
| 539 // response being received. | 545 // response being received. |
| 540 base::Time next_refresh1 = last_update_ + base::TimeDelta::FromMilliseconds( | 546 base::Time next_refresh1 = |
| 541 static_cast<int>(kMillisecondsPerSecond * | 547 last_update_ + |
| 542 kListenerRefreshRatio1 * ttl_)); | 548 base::TimeDelta::FromMilliseconds(static_cast<int>( |
| 549 kMillisecondsPerSecond * kListenerRefreshRatio1 * ttl_)); |
| 543 | 550 |
| 544 base::Time next_refresh2 = last_update_ + base::TimeDelta::FromMilliseconds( | 551 base::Time next_refresh2 = |
| 545 static_cast<int>(kMillisecondsPerSecond * | 552 last_update_ + |
| 546 kListenerRefreshRatio2 * ttl_)); | 553 base::TimeDelta::FromMilliseconds(static_cast<int>( |
| 554 kMillisecondsPerSecond * kListenerRefreshRatio2 * ttl_)); |
| 547 | 555 |
| 548 base::MessageLoop::current()->PostDelayedTask( | 556 base::MessageLoop::current()->PostDelayedTask( |
| 549 FROM_HERE, | 557 FROM_HERE, next_refresh_.callback(), next_refresh1 - base::Time::Now()); |
| 550 next_refresh_.callback(), | |
| 551 next_refresh1 - base::Time::Now()); | |
| 552 | 558 |
| 553 base::MessageLoop::current()->PostDelayedTask( | 559 base::MessageLoop::current()->PostDelayedTask( |
| 554 FROM_HERE, | 560 FROM_HERE, next_refresh_.callback(), next_refresh2 - base::Time::Now()); |
| 555 next_refresh_.callback(), | |
| 556 next_refresh2 - base::Time::Now()); | |
| 557 } | 561 } |
| 558 | 562 |
| 559 void MDnsListenerImpl::DoRefresh() { | 563 void MDnsListenerImpl::DoRefresh() { |
| 560 client_->core()->SendQuery(rrtype_, name_); | 564 client_->core()->SendQuery(rrtype_, name_); |
| 561 } | 565 } |
| 562 | 566 |
| 563 MDnsTransactionImpl::MDnsTransactionImpl( | 567 MDnsTransactionImpl::MDnsTransactionImpl( |
| 564 uint16 rrtype, | 568 uint16 rrtype, |
| 565 const std::string& name, | 569 const std::string& name, |
| 566 int flags, | 570 int flags, |
| 567 const MDnsTransaction::ResultCallback& callback, | 571 const MDnsTransaction::ResultCallback& callback, |
| 568 MDnsClientImpl* client) | 572 MDnsClientImpl* client) |
| 569 : rrtype_(rrtype), name_(name), callback_(callback), client_(client), | 573 : rrtype_(rrtype), |
| 570 started_(false), flags_(flags) { | 574 name_(name), |
| 575 callback_(callback), |
| 576 client_(client), |
| 577 started_(false), |
| 578 flags_(flags) { |
| 571 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_); | 579 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_); |
| 572 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE || | 580 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE || |
| 573 flags_ & MDnsTransaction::QUERY_NETWORK); | 581 flags_ & MDnsTransaction::QUERY_NETWORK); |
| 574 } | 582 } |
| 575 | 583 |
| 576 MDnsTransactionImpl::~MDnsTransactionImpl() { | 584 MDnsTransactionImpl::~MDnsTransactionImpl() { |
| 577 timeout_.Cancel(); | 585 timeout_.Cancel(); |
| 578 } | 586 } |
| 579 | 587 |
| 580 bool MDnsTransactionImpl::Start() { | 588 bool MDnsTransactionImpl::Start() { |
| 581 DCHECK(!started_); | 589 DCHECK(!started_); |
| 582 started_ = true; | 590 started_ = true; |
| 583 | 591 |
| 584 base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr(); | 592 base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr(); |
| 585 if (flags_ & MDnsTransaction::QUERY_CACHE) { | 593 if (flags_ & MDnsTransaction::QUERY_CACHE) { |
| 586 ServeRecordsFromCache(); | 594 ServeRecordsFromCache(); |
| 587 | 595 |
| 588 if (!weak_this || !is_active()) return true; | 596 if (!weak_this || !is_active()) |
| 597 return true; |
| 589 } | 598 } |
| 590 | 599 |
| 591 if (flags_ & MDnsTransaction::QUERY_NETWORK) { | 600 if (flags_ & MDnsTransaction::QUERY_NETWORK) { |
| 592 return QueryAndListen(); | 601 return QueryAndListen(); |
| 593 } | 602 } |
| 594 | 603 |
| 595 // If this is a cache only query, signal that the transaction is over | 604 // If this is a cache only query, signal that the transaction is over |
| 596 // immediately. | 605 // immediately. |
| 597 SignalTransactionOver(); | 606 SignalTransactionOver(); |
| 598 return true; | 607 return true; |
| 599 } | 608 } |
| 600 | 609 |
| 601 const std::string& MDnsTransactionImpl::GetName() const { | 610 const std::string& MDnsTransactionImpl::GetName() const { |
| 602 return name_; | 611 return name_; |
| 603 } | 612 } |
| 604 | 613 |
| 605 uint16 MDnsTransactionImpl::GetType() const { | 614 uint16 MDnsTransactionImpl::GetType() const { |
| 606 return rrtype_; | 615 return rrtype_; |
| 607 } | 616 } |
| 608 | 617 |
| 609 void MDnsTransactionImpl::CacheRecordFound(const RecordParsed* record) { | 618 void MDnsTransactionImpl::CacheRecordFound(const RecordParsed* record) { |
| 610 DCHECK(started_); | 619 DCHECK(started_); |
| 611 OnRecordUpdate(MDnsListener::RECORD_ADDED, record); | 620 OnRecordUpdate(MDnsListener::RECORD_ADDED, record); |
| 612 } | 621 } |
| 613 | 622 |
| 614 void MDnsTransactionImpl::TriggerCallback(MDnsTransaction::Result result, | 623 void MDnsTransactionImpl::TriggerCallback(MDnsTransaction::Result result, |
| 615 const RecordParsed* record) { | 624 const RecordParsed* record) { |
| 616 DCHECK(started_); | 625 DCHECK(started_); |
| 617 if (!is_active()) return; | 626 if (!is_active()) |
| 627 return; |
| 618 | 628 |
| 619 // Ensure callback is run after touching all class state, so that | 629 // Ensure callback is run after touching all class state, so that |
| 620 // the callback can delete the transaction. | 630 // the callback can delete the transaction. |
| 621 MDnsTransaction::ResultCallback callback = callback_; | 631 MDnsTransaction::ResultCallback callback = callback_; |
| 622 | 632 |
| 623 // Reset the transaction if it expects a single result, or if the result | 633 // Reset the transaction if it expects a single result, or if the result |
| 624 // is a final one (everything except for a record). | 634 // is a final one (everything except for a record). |
| 625 if (flags_ & MDnsTransaction::SINGLE_RESULT || | 635 if (flags_ & MDnsTransaction::SINGLE_RESULT || |
| 626 result != MDnsTransaction::RESULT_RECORD) { | 636 result != MDnsTransaction::RESULT_RECORD) { |
| 627 Reset(); | 637 Reset(); |
| 628 } | 638 } |
| 629 | 639 |
| 630 callback.Run(result, record); | 640 callback.Run(result, record); |
| 631 } | 641 } |
| 632 | 642 |
| 633 void MDnsTransactionImpl::Reset() { | 643 void MDnsTransactionImpl::Reset() { |
| 634 callback_.Reset(); | 644 callback_.Reset(); |
| 635 listener_.reset(); | 645 listener_.reset(); |
| 636 timeout_.Cancel(); | 646 timeout_.Cancel(); |
| 637 } | 647 } |
| 638 | 648 |
| 639 void MDnsTransactionImpl::OnRecordUpdate(MDnsListener::UpdateType update, | 649 void MDnsTransactionImpl::OnRecordUpdate(MDnsListener::UpdateType update, |
| 640 const RecordParsed* record) { | 650 const RecordParsed* record) { |
| 641 DCHECK(started_); | 651 DCHECK(started_); |
| 642 if (update == MDnsListener::RECORD_ADDED || | 652 if (update == MDnsListener::RECORD_ADDED || |
| 643 update == MDnsListener::RECORD_CHANGED) | 653 update == MDnsListener::RECORD_CHANGED) |
| 644 TriggerCallback(MDnsTransaction::RESULT_RECORD, record); | 654 TriggerCallback(MDnsTransaction::RESULT_RECORD, record); |
| 645 } | 655 } |
| 646 | 656 |
| 647 void MDnsTransactionImpl::SignalTransactionOver() { | 657 void MDnsTransactionImpl::SignalTransactionOver() { |
| 648 DCHECK(started_); | 658 DCHECK(started_); |
| 649 if (flags_ & MDnsTransaction::SINGLE_RESULT) { | 659 if (flags_ & MDnsTransaction::SINGLE_RESULT) { |
| 650 TriggerCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL); | 660 TriggerCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL); |
| 651 } else { | 661 } else { |
| 652 TriggerCallback(MDnsTransaction::RESULT_DONE, NULL); | 662 TriggerCallback(MDnsTransaction::RESULT_DONE, NULL); |
| 653 } | 663 } |
| 654 } | 664 } |
| 655 | 665 |
| 656 void MDnsTransactionImpl::ServeRecordsFromCache() { | 666 void MDnsTransactionImpl::ServeRecordsFromCache() { |
| 657 std::vector<const RecordParsed*> records; | 667 std::vector<const RecordParsed*> records; |
| 658 base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr(); | 668 base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr(); |
| 659 | 669 |
| 660 if (client_->core()) { | 670 if (client_->core()) { |
| 661 client_->core()->QueryCache(rrtype_, name_, &records); | 671 client_->core()->QueryCache(rrtype_, name_, &records); |
| 662 for (std::vector<const RecordParsed*>::iterator i = records.begin(); | 672 for (std::vector<const RecordParsed*>::iterator i = records.begin(); |
| 663 i != records.end() && weak_this; ++i) { | 673 i != records.end() && weak_this; |
| 674 ++i) { |
| 664 weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD, *i); | 675 weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD, *i); |
| 665 } | 676 } |
| 666 | 677 |
| 667 #if defined(ENABLE_NSEC) | 678 #if defined(ENABLE_NSEC) |
| 668 if (records.empty()) { | 679 if (records.empty()) { |
| 669 DCHECK(weak_this); | 680 DCHECK(weak_this); |
| 670 client_->core()->QueryCache(dns_protocol::kTypeNSEC, name_, &records); | 681 client_->core()->QueryCache(dns_protocol::kTypeNSEC, name_, &records); |
| 671 if (!records.empty()) { | 682 if (!records.empty()) { |
| 672 const NsecRecordRdata* rdata = | 683 const NsecRecordRdata* rdata = |
| 673 records.front()->rdata<NsecRecordRdata>(); | 684 records.front()->rdata<NsecRecordRdata>(); |
| 674 DCHECK(rdata); | 685 DCHECK(rdata); |
| 675 if (!rdata->GetBit(rrtype_)) | 686 if (!rdata->GetBit(rrtype_)) |
| 676 weak_this->TriggerCallback(MDnsTransaction::RESULT_NSEC, NULL); | 687 weak_this->TriggerCallback(MDnsTransaction::RESULT_NSEC, NULL); |
| 677 } | 688 } |
| 678 } | 689 } |
| 679 #endif | 690 #endif |
| 680 } | 691 } |
| 681 } | 692 } |
| 682 | 693 |
| 683 bool MDnsTransactionImpl::QueryAndListen() { | 694 bool MDnsTransactionImpl::QueryAndListen() { |
| 684 listener_ = client_->CreateListener(rrtype_, name_, this); | 695 listener_ = client_->CreateListener(rrtype_, name_, this); |
| 685 if (!listener_->Start()) | 696 if (!listener_->Start()) |
| 686 return false; | 697 return false; |
| 687 | 698 |
| 688 DCHECK(client_->core()); | 699 DCHECK(client_->core()); |
| 689 if (!client_->core()->SendQuery(rrtype_, name_)) | 700 if (!client_->core()->SendQuery(rrtype_, name_)) |
| 690 return false; | 701 return false; |
| 691 | 702 |
| 692 timeout_.Reset(base::Bind(&MDnsTransactionImpl::SignalTransactionOver, | 703 timeout_.Reset( |
| 693 AsWeakPtr())); | 704 base::Bind(&MDnsTransactionImpl::SignalTransactionOver, AsWeakPtr())); |
| 694 base::MessageLoop::current()->PostDelayedTask( | 705 base::MessageLoop::current()->PostDelayedTask( |
| 695 FROM_HERE, | 706 FROM_HERE, |
| 696 timeout_.callback(), | 707 timeout_.callback(), |
| 697 base::TimeDelta::FromSeconds(MDnsTransactionTimeoutSeconds)); | 708 base::TimeDelta::FromSeconds(MDnsTransactionTimeoutSeconds)); |
| 698 | 709 |
| 699 return true; | 710 return true; |
| 700 } | 711 } |
| 701 | 712 |
| 702 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { | 713 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { |
| 703 TriggerCallback(RESULT_NSEC, NULL); | 714 TriggerCallback(RESULT_NSEC, NULL); |
| 704 } | 715 } |
| 705 | 716 |
| 706 void MDnsTransactionImpl::OnCachePurged() { | 717 void MDnsTransactionImpl::OnCachePurged() { |
| 707 // TODO(noamsml): Cache purge situations not yet implemented | 718 // TODO(noamsml): Cache purge situations not yet implemented |
| 708 } | 719 } |
| 709 | 720 |
| 710 } // namespace net | 721 } // namespace net |
| OLD | NEW |