|
|
Created:
7 years, 7 months ago by Noam Samuel Modified:
7 years, 6 months ago CC:
chromium-reviews, cbentzel+watch_chromium.org, mmenke Base URL:
https://chromium.googlesource.com/chromium/src.git@mdns_implementation2 Visibility:
Public. |
DescriptionMulticast DNS implementation (initial)
An implementation of multicast DNS in net/. Currently, the multicast DNS
implementation supports the following features:
- Listeners, which can be notified of any changes to records of a certain type
and name, or records of a certain type.
- Transactions, which allow users to query multicast DNS for a specific unique
record (e.g. an address)
BUG=233821
TEST=MDnsTest.*,MDnsConnectionTest.*
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=206170
Patch Set 1 #
Total comments: 68
Patch Set 2 : Uploading to check comments against diff (next upload will have files renamed) #
Total comments: 2
Patch Set 3 : Renamed files from "listener" to "client" #
Total comments: 11
Patch Set 4 : #Patch Set 5 : #
Total comments: 61
Patch Set 6 : #Patch Set 7 : #
Total comments: 6
Patch Set 8 : #
Total comments: 27
Patch Set 9 : #Patch Set 10 : #
Total comments: 82
Patch Set 11 : #
Total comments: 2
Messages
Total messages: 31 (0 generated)
I have only skimmed it, but overall it seems that the reason you need to Clone() records is because you don't want to synchronously call the callback. I'm guessing you are particularly concerned that, if the request completes synchronously on creation, receiving the callback might be unexpected. This is precisely why DnsTransaction has |int Start()| and an accessor to DnsResponse*, and why HostResolver::Resolve takes an AddressList*. This allows both to finish synchronously and avoid passing ownership to the message loop task. I don't have a very strong opinion about this, but the approach to "pass everything asynchronously via message loop" is contrary to how the rest of src/net operates, that is: - if available synchronously: return result directly; - otherwise: return ERR_IO_PENDING and later call some callback. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h File net/dns/mdns_listener.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:18: extern const char kMDNSMulticastGroupIPv4[]; Why do you need this? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:23: class MDnsTransaction; I suggest you define MDnsTransaction first so that you don't have to forward declare it. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:31: }; Seems redundant with MDnsCache::UpdateType. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:39: class MDnsListenerFactory { Needs a comment. I find the name confusing. It can create Listeners and Transactions. I'd call it MDnsClient. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:49: // record. Not sure why there's TODO here. What part is missing? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:50: virtual void OnNSecRecord(const std::string& name, unsigned type) = 0; Spell "NSec" vs. "Nsec" consistently here and in MDnsTransactionResult. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:58: // Add delegate for RRType |rrtype| and name |name|. Comment says "Add delegate" but it creates a Listener. Probably best to have a class-level comment explaining what each class represents. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:64: bool active, Needs comment. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:65: bool alert_existing_records, Needs comment. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:85: // Destroing the transaction cancels pending transactions. "Destroying" "it" would be better than "pending transactions" https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:107: // Whether this listener is active (true) or passive (false) What does that mean? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:49: if (!RecieveOnePacket(socket_ipv4_.get(), What is the point of doing this? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); Why not just call: l->second->AlertDelegate(update_type, record)? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h File net/dns/mdns_listener_impl.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:28: class Core : public base::SupportsWeakPtr<Core> { Needs comment regarding lifetime. When is Core created? Who can hold weak pointers to it? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:62: void OnDatagramRecieved(UDPSocket* socket, Throughout the file: s/Recieve/Receive/ https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:67: // Request another packet from the network. The implementation shows that this calls RecvFrom without sending anything out. Why would anyone send us a packet? Can it wait indefinitely? What does this return? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:107: base::Time scheduled_cleanup_; DISALLOW_COPY_AND_ASSIGN. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:125: MDnsListenerFactory::Delegate* delegate) OVERRIDE; You don't need MDnsListenerFactory:: here and elsewhere in this file. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), To minimize flakiness, we'd test this with MockUDPClientSocket. Do you really need to test on UDPSocket? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:394: client_socket_->Close(); Not necessary. ~MDnsTest (called immediately after TearDown) will destroy and close all sockets. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_query.h File net/dns/mdns_query.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_query.h#newcode19 net/dns/mdns_query.h:19: // Note: Currently this class is very similar to DnsQuery, but it is kept If, in this CL, DnsQuery is the superset of MDnsQuery, please use DnsQuery. https://codereview.chromium.org/15733008/diff/1/net/test/fake_time_system.h File net/test/fake_time_system.h (right): https://codereview.chromium.org/15733008/diff/1/net/test/fake_time_system.h#n... net/test/fake_time_system.h:16: class FakeTimeSystem : public base::Clock, public base::TaskRunner { Needs class-level comment. Not sure you need this.
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h File net/dns/mdns_listener.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:31: }; MDnsCache::UpdateType contains a NoChange member, which can never be used as an update type. I thought it would be unclear if they used the same enum (users will think they have to handle the NoChange case, and compilers will produce errors for switch statements that don't handle it). On 2013/05/24 15:32:22, szym wrote: > Seems redundant with MDnsCache::UpdateType. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:49: // record. Maybe the TODO should be moved somewhere else. The TODO refers to actually implementing NSEC record parsing. On 2013/05/24 15:32:22, szym wrote: > Not sure why there's TODO here. What part is missing? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:107: // Whether this listener is active (true) or passive (false) On 2013/05/24 15:32:22, szym wrote: > What does that mean? An active listener is allowed to send periodic queries to see if new records of a given type are available. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:49: if (!RecieveOnePacket(socket_ipv4_.get(), On 2013/05/24 15:32:22, szym wrote: > What is the point of doing this? Oh. I guess this method is somewhat misnamed. RecieveOnePacket is used to request a packet. It sets a handler for receiving the packet that processes it and then requests the next packet. This is the "main loop" for the mDNS listener. Not 100% sure what to name it; maybe "RecieveNextPacket"? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); Listener delegates may create or delete any listeners. Thus, the iterator may become invalid while iterating over the listeners. On a second look, this can be solved by storing weak pointers to the listeners and copying them to a separate collection before iterating over them. Another problem is that a listener delegate is allowed to delete all listeners, which would stop the client from listening for MDns packets, and would in turn delete the cache (since it can no longer be kept up to date), which owns the record, and thus delete the record itself. Therefore, IMO, it makes sense to at least copy the record, even if we call the delegates synchronously. Alternately, it is be possible to make the starting/stopping of listening for mDNS more explicit by requiring users of the API to call AddListenRef and RemoveListenRef explicitly when they start/stop using mDNS. On 2013/05/24 15:32:22, szym wrote: > Why not just call: l->second->AlertDelegate(update_type, record)? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h File net/dns/mdns_listener_impl.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:28: class Core : public base::SupportsWeakPtr<Core> { On 2013/05/24 15:32:22, szym wrote: > Needs comment regarding lifetime. When is Core created? Who can hold weak > pointers to it? The weak pointer-ability of these classes is mostly used to allow scheduling methods on them through the message loop. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:67: // Request another packet from the network. It does wait indefinitely. It does so in an asynchronous fashion. Since every MDns client has to act as a server, this is actually part of a listening loop that continually listens for packets sent to the mDNS multicast group. On 2013/05/24 15:32:22, szym wrote: > The implementation shows that this calls RecvFrom without sending anything out. > Why would anyone send us a packet? Can it wait indefinitely? > > What does this return?
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h File net/dns/mdns_listener.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:18: extern const char kMDNSMulticastGroupIPv4[]; I put it here so that classes other than the implementation can access it. However, this seems excessive. I will move it to the implmentation .cc. On 2013/05/24 15:32:22, szym wrote: > Why do you need this? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), Hm. I tend to agree that, in retrospect, using mock sockets rather than loopback network traffic may be simpler. These sockets are actually used to create mock network traffic for the MDnsClient. The sockets inside MDnsClient are used as servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I could use it in the MDnsClient and then create a mock version of UDPServerSocket. On 2013/05/24 15:32:22, szym wrote: > To minimize flakiness, we'd test this with MockUDPClientSocket. Do you really > need to test on UDPSocket? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_query.h File net/dns/mdns_query.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_query.h#newcode19 net/dns/mdns_query.h:19: // Note: Currently this class is very similar to DnsQuery, but it is kept On 2013/05/24 15:32:22, szym wrote: > If, in this CL, DnsQuery is the superset of MDnsQuery, please use DnsQuery. The one difference I see is that an MDns query should not set the RD flag. Does it make sense to add a method to change the flags on a query?
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); On second thought, deferring shutting down listening (i.e. having it not occur synchronously) is probably a better solution. That way we also don't wipe the cache if someone has exactly one listener and then destroys it and immediately creates another listener. On 2013/05/24 19:00:49, Noam Samuel wrote: > Listener delegates may create or delete any listeners. Thus, the iterator may > become invalid while iterating over the listeners. > > On a second look, this can be solved by storing weak pointers to the listeners > and copying them to a separate collection before iterating over them. > > Another problem is that a listener delegate is allowed to delete all listeners, > which would stop the client from listening for MDns packets, and would in turn > delete the cache (since it can no longer be kept up to date), which owns the > record, and thus delete the record itself. Therefore, IMO, it makes sense to at > least copy the record, even if we call the delegates synchronously. > > Alternately, it is be possible to make the starting/stopping of listening for > mDNS more explicit by requiring users of the API to call AddListenRef and > RemoveListenRef explicitly when they start/stop using mDNS. > > On 2013/05/24 15:32:22, szym wrote: > > Why not just call: l->second->AlertDelegate(update_type, record)? >
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:120: AsWeakPtr(), socket, response, recv_addr)); You don't really need WeakPtr here since if Core is gone, so is |socket|. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:125: base::Bind(&MDnsListenerFactoryImpl::Core::OnDatagramRecieved, Why not call synchronously? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); You could consider using std::map<ListenerKey, ObserverList<MDnsListenerImpl> > instead of std::multimap. ObserverList uses very simple technique to safely handle removals during iteration. If you go this route, you can avoid losing the whole client during callbacks by simply taking a "scoped" reference in AlertListeners. On 2013/05/24 22:34:20, Noam Samuel wrote: > On second thought, deferring shutting down listening (i.e. having it not occur > synchronously) is probably a better solution. That way we also don't wipe the > cache if someone has exactly one listener and then destroys it and immediately > creates another listener. > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > Listener delegates may create or delete any listeners. Thus, the iterator may > > become invalid while iterating over the listeners. > > > > On a second look, this can be solved by storing weak pointers to the listeners > > and copying them to a separate collection before iterating over them. > > > > Another problem is that a listener delegate is allowed to delete all > listeners, > > which would stop the client from listening for MDns packets, and would in turn > > delete the cache (since it can no longer be kept up to date), which owns the > > record, and thus delete the record itself. Therefore, IMO, it makes sense to > at > > least copy the record, even if we call the delegates synchronously. > > > > Alternately, it is be possible to make the starting/stopping of listening for > > mDNS more explicit by requiring users of the API to call AddListenRef and > > RemoveListenRef explicitly when they start/stop using mDNS. > > > > On 2013/05/24 15:32:22, szym wrote: > > > Why not just call: l->second->AlertDelegate(update_type, record)? > > > https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h File net/dns/mdns_listener_impl.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:28: class Core : public base::SupportsWeakPtr<Core> { Still needs a comment in the code. On 2013/05/24 19:00:49, Noam Samuel wrote: > On 2013/05/24 15:32:22, szym wrote: > > Needs comment regarding lifetime. When is Core created? Who can hold weak > > pointers to it? > > The weak pointer-ability of these classes is mostly used to allow scheduling > methods on them through the message loop.
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:125: base::Bind(&MDnsListenerFactoryImpl::Core::OnDatagramRecieved, If an attacker were to spam the mdns port with packets while you're listening, they could cause a stack overflow if this call is synchronized. If this call is not synchronized it will gladly accept infinitely many packets. On 2013/05/25 02:51:01, szym wrote: > Why not call synchronously? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); Taking a scoped reference in the class entrypoints that may call AlertListeners does work, but since it's more complicated to reason about (What if someone creates another class entrypoint that may call AlertListeners and forgets to add a scoped listen reference? The problem may not be immediately apparent), I prefer to go the route of using the message loop to defer deletion. On 2013/05/25 02:51:01, szym wrote: > You could consider using std::map<ListenerKey, ObserverList<MDnsListenerImpl> > > instead of std::multimap. ObserverList uses very simple technique to safely > handle removals during iteration. > > If you go this route, you can avoid losing the whole client during callbacks by > simply taking a "scoped" reference in AlertListeners. > > > On 2013/05/24 22:34:20, Noam Samuel wrote: > > On second thought, deferring shutting down listening (i.e. having it not occur > > synchronously) is probably a better solution. That way we also don't wipe the > > cache if someone has exactly one listener and then destroys it and immediately > > creates another listener. > > > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > > Listener delegates may create or delete any listeners. Thus, the iterator > may > > > become invalid while iterating over the listeners. > > > > > > On a second look, this can be solved by storing weak pointers to the > listeners > > > and copying them to a separate collection before iterating over them. > > > > > > Another problem is that a listener delegate is allowed to delete all > > listeners, > > > which would stop the client from listening for MDns packets, and would in > turn > > > delete the cache (since it can no longer be kept up to date), which owns the > > > record, and thus delete the record itself. Therefore, IMO, it makes sense to > > at > > > least copy the record, even if we call the delegates synchronously. > > > > > > Alternately, it is be possible to make the starting/stopping of listening > for > > > mDNS more explicit by requiring users of the API to call AddListenRef and > > > RemoveListenRef explicitly when they start/stop using mDNS. > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > Why not just call: l->second->AlertDelegate(update_type, record)? > > > > > >
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:125: base::Bind(&MDnsListenerFactoryImpl::Core::OnDatagramRecieved, On 2013/05/29 17:53:03, Noam Samuel wrote: > If an attacker were to spam the mdns port with packets while you're listening, > they could cause a stack overflow if this call is synchronized. If this call is > not synchronized it will gladly accept infinitely many packets. > > On 2013/05/25 02:51:01, szym wrote: > > Why not call synchronously? The solution to this is to replace recursion with iteration. This is the common "DoLoop" pattern in net/. OnDatagramReceived should return to the loop rather than call through to ReceiveOnePacket. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); Ok, but now you have to deal with a situation where a listener says "remove me", so you should not call it again. But in another callback the listener says "add me". One solution is to keep per-listener state ("is active") and only clean the listeners up after all callbacks finished. You now need to go through all listeners twice, but it shouldn't be very expensive (and no more expensive than RemoveListener). On 2013/05/29 17:53:03, Noam Samuel wrote: > Taking a scoped reference in the class entrypoints that may call AlertListeners > does work, but since it's more complicated to reason about (What if someone > creates another class entrypoint that may call AlertListeners and forgets to add > a scoped listen reference? The problem may not be immediately apparent), I > prefer to go the route of using the message loop to defer deletion. > > On 2013/05/25 02:51:01, szym wrote: > > You could consider using std::map<ListenerKey, ObserverList<MDnsListenerImpl> > > > > instead of std::multimap. ObserverList uses very simple technique to safely > > handle removals during iteration. > > > > If you go this route, you can avoid losing the whole client during callbacks > by > > simply taking a "scoped" reference in AlertListeners. > > > > > > On 2013/05/24 22:34:20, Noam Samuel wrote: > > > On second thought, deferring shutting down listening (i.e. having it not > occur > > > synchronously) is probably a better solution. That way we also don't wipe > the > > > cache if someone has exactly one listener and then destroys it and > immediately > > > creates another listener. > > > > > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > > > Listener delegates may create or delete any listeners. Thus, the iterator > > may > > > > become invalid while iterating over the listeners. > > > > > > > > On a second look, this can be solved by storing weak pointers to the > > listeners > > > > and copying them to a separate collection before iterating over them. > > > > > > > > Another problem is that a listener delegate is allowed to delete all > > > listeners, > > > > which would stop the client from listening for MDns packets, and would in > > turn > > > > delete the cache (since it can no longer be kept up to date), which owns > the > > > > record, and thus delete the record itself. Therefore, IMO, it makes sense > to > > > at > > > > least copy the record, even if we call the delegates synchronously. > > > > > > > > Alternately, it is be possible to make the starting/stopping of listening > > for > > > > mDNS more explicit by requiring users of the API to call AddListenRef and > > > > RemoveListenRef explicitly when they start/stop using mDNS. > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > Why not just call: l->second->AlertDelegate(update_type, record)? > > > > > > > > >
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); Each individual listener is added/removed in an RAII fashion, so it should be impossible for a listener to add itself after it removes itself. When using deferred deletion, if another listener is added after the last listen ref is removed and before the core is actually deleted, a listen ref will be added and when the scheduled core deletion happens, the client will see that there is a non-zero number of listen refs and will not delete the core. On 2013/05/29 17:59:41, szym wrote: > Ok, but now you have to deal with a situation where a listener says "remove me", > so you should not call it again. But in another callback the listener says "add > me". > > One solution is to keep per-listener state ("is active") and only clean the > listeners up after all callbacks finished. You now need to go through all > listeners twice, but it shouldn't be very expensive (and no more expensive than > RemoveListener). > > On 2013/05/29 17:53:03, Noam Samuel wrote: > > Taking a scoped reference in the class entrypoints that may call > AlertListeners > > does work, but since it's more complicated to reason about (What if someone > > creates another class entrypoint that may call AlertListeners and forgets to > add > > a scoped listen reference? The problem may not be immediately apparent), I > > prefer to go the route of using the message loop to defer deletion. > > > > On 2013/05/25 02:51:01, szym wrote: > > > You could consider using std::map<ListenerKey, > ObserverList<MDnsListenerImpl> > > > > > > instead of std::multimap. ObserverList uses very simple technique to safely > > > handle removals during iteration. > > > > > > If you go this route, you can avoid losing the whole client during callbacks > > by > > > simply taking a "scoped" reference in AlertListeners. > > > > > > > > > On 2013/05/24 22:34:20, Noam Samuel wrote: > > > > On second thought, deferring shutting down listening (i.e. having it not > > occur > > > > synchronously) is probably a better solution. That way we also don't wipe > > the > > > > cache if someone has exactly one listener and then destroys it and > > immediately > > > > creates another listener. > > > > > > > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > > > > Listener delegates may create or delete any listeners. Thus, the > iterator > > > may > > > > > become invalid while iterating over the listeners. > > > > > > > > > > On a second look, this can be solved by storing weak pointers to the > > > listeners > > > > > and copying them to a separate collection before iterating over them. > > > > > > > > > > Another problem is that a listener delegate is allowed to delete all > > > > listeners, > > > > > which would stop the client from listening for MDns packets, and would > in > > > turn > > > > > delete the cache (since it can no longer be kept up to date), which owns > > the > > > > > record, and thus delete the record itself. Therefore, IMO, it makes > sense > > to > > > > at > > > > > least copy the record, even if we call the delegates synchronously. > > > > > > > > > > Alternately, it is be possible to make the starting/stopping of > listening > > > for > > > > > mDNS more explicit by requiring users of the API to call AddListenRef > and > > > > > RemoveListenRef explicitly when they start/stop using mDNS. > > > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > > Why not just call: l->second->AlertDelegate(update_type, record)? > > > > > > > > > > > > >
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); With deferred deletion, how do you avoid calling back a listener removed during callback. On 2013/05/29 18:35:35, Noam Samuel wrote: > Each individual listener is added/removed in an RAII fashion, so it should be > impossible for a listener to add itself after it removes itself. > > When using deferred deletion, if another listener is added after the last listen > ref is removed and before the core is actually deleted, a listen ref will be > added and when the scheduled core deletion happens, the client will see that > there is a non-zero number of listen refs and will not delete the core. > > On 2013/05/29 17:59:41, szym wrote: > > Ok, but now you have to deal with a situation where a listener says "remove > me", > > so you should not call it again. But in another callback the listener says > "add > > me". > > > > One solution is to keep per-listener state ("is active") and only clean the > > listeners up after all callbacks finished. You now need to go through all > > listeners twice, but it shouldn't be very expensive (and no more expensive > than > > RemoveListener). > > > > On 2013/05/29 17:53:03, Noam Samuel wrote: > > > Taking a scoped reference in the class entrypoints that may call > > AlertListeners > > > does work, but since it's more complicated to reason about (What if someone > > > creates another class entrypoint that may call AlertListeners and forgets to > > add > > > a scoped listen reference? The problem may not be immediately apparent), I > > > prefer to go the route of using the message loop to defer deletion. > > > > > > On 2013/05/25 02:51:01, szym wrote: > > > > You could consider using std::map<ListenerKey, > > ObserverList<MDnsListenerImpl> > > > > > > > > instead of std::multimap. ObserverList uses very simple technique to > safely > > > > handle removals during iteration. > > > > > > > > If you go this route, you can avoid losing the whole client during > callbacks > > > by > > > > simply taking a "scoped" reference in AlertListeners. > > > > > > > > > > > > On 2013/05/24 22:34:20, Noam Samuel wrote: > > > > > On second thought, deferring shutting down listening (i.e. having it not > > > occur > > > > > synchronously) is probably a better solution. That way we also don't > wipe > > > the > > > > > cache if someone has exactly one listener and then destroys it and > > > immediately > > > > > creates another listener. > > > > > > > > > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > > > > > Listener delegates may create or delete any listeners. Thus, the > > iterator > > > > may > > > > > > become invalid while iterating over the listeners. > > > > > > > > > > > > On a second look, this can be solved by storing weak pointers to the > > > > listeners > > > > > > and copying them to a separate collection before iterating over them. > > > > > > > > > > > > Another problem is that a listener delegate is allowed to delete all > > > > > listeners, > > > > > > which would stop the client from listening for MDns packets, and would > > in > > > > turn > > > > > > delete the cache (since it can no longer be kept up to date), which > owns > > > the > > > > > > record, and thus delete the record itself. Therefore, IMO, it makes > > sense > > > to > > > > > at > > > > > > least copy the record, even if we call the delegates synchronously. > > > > > > > > > > > > Alternately, it is be possible to make the starting/stopping of > > listening > > > > for > > > > > > mDNS more explicit by requiring users of the API to call AddListenRef > > and > > > > > > RemoveListenRef explicitly when they start/stop using mDNS. > > > > > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > > > Why not just call: l->second->AlertDelegate(update_type, record)? > > > > > > > > > > > > > > > > > >
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:233: base::Owned(record_clone.release())) ); Oh, sorry. The deferred deletion applies only to the core as a whole, so I still remove listeners immediately, but then if the last listener is removed, forcing a deletion of the core (the object that contains the connection and cache), I defer the deletion of the core using the message loop. The code looks like this: void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) { <Irrelevant> client_->SubtractListenRef(); } void MDnsClientImpl::SubtractListenRef() { listen_refs_--; if (listen_refs_ == 0) { task_runner_->PostTask(FROM_HERE, base::Bind( &MDnsClientImpl::Shutdown, base::Unretained(this))); } } void MDnsClientImpl::Shutdown() { // We need to check that new listeners haven't been created. if (listen_refs_ == 0) { core_.reset(); } } On 2013/05/29 18:40:43, szym wrote: > With deferred deletion, how do you avoid calling back a listener removed during > callback. > > On 2013/05/29 18:35:35, Noam Samuel wrote: > > Each individual listener is added/removed in an RAII fashion, so it should be > > impossible for a listener to add itself after it removes itself. > > > > When using deferred deletion, if another listener is added after the last > listen > > ref is removed and before the core is actually deleted, a listen ref will be > > added and when the scheduled core deletion happens, the client will see that > > there is a non-zero number of listen refs and will not delete the core. > > > > On 2013/05/29 17:59:41, szym wrote: > > > Ok, but now you have to deal with a situation where a listener says "remove > > me", > > > so you should not call it again. But in another callback the listener says > > "add > > > me". > > > > > > One solution is to keep per-listener state ("is active") and only clean the > > > listeners up after all callbacks finished. You now need to go through all > > > listeners twice, but it shouldn't be very expensive (and no more expensive > > than > > > RemoveListener). > > > > > > On 2013/05/29 17:53:03, Noam Samuel wrote: > > > > Taking a scoped reference in the class entrypoints that may call > > > AlertListeners > > > > does work, but since it's more complicated to reason about (What if > someone > > > > creates another class entrypoint that may call AlertListeners and forgets > to > > > add > > > > a scoped listen reference? The problem may not be immediately apparent), I > > > > prefer to go the route of using the message loop to defer deletion. > > > > > > > > On 2013/05/25 02:51:01, szym wrote: > > > > > You could consider using std::map<ListenerKey, > > > ObserverList<MDnsListenerImpl> > > > > > > > > > > instead of std::multimap. ObserverList uses very simple technique to > > safely > > > > > handle removals during iteration. > > > > > > > > > > If you go this route, you can avoid losing the whole client during > > callbacks > > > > by > > > > > simply taking a "scoped" reference in AlertListeners. > > > > > > > > > > > > > > > On 2013/05/24 22:34:20, Noam Samuel wrote: > > > > > > On second thought, deferring shutting down listening (i.e. having it > not > > > > occur > > > > > > synchronously) is probably a better solution. That way we also don't > > wipe > > > > the > > > > > > cache if someone has exactly one listener and then destroys it and > > > > immediately > > > > > > creates another listener. > > > > > > > > > > > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > > > > > > Listener delegates may create or delete any listeners. Thus, the > > > iterator > > > > > may > > > > > > > become invalid while iterating over the listeners. > > > > > > > > > > > > > > On a second look, this can be solved by storing weak pointers to the > > > > > listeners > > > > > > > and copying them to a separate collection before iterating over > them. > > > > > > > > > > > > > > Another problem is that a listener delegate is allowed to delete all > > > > > > listeners, > > > > > > > which would stop the client from listening for MDns packets, and > would > > > in > > > > > turn > > > > > > > delete the cache (since it can no longer be kept up to date), which > > owns > > > > the > > > > > > > record, and thus delete the record itself. Therefore, IMO, it makes > > > sense > > > > to > > > > > > at > > > > > > > least copy the record, even if we call the delegates synchronously. > > > > > > > > > > > > > > Alternately, it is be possible to make the starting/stopping of > > > listening > > > > > for > > > > > > > mDNS more explicit by requiring users of the API to call > AddListenRef > > > and > > > > > > > RemoveListenRef explicitly when they start/stop using mDNS. > > > > > > > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > > > > Why not just call: l->second->AlertDelegate(update_type, record)? > > > > > > > > > > > > > > > > > > > > > > > >
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h File net/dns/mdns_listener.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:18: extern const char kMDNSMulticastGroupIPv4[]; On 2013/05/24 21:59:18, Noam Samuel wrote: > I put it here so that classes other than the implementation can access it. > However, this seems excessive. I will move it to the implmentation .cc. > On 2013/05/24 15:32:22, szym wrote: > > Why do you need this? > Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:23: class MDnsTransaction; On 2013/05/24 15:32:22, szym wrote: > I suggest you define MDnsTransaction first so that you don't have to forward > declare it. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:39: class MDnsListenerFactory { On 2013/05/24 15:32:22, szym wrote: > Needs a comment. I find the name confusing. It can create Listeners and > Transactions. I'd call it MDnsClient. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:49: // record. On 2013/05/24 19:00:49, Noam Samuel wrote: > Maybe the TODO should be moved somewhere else. The TODO refers to actually > implementing NSEC record parsing. > > On 2013/05/24 15:32:22, szym wrote: > > Not sure why there's TODO here. What part is missing? > Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:50: virtual void OnNSecRecord(const std::string& name, unsigned type) = 0; On 2013/05/24 15:32:22, szym wrote: > Spell "NSec" vs. "Nsec" consistently here and in MDnsTransactionResult. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:58: // Add delegate for RRType |rrtype| and name |name|. On 2013/05/24 15:32:22, szym wrote: > Comment says "Add delegate" but it creates a Listener. Probably best to have a > class-level comment explaining what each class represents. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:64: bool active, On 2013/05/24 15:32:22, szym wrote: > Needs comment. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:65: bool alert_existing_records, On 2013/05/24 15:32:22, szym wrote: > Needs comment. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:85: // Destroing the transaction cancels pending transactions. On 2013/05/24 15:32:22, szym wrote: > "Destroying" > "it" would be better than "pending transactions" Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener.h#newco... net/dns/mdns_listener.h:107: // Whether this listener is active (true) or passive (false) On 2013/05/24 19:00:49, Noam Samuel wrote: > On 2013/05/24 15:32:22, szym wrote: > > What does that mean? > > An active listener is allowed to send periodic queries to see if new records of > a given type are available. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:49: if (!RecieveOnePacket(socket_ipv4_.get(), Renamed method and moved it to MDnsConnectionImpl. On 2013/05/24 19:00:49, Noam Samuel wrote: > On 2013/05/24 15:32:22, szym wrote: > > What is the point of doing this? > > Oh. I guess this method is somewhat misnamed. RecieveOnePacket is used to > request a packet. It sets a handler for receiving the packet that processes it > and then requests the next packet. This is the "main loop" for the mDNS > listener. Not 100% sure what to name it; maybe "RecieveNextPacket"? https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:120: AsWeakPtr(), socket, response, recv_addr)); On 2013/05/25 02:51:01, szym wrote: > You don't really need WeakPtr here since if Core is gone, so is |socket|. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.cc... net/dns/mdns_listener_impl.cc:125: base::Bind(&MDnsListenerFactoryImpl::Core::OnDatagramRecieved, On 2013/05/29 17:59:41, szym wrote: > On 2013/05/29 17:53:03, Noam Samuel wrote: > > If an attacker were to spam the mdns port with packets while you're listening, > > they could cause a stack overflow if this call is synchronized. If this call > is > > not synchronized it will gladly accept infinitely many packets. > > > > On 2013/05/25 02:51:01, szym wrote: > > > Why not call synchronously? > > The solution to this is to replace recursion with iteration. This is the common > "DoLoop" pattern in net/. OnDatagramReceived should return to the loop rather > than call through to ReceiveOnePacket. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h File net/dns/mdns_listener_impl.h (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:28: class Core : public base::SupportsWeakPtr<Core> { On 2013/05/25 02:51:01, szym wrote: > Still needs a comment in the code. > > On 2013/05/24 19:00:49, Noam Samuel wrote: > > On 2013/05/24 15:32:22, szym wrote: > > > Needs comment regarding lifetime. When is Core created? Who can hold weak > > > pointers to it? > > > > The weak pointer-ability of these classes is mostly used to allow scheduling > > methods on them through the message loop. > Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:62: void OnDatagramRecieved(UDPSocket* socket, On 2013/05/24 15:32:22, szym wrote: > Throughout the file: s/Recieve/Receive/ Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:107: base::Time scheduled_cleanup_; On 2013/05/24 15:32:22, szym wrote: > DISALLOW_COPY_AND_ASSIGN. Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_impl.h#... net/dns/mdns_listener_impl.h:125: MDnsListenerFactory::Delegate* delegate) OVERRIDE; Moved all the delegates and callbacks to their respective objects. On 2013/05/24 15:32:22, szym wrote: > You don't need MDnsListenerFactory:: here and elsewhere in this file. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), On 2013/05/24 21:59:18, Noam Samuel wrote: > Hm. I tend to agree that, in retrospect, using mock sockets rather than loopback > network traffic may be simpler. These sockets are actually used to create mock > network traffic for the MDnsClient. The sockets inside MDnsClient are used as > servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I could use it > in the MDnsClient and then create a mock version of UDPServerSocket. > > On 2013/05/24 15:32:22, szym wrote: > > To minimize flakiness, we'd test this with MockUDPClientSocket. Do you really > > need to test on UDPSocket? > Done. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:394: client_socket_->Close(); On 2013/05/24 15:32:22, szym wrote: > Not necessary. ~MDnsTest (called immediately after TearDown) will destroy and > close all sockets. Done. https://codereview.chromium.org/15733008/diff/1/net/test/fake_time_system.h File net/test/fake_time_system.h (right): https://codereview.chromium.org/15733008/diff/1/net/test/fake_time_system.h#n... net/test/fake_time_system.h:16: class FakeTimeSystem : public base::Clock, public base::TaskRunner { On 2013/05/24 15:32:22, szym wrote: > Needs class-level comment. Not sure you need this. Done.
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), On 2013/05/29 21:25:16, Noam Samuel wrote: > On 2013/05/24 21:59:18, Noam Samuel wrote: > > Hm. I tend to agree that, in retrospect, using mock sockets rather than > loopback > > network traffic may be simpler. These sockets are actually used to create mock > > network traffic for the MDnsClient. The sockets inside MDnsClient are used as > > servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I could use > it > > in the MDnsClient and then create a mock version of UDPServerSocket. > > > > On 2013/05/24 15:32:22, szym wrote: > > > To minimize flakiness, we'd test this with MockUDPClientSocket. Do you > really > > > need to test on UDPSocket? > > > > Done. I still see UDPSocket rather than DatagramServerSocket. https://codereview.chromium.org/15733008/diff/17001/net/dns/mdns_listener_imp... File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/17001/net/dns/mdns_listener_imp... net/dns/mdns_listener_impl.cc:579: delegate_->HandlePacket(response, rval); This needs to be adjusted to follow the common design pattern in net. Please take a look at other DoLoop methods in src/net. In your case you have two sockets that you want to process "in parallel", so I suggest creating two instances of a class implementing DoLoop, each wrapping one socket and response buffer. Because the processing is very simple (recv and handle), you don't really need States. It could really be as simple as: Receiver::DoLoop(int rv) { do { if (rv > 0) delegate_->HandlePacket(rv, buffer_); rv = socket_->Recv(buffer, Bind(Receiver::OnDatagramReceived, Unretained(this))); } while (rv > 0); if (rv != ERR_IO_PENDING) delegate_->HandleError(rv); } Receiver::OnDatagramReceived(int rv) { DoLoop(rv); } Connection::Start() { ipv4_receiver_->DoLoop(0); ipv6_receiver_->DoLoop(0); } https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:30: : client_(client), task_runner_(task_runner), clock_(clock), The only reason I see for this dependency on TaskRunner and Clock is that you want to be able to inject mocks to test timeout and cache clean-up. In this trade: dependency plumbing vs. waiting a bit longer in tests, I don't think the price is right. Timeout is 3 seconds and clean-up depends on TTL, so no test would wait longer than 3 seconds if you used the current MessageLoopProxy and base::Time::Now(). https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:372: scoped_ptr<const RecordParsed> record_clone = records.front()->Clone(); Why do you need to Clone? https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:373: task_runner_->PostTask( Why not call CacheRecordFound directly? https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:410: triggered_ = true; Instead of adding |triggered_|, I suggest: if (callback_.is_null()) return; https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:30: class MDnsConnection { Since this is internal to mdns_client_impl, I don't think you need this interface. Instead, I'd suggest making this class internal to MDnsClientImpl so that it can call its private methods directly.
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), DatagramServerSocket doesn't support multicasting (JoinGroup and AllowAddressReuse). Should I add support for it? On 2013/06/02 19:01:23, szym wrote: > On 2013/05/29 21:25:16, Noam Samuel wrote: > > On 2013/05/24 21:59:18, Noam Samuel wrote: > > > Hm. I tend to agree that, in retrospect, using mock sockets rather than > > loopback > > > network traffic may be simpler. These sockets are actually used to create > mock > > > network traffic for the MDnsClient. The sockets inside MDnsClient are used > as > > > servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I could use > > it > > > in the MDnsClient and then create a mock version of UDPServerSocket. > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > To minimize flakiness, we'd test this with MockUDPClientSocket. Do you > > really > > > > need to test on UDPSocket? > > > > > > > Done. > > I still see UDPSocket rather than DatagramServerSocket. https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:30: class MDnsConnection { On 2013/06/02 19:01:23, szym wrote: > Since this is internal to mdns_client_impl, I don't think you need this > interface. Instead, I'd suggest making this class internal to MDnsClientImpl so > that it can call its private methods directly. This class is mocked in the tests to allow separating the testing of the socket read loop and networking aspects from the testing of other parts of the mdns logic.
https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), On 2013/06/03 17:57:55, Noam Samuel wrote: > DatagramServerSocket doesn't support multicasting (JoinGroup and > AllowAddressReuse). Should I add support for it? > > On 2013/06/02 19:01:23, szym wrote: > > On 2013/05/29 21:25:16, Noam Samuel wrote: > > > On 2013/05/24 21:59:18, Noam Samuel wrote: > > > > Hm. I tend to agree that, in retrospect, using mock sockets rather than > > > loopback > > > > network traffic may be simpler. These sockets are actually used to create > > mock > > > > network traffic for the MDnsClient. The sockets inside MDnsClient are used > > as > > > > servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I could > use > > > it > > > > in the MDnsClient and then create a mock version of UDPServerSocket. > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > To minimize flakiness, we'd test this with MockUDPClientSocket. Do you > > > really > > > > > need to test on UDPSocket? > > > > > > > > > > Done. > > > > I still see UDPSocket rather than DatagramServerSocket. > I think so. https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:30: class MDnsConnection { On 2013/06/03 17:57:55, Noam Samuel wrote: > On 2013/06/02 19:01:23, szym wrote: > > Since this is internal to mdns_client_impl, I don't think you need this > > interface. Instead, I'd suggest making this class internal to MDnsClientImpl > so > > that it can call its private methods directly. > > This class is mocked in the tests to allow separating the testing of the socket > read loop and networking aspects from the testing of other parts of the mdns > logic. Whelp! I didn't notice it. This CL is a bit large.
Additional change: After running into some issues with synchronous callbacks being called on initialization, moved actual initialization logic to Start() methods on both the listener and the transaction. https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... File net/dns/mdns_listener_unittest.cc (right): https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), On 2013/06/03 18:38:30, szym wrote: > On 2013/06/03 17:57:55, Noam Samuel wrote: > > DatagramServerSocket doesn't support multicasting (JoinGroup and > > AllowAddressReuse). Should I add support for it? > > > > On 2013/06/02 19:01:23, szym wrote: > > > On 2013/05/29 21:25:16, Noam Samuel wrote: > > > > On 2013/05/24 21:59:18, Noam Samuel wrote: > > > > > Hm. I tend to agree that, in retrospect, using mock sockets rather than > > > > loopback > > > > > network traffic may be simpler. These sockets are actually used to > create > > > mock > > > > > network traffic for the MDnsClient. The sockets inside MDnsClient are > used > > > as > > > > > servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I could > > use > > > > it > > > > > in the MDnsClient and then create a mock version of UDPServerSocket. > > > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > > To minimize flakiness, we'd test this with MockUDPClientSocket. Do you > > > > really > > > > > > need to test on UDPSocket? > > > > > > > > > > > > > Done. > > > > > > I still see UDPSocket rather than DatagramServerSocket. > > > > I think so. Added support in interface: https://codereview.chromium.org/15995023/ https://codereview.chromium.org/15733008/diff/17001/net/dns/mdns_listener_imp... File net/dns/mdns_listener_impl.cc (right): https://codereview.chromium.org/15733008/diff/17001/net/dns/mdns_listener_imp... net/dns/mdns_listener_impl.cc:579: delegate_->HandlePacket(response, rval); On 2013/06/02 19:01:23, szym wrote: > This needs to be adjusted to follow the common design pattern in net. Please > take a look at other DoLoop methods in src/net. > > In your case you have two sockets that you want to process "in parallel", so I > suggest creating two instances of a class implementing DoLoop, each wrapping one > socket and response buffer. > > Because the processing is very simple (recv and handle), you don't really need > States. It could really be as simple as: > > Receiver::DoLoop(int rv) { > do { > if (rv > 0) > delegate_->HandlePacket(rv, buffer_); > rv = socket_->Recv(buffer, Bind(Receiver::OnDatagramReceived, > Unretained(this))); > } while (rv > 0); > if (rv != ERR_IO_PENDING) > delegate_->HandleError(rv); > } > > Receiver::OnDatagramReceived(int rv) { > DoLoop(rv); > } > > Connection::Start() { > ipv4_receiver_->DoLoop(0); > ipv6_receiver_->DoLoop(0); > } Done. https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:30: : client_(client), task_runner_(task_runner), clock_(clock), On 2013/06/02 19:01:23, szym wrote: > The only reason I see for this dependency on TaskRunner and Clock is that you > want to be able to inject mocks to test timeout and cache clean-up. > > In this trade: dependency plumbing vs. waiting a bit longer in tests, I don't > think the price is right. Timeout is 3 seconds and clean-up depends on TTL, so > no test would wait longer than 3 seconds if you used the current > MessageLoopProxy and base::Time::Now(). > Done. https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:372: scoped_ptr<const RecordParsed> record_clone = records.front()->Clone(); On 2013/06/02 19:01:23, szym wrote: > Why do you need to Clone? Removed. https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:373: task_runner_->PostTask( On 2013/06/02 19:01:23, szym wrote: > Why not call CacheRecordFound directly? Synchronized. https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:410: triggered_ = true; On 2013/06/02 19:01:23, szym wrote: > Instead of adding |triggered_|, I suggest: > if (callback_.is_null()) return; Done.
Hey, In order to make the API surface easier to use, I simplified it a bit by removing the concept of "active" listeners and of alert existing records in listeners. Now listeners are simple change notifiers, and most of the logic for actually querying for all services has been moved to transactions. Now transaction creation takes an extra "flags" parameter, which lets you specify whether you want to query the network, the cache, or both, and whether the transaction should return one result (call the callback once) or multiple (call the callback multiple times). --Noam On 2013/06/04 00:08:02, Noam Samuel wrote: > Additional change: After running into some issues with synchronous callbacks > being called on initialization, moved actual initialization logic to Start() > methods on both the listener and the transaction. > > https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... > File net/dns/mdns_listener_unittest.cc (right): > > https://codereview.chromium.org/15733008/diff/1/net/dns/mdns_listener_unittes... > net/dns/mdns_listener_unittest.cc:361: net::NetLog::Source())), > On 2013/06/03 18:38:30, szym wrote: > > On 2013/06/03 17:57:55, Noam Samuel wrote: > > > DatagramServerSocket doesn't support multicasting (JoinGroup and > > > AllowAddressReuse). Should I add support for it? > > > > > > On 2013/06/02 19:01:23, szym wrote: > > > > On 2013/05/29 21:25:16, Noam Samuel wrote: > > > > > On 2013/05/24 21:59:18, Noam Samuel wrote: > > > > > > Hm. I tend to agree that, in retrospect, using mock sockets rather > than > > > > > loopback > > > > > > network traffic may be simpler. These sockets are actually used to > > create > > > > mock > > > > > > network traffic for the MDnsClient. The sockets inside MDnsClient are > > used > > > > as > > > > > > servers. If I added JoinGroup and LeaveGroup to UDPServerSocket, I > could > > > use > > > > > it > > > > > > in the MDnsClient and then create a mock version of UDPServerSocket. > > > > > > > > > > > > On 2013/05/24 15:32:22, szym wrote: > > > > > > > To minimize flakiness, we'd test this with MockUDPClientSocket. Do > you > > > > > really > > > > > > > need to test on UDPSocket? > > > > > > > > > > > > > > > > Done. > > > > > > > > I still see UDPSocket rather than DatagramServerSocket. > > > > > > > I think so. > > Added support in interface: https://codereview.chromium.org/15995023/ > > https://codereview.chromium.org/15733008/diff/17001/net/dns/mdns_listener_imp... > File net/dns/mdns_listener_impl.cc (right): > > https://codereview.chromium.org/15733008/diff/17001/net/dns/mdns_listener_imp... > net/dns/mdns_listener_impl.cc:579: delegate_->HandlePacket(response, rval); > On 2013/06/02 19:01:23, szym wrote: > > This needs to be adjusted to follow the common design pattern in net. Please > > take a look at other DoLoop methods in src/net. > > > > In your case you have two sockets that you want to process "in parallel", so I > > suggest creating two instances of a class implementing DoLoop, each wrapping > one > > socket and response buffer. > > > > Because the processing is very simple (recv and handle), you don't really need > > States. It could really be as simple as: > > > > Receiver::DoLoop(int rv) { > > do { > > if (rv > 0) > > delegate_->HandlePacket(rv, buffer_); > > rv = socket_->Recv(buffer, Bind(Receiver::OnDatagramReceived, > > Unretained(this))); > > } while (rv > 0); > > if (rv != ERR_IO_PENDING) > > delegate_->HandleError(rv); > > } > > > > Receiver::OnDatagramReceived(int rv) { > > DoLoop(rv); > > } > > > > Connection::Start() { > > ipv4_receiver_->DoLoop(0); > > ipv6_receiver_->DoLoop(0); > > } > > Done. > > https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.cc > File net/dns/mdns_client_impl.cc (right): > > https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... > net/dns/mdns_client_impl.cc:30: : client_(client), task_runner_(task_runner), > clock_(clock), > On 2013/06/02 19:01:23, szym wrote: > > The only reason I see for this dependency on TaskRunner and Clock is that you > > want to be able to inject mocks to test timeout and cache clean-up. > > > > In this trade: dependency plumbing vs. waiting a bit longer in tests, I don't > > think the price is right. Timeout is 3 seconds and clean-up depends on TTL, so > > no test would wait longer than 3 seconds if you used the current > > MessageLoopProxy and base::Time::Now(). > > > > Done. > > https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... > net/dns/mdns_client_impl.cc:372: scoped_ptr<const RecordParsed> record_clone = > records.front()->Clone(); > On 2013/06/02 19:01:23, szym wrote: > > Why do you need to Clone? > > Removed. > > https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... > net/dns/mdns_client_impl.cc:373: task_runner_->PostTask( > On 2013/06/02 19:01:23, szym wrote: > > Why not call CacheRecordFound directly? > > Synchronized. > > https://codereview.chromium.org/15733008/diff/20002/net/dns/mdns_client_impl.... > net/dns/mdns_client_impl.cc:410: triggered_ = true; > On 2013/06/02 19:01:23, szym wrote: > > Instead of adding |triggered_|, I suggest: > > if (callback_.is_null()) return; > > Done.
A lot of nits, but the two major points are: 1) Please move repeated code from MDnsConnectionImpl to RecvLoop (and maybe call it SocketHandler). 2) Please add tests using mocked DatagramServerSocket. The rationale for this request is that you need to ensure that RecvLoop can handle both synchronous and asynchronous results (including errors) from DatagramServerSocket calls. It is relatively straightforward to create an MockMDnsConnection-like fixture by giving MDnsConnection mock sockets. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h File net/dns/mdns_client.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:20: enum MDnsUpdateType { nit: Needs a comment on what it is used for. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:26: enum MDnsTransactionResult { nit: Needs a comment on what it is used for. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:27: // Called whenever a record is found. Nit: "Passed" would be better than "called". https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:34: // called when the transaction has finished without finding any results. nit: Would make sense to mention that this is the case of time-out? https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:42: enum MDnsTransactionFlags { nit: Needs a comment on what it is used for. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:46: kMDnsTransactionSingleResult = 0x1, nit: Use 1 << 0 instead of 0x1. Same below. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:52: kMDnsTransactionFlagMask = 0x7, Never used. Remove. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:55: // A class representing a one-time record lookup. A transaction takes one nit: "A class" is redundant. "Represents a one-time record lookup." is better, but just "A one-time record lookup." would suffice as well. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:69: // Start the transaction. nit: Return what? https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:112: // This class listens for Multicast DNS on the local network. You can access nit: No need for "This class". https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:125: // created. Update comment to reflect change in interface. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:131: // Create a transaction to Query MDNS for a query to the cache, to the Confusing grammar. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:463: connection_->OnError(this, socket_, rv); Ok, but be careful that this can be called inside Init(). Normally, you'd do return rv and in both Init and OnDatagramReceived. if (DoLoop(rv) != OK) OnError(rv); Right now your OnError does nothing. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:481: socket_ipv6_->Close(); No need for either. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:545: int status = socket->Listen(bind_endpoint); nit: suggest rv or result instead of status. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:563: &multicast_group_number); You are parsing the constant on every sent packet. Could you instead initialize both in the constructor of MDnsConnectionImpl and just pass IPEndPoint around? You could also use it in BindSocket (IPEndPoint::address()). https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:28: // This class represents a connection to the network for multicast DNS clients. nit: No need for "This class represents". https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:29: // It reads data into DNSResponse objects and alerts the delegate that a packet nit: DnsResponse https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:37: virtual ~Delegate() {} In MDnsConnectionImpl you moved error handling to the delegate, but with the interface above there is no way to test that path without mocking sockets. I still think you'd better test MDnsClientImpl using mocked sockets only and avoid adding another layer of indirection just for testing. Even if you keep MDnsConnection and MDnsConnectionImpl separate, you will still need to add tests for MDnsConnectionImpl using mocked sockets. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:41: virtual bool Init() = 0; nit: Returns? https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:44: virtual bool Send(IOBuffer* buffer, unsigned size) = 0; nit: Returns? https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:174: // Start the listener. Returns true on success. You don't really need to copy comments on implementation of an interface. Instead write // MDnsListener implementation: above the first method. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:186: void AlertDelegate(MDnsUpdateType update_type, nit: Needs a comment. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:199: public base::SupportsWeakPtr<MDnsTransactionImpl>, nit: Don't put SupportsWeakPtr in between two interfaces. I suggest making it first. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:209: // Start the transaction. Returns true on success. // MDnsTransaction implementation: https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:219: virtual const std::string& GetName() const OVERRIDE; Keep the methods from different interfaces separate. MDnsTransaction before MDnsListener::Delegate https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:222: bool is_valid() { return !callback_.is_null(); } I'd suggest is_active() or is_pending(), since nothing is being validated. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:263: class RecvLoop { This could be better structured, by moving socket ownership, BindSocket, and Send to RecvLoop. It should also have the IPEndPoint stored in a field. MDnsConnectionImpl::Send would just forward the arguments to RecvLoop::Send. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_unitt... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:871: TEST_F(MDnsConnectionTest, DISABLED_Recieve4) { Do NOT add DISABLED tests. Leave them out of this CL. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_query.h File net/dns/mdns_query.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_query.h#newc... net/dns/mdns_query.h:22: class MDnsQuery { Could we make this CL a little bit smaller, by using DnsQuery now and moving this to a subsequent CL?
https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h File net/dns/mdns_client.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:20: enum MDnsUpdateType { On 2013/06/07 16:40:02, szym wrote: > nit: Needs a comment on what it is used for. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:26: enum MDnsTransactionResult { On 2013/06/07 16:40:02, szym wrote: > nit: Needs a comment on what it is used for. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:27: // Called whenever a record is found. On 2013/06/07 16:40:02, szym wrote: > Nit: "Passed" would be better than "called". Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:34: // called when the transaction has finished without finding any results. On 2013/06/07 16:40:02, szym wrote: > nit: Would make sense to mention that this is the case of time-out? Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:42: enum MDnsTransactionFlags { On 2013/06/07 16:40:02, szym wrote: > nit: Needs a comment on what it is used for. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:46: kMDnsTransactionSingleResult = 0x1, On 2013/06/07 16:40:02, szym wrote: > nit: Use 1 << 0 instead of 0x1. Same below. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:52: kMDnsTransactionFlagMask = 0x7, On 2013/06/07 16:40:02, szym wrote: > Never used. Remove. This is used in a DCHECK to warn users who pass nonexistent flags to CreateTransaction. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:55: // A class representing a one-time record lookup. A transaction takes one On 2013/06/07 16:40:02, szym wrote: > nit: "A class" is redundant. "Represents a one-time record lookup." is better, > but just "A one-time record lookup." would suffice as well. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:69: // Start the transaction. On 2013/06/07 16:40:02, szym wrote: > nit: Return what? Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:112: // This class listens for Multicast DNS on the local network. You can access On 2013/06/07 16:40:02, szym wrote: > nit: No need for "This class". Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:125: // created. On 2013/06/07 16:40:02, szym wrote: > Update comment to reflect change in interface. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client.h#new... net/dns/mdns_client.h:131: // Create a transaction to Query MDNS for a query to the cache, to the On 2013/06/07 16:40:02, szym wrote: > Confusing grammar. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:463: connection_->OnError(this, socket_, rv); OnError now tunnels up to client, still does nothing. Will add retry/flush logic in subsequent CL. On 2013/06/07 16:40:02, szym wrote: > Ok, but be careful that this can be called inside Init(). > > Normally, you'd do return rv and in both Init and OnDatagramReceived. > if (DoLoop(rv) != OK) > OnError(rv); > > Right now your OnError does nothing. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:481: socket_ipv6_->Close(); On 2013/06/07 16:40:02, szym wrote: > No need for either. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:545: int status = socket->Listen(bind_endpoint); On 2013/06/07 16:40:02, szym wrote: > nit: suggest rv or result instead of status. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:563: &multicast_group_number); On 2013/06/07 16:40:02, szym wrote: > You are parsing the constant on every sent packet. Could you instead initialize > both in the constructor of MDnsConnectionImpl and just pass IPEndPoint around? > > You could also use it in BindSocket (IPEndPoint::address()). Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:28: // This class represents a connection to the network for multicast DNS clients. On 2013/06/07 16:40:02, szym wrote: > nit: No need for "This class represents". Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:29: // It reads data into DNSResponse objects and alerts the delegate that a packet On 2013/06/07 16:40:02, szym wrote: > nit: DnsResponse Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:37: virtual ~Delegate() {} Added tests for MDnsConnectionImpl using mocked objects. On 2013/06/07 16:40:02, szym wrote: > In MDnsConnectionImpl you moved error handling to the delegate, but with the > interface above there is no way to test that path without mocking sockets. > > I still think you'd better test MDnsClientImpl using mocked sockets only and > avoid adding another layer of indirection just for testing. > > Even if you keep MDnsConnection and MDnsConnectionImpl separate, you will still > need to add tests for MDnsConnectionImpl using mocked sockets. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:41: virtual bool Init() = 0; On 2013/06/07 16:40:02, szym wrote: > nit: Returns? Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:44: virtual bool Send(IOBuffer* buffer, unsigned size) = 0; On 2013/06/07 16:40:02, szym wrote: > nit: Returns? Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:174: // Start the listener. Returns true on success. On 2013/06/07 16:40:02, szym wrote: > You don't really need to copy comments on implementation of an interface. > Instead write > // MDnsListener implementation: > above the first method. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:186: void AlertDelegate(MDnsUpdateType update_type, On 2013/06/07 16:40:02, szym wrote: > nit: Needs a comment. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:199: public base::SupportsWeakPtr<MDnsTransactionImpl>, On 2013/06/07 16:40:02, szym wrote: > nit: Don't put SupportsWeakPtr in between two interfaces. I suggest making it > first. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:209: // Start the transaction. Returns true on success. On 2013/06/07 16:40:02, szym wrote: > // MDnsTransaction implementation: Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:219: virtual const std::string& GetName() const OVERRIDE; On 2013/06/07 16:40:02, szym wrote: > Keep the methods from different interfaces separate. MDnsTransaction before > MDnsListener::Delegate Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:222: bool is_valid() { return !callback_.is_null(); } On 2013/06/07 16:40:02, szym wrote: > I'd suggest is_active() or is_pending(), since nothing is being validated. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:263: class RecvLoop { On 2013/06/07 16:40:02, szym wrote: > This could be better structured, by moving socket ownership, BindSocket, and > Send to RecvLoop. It should also have the IPEndPoint stored in a field. > MDnsConnectionImpl::Send would just forward the arguments to RecvLoop::Send. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_unitt... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:871: TEST_F(MDnsConnectionTest, DISABLED_Recieve4) { On 2013/06/07 16:40:02, szym wrote: > Do NOT add DISABLED tests. Leave them out of this CL. Done. https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_query.h File net/dns/mdns_query.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_query.h#newc... net/dns/mdns_query.h:22: class MDnsQuery { On 2013/06/07 16:40:02, szym wrote: > Could we make this CL a little bit smaller, by using DnsQuery now and moving > this to a subsequent CL? Done. Note that this adds the RD flag to queries, which isn't compliant with the mDNS spec.
https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_query.h File net/dns/mdns_query.h (right): https://codereview.chromium.org/15733008/diff/64001/net/dns/mdns_query.h#newc... net/dns/mdns_query.h:22: class MDnsQuery { On 2013/06/07 23:54:43, Noam Samuel wrote: > On 2013/06/07 16:40:02, szym wrote: > > Could we make this CL a little bit smaller, by using DnsQuery now and moving > > this to a subsequent CL? > > Done. Note that this adds the RD flag to queries, which isn't compliant with the > mDNS spec. I missed the RD bit. We certainly don't want clearly incorrect code. I'm ok with MDnsQuery, but the comment needs to legitimize its presence. Alternatively, you could add DnsQuery::set_flags(uint16) (pass them in host order). https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client.h File net/dns/mdns_client.h (right): https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client.h#new... net/dns/mdns_client.h:141: int flags, // See MDnsTransactionFlags Move this to the comment above. https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:530: : socket_handler_ipv4_(this, GetIPEndPoint(kMDnsMulticastGroupIPv4, If you always use this with the same port, why not make it GetMDnsIPEndPoint(const string& multicast_group)? https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:220: void Reset(); Make it private. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:60: // and is deleted whenever the number of references for listening reachers nit: "reaches" Suggest: "whenever the number of listeners reaches zero." https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:62: // tasks scheduled on it are not delivered after it is destroyed. The last sentence does not seem to be adding much. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:124: explicit MDnsClientImpl(MDnsConnectionFactory* connection_factory); I suggest always passing the factory into the constructor. MDnsClientImpl is not the public interface. Pass the real factory when you construct it in MDnsClient::GetInstance. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:157: MDnsConnectionFactory* connection_factory_; I suggest it should always own it. Whenever a situation like this arises, just keep a plain (unsafe) pointer in the test fixture. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:292: // Callback for handling a datagram being recieved on either ipv4 or ipv6. nit: "received" https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:293: // Responsible for ensuring we request another packet from the network. This sentence is obsolete. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:231: class MockMDnsConnection : public MDnsConnection { I think this could be equivalently built from MDnsConnectionImpl with mock sockets. It's possible you could accomplish that with existing MockDatagramServerSocket. Alternatively, a "SimpleMockSocket" would be: int RecvFrom(buffer, callback) { recv_buffer_ = buffer; recv_callback_ = callback; return ERR_IO_PENDING; } int SendTo(buffer, callback) { send_buffer_ = buffer; send_callback_ = callback; return ERR_IO_PENDING; } bool SimulateReceive(string data) { if(recv_buffer_ == NULL) return false; memcpy(recv_buffer_, data); recv_buffer_ = NULL; recv_callback_.Run(data.size()); return true; } bool ExpectSendData(string data) { if (send_buffer_ == NULL) return false; if (memcmp(send_buffer_, data)) return false; send_buffer_ = NULL; send_callback_.Run(data.size()); return true; } Then inject this into MDnsClientImpl using DatagramServerSocketFactory (instead of MDnsConnectionFactory). MDnsTest() { MDnsTest(): factory_(new MockSocketFactory), test_client_(new MDnsClientImpl(factory_)) {} MockSocketFactory* factory_; // owned by test_client_ scoped_ptr<MDnsClientImpl> test_client_; }; where MockSocketFactory : DatagramServerSocketFactory { scoped_ptr<DatagramServerSocket> CreateSocket() { socket = new MockDatagramServerSocket(); sockets_.push(socket); return new MockDatagramServerSocket(); } bool ExpectSendData(string data) { for (socket in sockets_) if (!socket->ExpectSendData(data)) return false; } vector<DatagramServerSocket*> sockets_; // sockets owned by the caller. } This approach would completely avoid the need for the pure virtual MDnsConnection interface. The price is only a little bit of awkwardness because you need to go through all the issued sockets by the factory. ====== Why it makes sense? DatagramServerSocket is already an interface which can be mocked out for testing. There is no need to add yet another interface unless it significantly simplifies the mocks. I don't think that's the case here. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:298: class RecordParsedCopyContainer { It seems you could avoid the clone by following the pattern of ExpectPacket, i.e., store the expectations before the callback is called. (Maybe call it ExpectedNptrRecord.) If you prefer this, you should copy only the interesting parts out of the record: |name| and |ptrdomain| and verify that it is a PTR record. (Maybe call it NptrRecordContainer.) https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:336: void SendPacket(const char* packet, unsigned size); This name is a bit misleading. You are simulating a packet arriving on the socket. Needs a better name and a comment. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:337: void ExpectPtrRecord( This name is misleading. Should be ExpectContainsPtrRecord, but bool ContainsPtrRecord would be better. If you fail within a method, you will need to rely on stack trace to diagnose the bug. If possible, it's generally better to return bool and wrap it in EXPECT_TRUE(...). https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:909: return JoinGroupInternal(IPAddressToString(group_address)); Shouldn't this be LeaveGroupInternal? https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:957: TEST_F(MDnsConnectionTest, RecieveSynchronous) { nit: Receive https://codereview.chromium.org/15733008/diff/93001/net/dns/record_parsed.h File net/dns/record_parsed.h (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/record_parsed.h#n... net/dns/record_parsed.h:28: scoped_ptr<const RecordParsed> Clone() const; How did this make its way back into this CL? It seems to be used in tests only. Does the test really need to Clone?
https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:231: class MockMDnsConnection : public MDnsConnection { Should I call the factory interface DatagramServerSocketFactory, or should the name be more specific? Right now I'm using MDnsDatagramServerSocketFactory as a placeholder name, but it is a bit unwieldy. On 2013/06/10 21:58:29, szym wrote: > I think this could be equivalently built from MDnsConnectionImpl with mock > sockets. It's possible you could accomplish that with existing > MockDatagramServerSocket. Alternatively, a "SimpleMockSocket" would be: > > int RecvFrom(buffer, callback) { > recv_buffer_ = buffer; > recv_callback_ = callback; > return ERR_IO_PENDING; > } > > int SendTo(buffer, callback) { > send_buffer_ = buffer; > send_callback_ = callback; > return ERR_IO_PENDING; > } > > bool SimulateReceive(string data) { > if(recv_buffer_ == NULL) return false; > memcpy(recv_buffer_, data); > recv_buffer_ = NULL; > recv_callback_.Run(data.size()); > return true; > } > > bool ExpectSendData(string data) { > if (send_buffer_ == NULL) return false; > if (memcmp(send_buffer_, data)) return false; > send_buffer_ = NULL; > send_callback_.Run(data.size()); > return true; > } > > Then inject this into MDnsClientImpl using DatagramServerSocketFactory (instead > of MDnsConnectionFactory). > > MDnsTest() { > MDnsTest(): factory_(new MockSocketFactory), > test_client_(new MDnsClientImpl(factory_)) {} > > MockSocketFactory* factory_; // owned by test_client_ > scoped_ptr<MDnsClientImpl> test_client_; > }; > > where > > MockSocketFactory : DatagramServerSocketFactory { > scoped_ptr<DatagramServerSocket> CreateSocket() { > socket = new MockDatagramServerSocket(); > sockets_.push(socket); > return new MockDatagramServerSocket(); > } > bool ExpectSendData(string data) { > for (socket in sockets_) > if (!socket->ExpectSendData(data)) > return false; > } > > vector<DatagramServerSocket*> sockets_; // sockets owned by the caller. > } > > This approach would completely avoid the need for the pure virtual > MDnsConnection interface. The price is only a little bit of awkwardness because > you need to go through all the issued sockets by the factory. > > ====== > Why it makes sense? DatagramServerSocket is already an interface which can be > mocked out for testing. There is no need to add yet another interface unless it > significantly simplifies the mocks. I don't think that's the case here.
https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client.h File net/dns/mdns_client.h (right): https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client.h#new... net/dns/mdns_client.h:141: int flags, // See MDnsTransactionFlags On 2013/06/10 21:58:28, szym wrote: > Move this to the comment above. Done. https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.cc:530: : socket_handler_ipv4_(this, GetIPEndPoint(kMDnsMulticastGroupIPv4, On 2013/06/10 21:58:28, szym wrote: > If you always use this with the same port, why not make it > GetMDnsIPEndPoint(const string& multicast_group)? Done. https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/82002/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:220: void Reset(); On 2013/06/10 21:58:28, szym wrote: > Make it private. Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:60: // and is deleted whenever the number of references for listening reachers On 2013/06/10 21:58:29, szym wrote: > nit: "reaches" > > Suggest: "whenever the number of listeners reaches zero." Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:62: // tasks scheduled on it are not delivered after it is destroyed. On 2013/06/10 21:58:29, szym wrote: > The last sentence does not seem to be adding much. Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:124: explicit MDnsClientImpl(MDnsConnectionFactory* connection_factory); On 2013/06/10 21:58:29, szym wrote: > I suggest always passing the factory into the constructor. MDnsClientImpl is not > the public interface. Pass the real factory when you construct it in > MDnsClient::GetInstance. Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:157: MDnsConnectionFactory* connection_factory_; On 2013/06/10 21:58:29, szym wrote: > I suggest it should always own it. Whenever a situation like this arises, just > keep a plain (unsafe) pointer in the test fixture. Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:292: // Callback for handling a datagram being recieved on either ipv4 or ipv6. On 2013/06/10 21:58:29, szym wrote: > nit: "received" Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_impl.... net/dns/mdns_client_impl.h:293: // Responsible for ensuring we request another packet from the network. On 2013/06/10 21:58:29, szym wrote: > This sentence is obsolete. Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:231: class MockMDnsConnection : public MDnsConnection { Done with name MDnsDatagramServerSocketFactory. On 2013/06/11 18:31:14, Noam Samuel wrote: > Should I call the factory interface DatagramServerSocketFactory, or should the > name be more specific? Right now I'm using MDnsDatagramServerSocketFactory as a > placeholder name, but it is a bit unwieldy. > > On 2013/06/10 21:58:29, szym wrote: > > I think this could be equivalently built from MDnsConnectionImpl with mock > > sockets. It's possible you could accomplish that with existing > > MockDatagramServerSocket. Alternatively, a "SimpleMockSocket" would be: > > > > int RecvFrom(buffer, callback) { > > recv_buffer_ = buffer; > > recv_callback_ = callback; > > return ERR_IO_PENDING; > > } > > > > int SendTo(buffer, callback) { > > send_buffer_ = buffer; > > send_callback_ = callback; > > return ERR_IO_PENDING; > > } > > > > bool SimulateReceive(string data) { > > if(recv_buffer_ == NULL) return false; > > memcpy(recv_buffer_, data); > > recv_buffer_ = NULL; > > recv_callback_.Run(data.size()); > > return true; > > } > > > > bool ExpectSendData(string data) { > > if (send_buffer_ == NULL) return false; > > if (memcmp(send_buffer_, data)) return false; > > send_buffer_ = NULL; > > send_callback_.Run(data.size()); > > return true; > > } > > > > Then inject this into MDnsClientImpl using DatagramServerSocketFactory > (instead > > of MDnsConnectionFactory). > > > > MDnsTest() { > > MDnsTest(): factory_(new MockSocketFactory), > > test_client_(new MDnsClientImpl(factory_)) {} > > > > MockSocketFactory* factory_; // owned by test_client_ > > scoped_ptr<MDnsClientImpl> test_client_; > > }; > > > > where > > > > MockSocketFactory : DatagramServerSocketFactory { > > scoped_ptr<DatagramServerSocket> CreateSocket() { > > socket = new MockDatagramServerSocket(); > > sockets_.push(socket); > > return new MockDatagramServerSocket(); > > } > > bool ExpectSendData(string data) { > > for (socket in sockets_) > > if (!socket->ExpectSendData(data)) > > return false; > > } > > > > vector<DatagramServerSocket*> sockets_; // sockets owned by the caller. > > } > > > > This approach would completely avoid the need for the pure virtual > > MDnsConnection interface. The price is only a little bit of awkwardness > because > > you need to go through all the issued sockets by the factory. > > > > ====== > > Why it makes sense? DatagramServerSocket is already an interface which can be > > mocked out for testing. There is no need to add yet another interface unless > it > > significantly simplifies the mocks. I don't think that's the case here. > https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:298: class RecordParsedCopyContainer { On 2013/06/10 21:58:29, szym wrote: > It seems you could avoid the clone by following the pattern of ExpectPacket, > i.e., store the expectations before the callback is called. (Maybe call it > ExpectedNptrRecord.) > > If you prefer this, you should copy only the interesting parts out of the > record: |name| and |ptrdomain| and verify that it is a PTR record. (Maybe call > it NptrRecordContainer.) Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:336: void SendPacket(const char* packet, unsigned size); On 2013/06/10 21:58:29, szym wrote: > This name is a bit misleading. You are simulating a packet arriving on the > socket. Needs a better name and a comment. Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:337: void ExpectPtrRecord( On 2013/06/10 21:58:29, szym wrote: > This name is misleading. Should be ExpectContainsPtrRecord, but bool > ContainsPtrRecord would be better. If you fail within a method, you will need to > rely on stack trace to diagnose the bug. If possible, it's generally better to > return bool and wrap it in EXPECT_TRUE(...). Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:909: return JoinGroupInternal(IPAddressToString(group_address)); On 2013/06/10 21:58:29, szym wrote: > Shouldn't this be LeaveGroupInternal? Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/mdns_client_unitt... net/dns/mdns_client_unittest.cc:957: TEST_F(MDnsConnectionTest, RecieveSynchronous) { On 2013/06/10 21:58:29, szym wrote: > nit: Receive Done. https://codereview.chromium.org/15733008/diff/93001/net/dns/record_parsed.h File net/dns/record_parsed.h (right): https://codereview.chromium.org/15733008/diff/93001/net/dns/record_parsed.h#n... net/dns/record_parsed.h:28: scoped_ptr<const RecordParsed> Clone() const; On 2013/06/10 21:58:29, szym wrote: > How did this make its way back into this CL? It seems to be used in tests only. > Does the test really need to Clone? Removed.
I appreciate your patience with the slow review. Still a bunch of nits, but LGTM overall. Don't forget to add TEST= line to CL. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.cc File net/dns/mdns_client.cc (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.cc#n... net/dns/mdns_client.cc:6: #include "net/dns/mdns_client_impl.h" nit: add blank line above https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h File net/dns/mdns_client.h (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:22: enum MDnsUpdateType { Perhaps put this nested in MDnsListener::UpdateType. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:23: kMDnsRecordAdded, http://www.chromium.org/developers/coding-style prefers macro-style naming for enums. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:30: enum MDnsTransactionResult { You could move this into MDnsTransaction so that the enum constant names are just RESULT_RECORD, RESULT_DONE, etc. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:77: // Start the transaction. Return true on success. Add a comment that cache-only transactions execute the callback immediately. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:87: // A listener listens for updates regarding a specific record or set of records. Add a short comment explaining the design responsibility of this class, e.g. "Created by MDnsClient and used to keep track of active listeners." You should also explain either here or in MDnsClient that the internal cache is destroyed when nobody is listening. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:20: static const char kMDnsMulticastGroupIPv4[] = "224.0.0.251"; nit: use anonymous namespace instead of static https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:31: cleanup_callback_.Cancel(); Not necessary. Destroying CancelableCallback cancels it. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:62: } nit: Here and elsewhere in this CL. No need for {} when "if + body" is just two lines. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:107: case MDnsCache::NoChange: I suggest adding case default: here. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:176: // This line has the effect of cancelling the previously scheduled cleanup. No need for "This line has the effect". Just "This cancels the previously scheduled cleanup." https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:180: // cleanup == base::Time means no cleanup necessary. I suggest "If |cleanup| is empty, then no cleanup necessary." https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:281: client_->core()->AddListener(this); Do you need DCHECK(client_->core()) ? https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:288: client_->core()->RemoveListener(this); ditto https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:342: if (is_active() && flags_ & kMDnsTransactionQueryNetwork) { nit: wrap the & part in parens to avoid confusion. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:434: MDnsConnection::SocketHandler::SocketHandler( Move MDnsConnection to the top of the file to match the order in the header. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:499: address_any.resize(multicast_addr_.address().size(), 0); You can do it in the initializer. IPAddressNumber address_any(size); (default value is 0) https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:64: void SendDone(int sent); nit: |rv| would be better instead of |sent|. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:77: IPEndPoint* recv_addr, I suggest you pass IPEndPoint by const&. Why do you need to pass the socket? https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:96: // The core object exists while the MDnsClient is listening for MDnsPackets, nit: No need for "MDnsPackets". It's also not clear what it is exactly. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:133: // Schedule a cleanup to a specific time, cancelling other cleanups. nit: add "cache" https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:155: explicit MDnsClientImpl(MDnsDatagramServerSocketFactory* socket_factory_); should be scoped_ptr https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:170: // Functions for testing only. nit: unnecessary comment. Better to explain what "listening" means, i.e., "Returns true when .." https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:179: void Shutdown(); Add a comment that this is deferred shutdown after the last listener is removed and the shutdown will be aborted if new listeners are added before it is executed. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:275: class MDnsDatagramServerSocketFactory { Why not declare it first so that there's no need to forward declare? If you want to make the name shorter, I'd be ok with DatagramServerSocketFactory since there's nothing MDNS specific about it. I'd also be ok with a nested MDnsConnection::SocketFactory. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:282: class MDnsDatagramServerSocketFactoryImpl I'd suggest hiding this from the header and only exposing it via static scoped_ptr<...Factory> CreateDefault(); in the interface above. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:234: int Listen(const IPEndPoint& address) { // DatagramServerSocket implementation https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:240: void SetResponsePacket(std::string response_packet) { These are not part of DatagramServerSocket so move them from here. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:244: int RespondImmediately(IOBuffer* buffer, int size, IPEndPoint* address, The name is confusing. How about HandleRecv? HandleRecvNow? HandleRecvLater? https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:246: int to_copy = std::min(response_packet_.size(), (size_t)size); size_returned would be more clear than to_copy static_cast<size_t> https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:330: int SendToInternal(const std::string& packet, const std::string& address, Does it need to be public? https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:336: // The latest recieve callback is always saved, since the MDnsConnection nit: receive https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:414: void SimulatePacketRecieve(const char* packet, unsigned size); nit: Receive https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:499: listener_privet->Start(); Should you ASSERT_TRUE all Start() calls (both listeners and transactions)? https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:525: RunUntilIdle(); I don't think you need to run the loop here. It should already be idle. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:553: TEST_F(MDnsTest, PassiveListenersCleanup) { I suggest PassiveListenersCacheCleanup. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:579: EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordRemoved, _)) Add a comment "Expect record is removed when its TTL expires." https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:629: TEST_F(MDnsTest, TransactionNoCache) { I suggest TransactionWithEmptyCache https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:925: MockDatagramServerSocket* socket = sockets_.front(); It'd be nice if you could ensure test failure without crash in case MDnsConnection only created one socket. (EXPECT_EQ will not abort the test, so you will still crash.) But given how simple MDnsConnection is, I'm not too concerned about this ever becoming an issue. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:955: // Follow successful connection initialization nit: end with "." https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:980: connection_.Init(); I suggest you return the value or (return connection_.Init() == OK) and ASSERT it in the test.
https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.cc File net/dns/mdns_client.cc (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.cc#n... net/dns/mdns_client.cc:6: #include "net/dns/mdns_client_impl.h" On 2013/06/12 21:35:41, szym wrote: > nit: add blank line above Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h File net/dns/mdns_client.h (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:22: enum MDnsUpdateType { On 2013/06/12 21:35:41, szym wrote: > Perhaps put this nested in MDnsListener::UpdateType. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:23: kMDnsRecordAdded, On 2013/06/12 21:35:41, szym wrote: > http://www.chromium.org/developers/coding-style prefers macro-style naming for > enums. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:30: enum MDnsTransactionResult { On 2013/06/12 21:35:41, szym wrote: > You could move this into MDnsTransaction so that the enum constant names are > just RESULT_RECORD, RESULT_DONE, etc. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:77: // Start the transaction. Return true on success. On 2013/06/12 21:35:41, szym wrote: > Add a comment that cache-only transactions execute the callback immediately. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client.h#ne... net/dns/mdns_client.h:87: // A listener listens for updates regarding a specific record or set of records. On 2013/06/12 21:35:41, szym wrote: > Add a short comment explaining the design responsibility of this class, e.g. > "Created by MDnsClient and used to keep track of active listeners." > > You should also explain either here or in MDnsClient that the internal cache is > destroyed when nobody is listening. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:20: static const char kMDnsMulticastGroupIPv4[] = "224.0.0.251"; On 2013/06/12 21:35:41, szym wrote: > nit: use anonymous namespace instead of static Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:31: cleanup_callback_.Cancel(); On 2013/06/12 21:35:41, szym wrote: > Not necessary. Destroying CancelableCallback cancels it. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:62: } On 2013/06/12 21:35:41, szym wrote: > nit: Here and elsewhere in this CL. No need for {} when "if + body" is just two > lines. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:107: case MDnsCache::NoChange: On 2013/06/12 21:35:41, szym wrote: > I suggest adding case default: here. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:176: // This line has the effect of cancelling the previously scheduled cleanup. On 2013/06/12 21:35:41, szym wrote: > No need for "This line has the effect". Just "This cancels the previously > scheduled cleanup." Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:180: // cleanup == base::Time means no cleanup necessary. On 2013/06/12 21:35:41, szym wrote: > I suggest "If |cleanup| is empty, then no cleanup necessary." Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:281: client_->core()->AddListener(this); On 2013/06/12 21:35:41, szym wrote: > Do you need DCHECK(client_->core()) ? Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:288: client_->core()->RemoveListener(this); On 2013/06/12 21:35:41, szym wrote: > ditto Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:342: if (is_active() && flags_ & kMDnsTransactionQueryNetwork) { On 2013/06/12 21:35:41, szym wrote: > nit: wrap the & part in parens to avoid confusion. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:434: MDnsConnection::SocketHandler::SocketHandler( On 2013/06/12 21:35:41, szym wrote: > Move MDnsConnection to the top of the file to match the order in the header. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:499: address_any.resize(multicast_addr_.address().size(), 0); On 2013/06/12 21:35:41, szym wrote: > You can do it in the initializer. > IPAddressNumber address_any(size); > (default value is 0) > > Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl.h File net/dns/mdns_client_impl.h (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:64: void SendDone(int sent); On 2013/06/12 21:35:41, szym wrote: > nit: |rv| would be better instead of |sent|. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:77: IPEndPoint* recv_addr, On 2013/06/12 21:35:41, szym wrote: > I suggest you pass IPEndPoint by const&. Why do you need to pass the socket? Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:96: // The core object exists while the MDnsClient is listening for MDnsPackets, On 2013/06/12 21:35:41, szym wrote: > nit: No need for "MDnsPackets". It's also not clear what it is exactly. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:133: // Schedule a cleanup to a specific time, cancelling other cleanups. On 2013/06/12 21:35:41, szym wrote: > nit: add "cache" Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:155: explicit MDnsClientImpl(MDnsDatagramServerSocketFactory* socket_factory_); On 2013/06/12 21:35:41, szym wrote: > should be scoped_ptr Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:170: // Functions for testing only. On 2013/06/12 21:35:41, szym wrote: > nit: unnecessary comment. Better to explain what "listening" means, i.e., > "Returns true when .." Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:179: void Shutdown(); On 2013/06/12 21:35:41, szym wrote: > Add a comment that this is deferred shutdown after the last listener is removed > and the shutdown will be aborted if new listeners are added before it is > executed. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:275: class MDnsDatagramServerSocketFactory { On 2013/06/12 21:35:41, szym wrote: > Why not declare it first so that there's no need to forward declare? > > If you want to make the name shorter, I'd be ok with DatagramServerSocketFactory > since there's nothing MDNS specific about it. > > I'd also be ok with a nested MDnsConnection::SocketFactory. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_impl... net/dns/mdns_client_impl.h:282: class MDnsDatagramServerSocketFactoryImpl On 2013/06/12 21:35:41, szym wrote: > I'd suggest hiding this from the header and only exposing it via static > scoped_ptr<...Factory> CreateDefault(); > in the interface above. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:234: int Listen(const IPEndPoint& address) { On 2013/06/12 21:35:41, szym wrote: > // DatagramServerSocket implementation Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:240: void SetResponsePacket(std::string response_packet) { On 2013/06/12 21:35:41, szym wrote: > These are not part of DatagramServerSocket so move them from here. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:244: int RespondImmediately(IOBuffer* buffer, int size, IPEndPoint* address, On 2013/06/12 21:35:41, szym wrote: > The name is confusing. How about HandleRecv? HandleRecvNow? HandleRecvLater? Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:246: int to_copy = std::min(response_packet_.size(), (size_t)size); On 2013/06/12 21:35:41, szym wrote: > size_returned would be more clear than to_copy > > static_cast<size_t> Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:330: int SendToInternal(const std::string& packet, const std::string& address, On 2013/06/12 21:35:41, szym wrote: > Does it need to be public? Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:336: // The latest recieve callback is always saved, since the MDnsConnection On 2013/06/12 21:35:41, szym wrote: > nit: receive Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:414: void SimulatePacketRecieve(const char* packet, unsigned size); On 2013/06/12 21:35:41, szym wrote: > nit: Receive Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:499: listener_privet->Start(); On 2013/06/12 21:35:41, szym wrote: > Should you ASSERT_TRUE all Start() calls (both listeners and transactions)? Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:525: RunUntilIdle(); On 2013/06/12 21:35:41, szym wrote: > I don't think you need to run the loop here. It should already be idle. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:553: TEST_F(MDnsTest, PassiveListenersCleanup) { On 2013/06/12 21:35:41, szym wrote: > I suggest PassiveListenersCacheCleanup. Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:579: EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordRemoved, _)) On 2013/06/12 21:35:41, szym wrote: > Add a comment "Expect record is removed when its TTL expires." Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:629: TEST_F(MDnsTest, TransactionNoCache) { On 2013/06/12 21:35:41, szym wrote: > I suggest TransactionWithEmptyCache Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:925: MockDatagramServerSocket* socket = sockets_.front(); On 2013/06/12 21:35:41, szym wrote: > It'd be nice if you could ensure test failure without crash in case > MDnsConnection only created one socket. (EXPECT_EQ will not abort the test, so > you will still crash.) But given how simple MDnsConnection is, I'm not too > concerned about this ever becoming an issue. Replaced with assert. Verified no crash. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:955: // Follow successful connection initialization On 2013/06/12 21:35:41, szym wrote: > nit: end with "." Done. https://codereview.chromium.org/15733008/diff/128001/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:980: connection_.Init(); On 2013/06/12 21:35:41, szym wrote: > I suggest you return the value or (return connection_.Init() == OK) and ASSERT > it in the test. Done.
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/noamsml@chromium.org/15733008/158002
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/noamsml@chromium.org/15733008/158002
Sorry for I got bad news for ya. Compile failed with a clobber build on mac_rel. http://build.chromium.org/p/tryserver.chromium/buildstatus?builder=mac_rel&nu... Your code is likely broken or HEAD is junk. Please ensure your code is not broken then alert the build sheriffs. Look at the try server FAQ for more details.
On 2013/06/13 06:47:46, I haz the power (commit-bot) wrote: > Sorry for I got bad news for ya. > Compile failed with a clobber build on mac_rel. > http://build.chromium.org/p/tryserver.chromium/buildstatus?builder=mac_rel&nu... > Your code is likely broken or HEAD is junk. Please ensure your > code is not broken then alert the build sheriffs. > Look at the try server FAQ for more details. Looks like it was a broken HEAD. The tree is currently open so I'm going to try again.
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/noamsml@chromium.org/15733008/158002
https://codereview.chromium.org/15733008/diff/158002/net/dns/mdns_client_impl.cc File net/dns/mdns_client_impl.cc (right): https://codereview.chromium.org/15733008/diff/158002/net/dns/mdns_client_impl... net/dns/mdns_client_impl.cc:481: DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_); For future reference, you don't need the class name here, since you are in a derived class. I understand if you want to be more explicit for readability (although it makes lines longer). https://codereview.chromium.org/15733008/diff/158002/net/dns/mdns_client_unit... File net/dns/mdns_client_unittest.cc (right): https://codereview.chromium.org/15733008/diff/158002/net/dns/mdns_client_unit... net/dns/mdns_client_unittest.cc:574: RunUntilIdle(); I don't think you need any RunUntilIdle after just SimulatePacketReceive. Ok to do it in a cleanup CL.
Message was sent while issue was closed.
Change committed as 206170 |