Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Unified Diff: cloud_print/gcp20/prototype/dns_sd_server.cc

Issue 16975004: Finished DNS-SD server. Finished Privet-specified DNS-SD server. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed Lint errors. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: cloud_print/gcp20/prototype/dns_sd_server.cc
diff --git a/cloud_print/gcp20/prototype/dns_sd_server.cc b/cloud_print/gcp20/prototype/dns_sd_server.cc
index 0ca8b4395f508f3225067019951632252f9f338c..28575d1fa908d3baf6103caf2c8defb8bc0a433d 100644
--- a/cloud_print/gcp20/prototype/dns_sd_server.cc
+++ b/cloud_print/gcp20/prototype/dns_sd_server.cc
@@ -7,7 +7,13 @@
#include <string.h>
#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "cloud_print/gcp20/prototype/dns_packet_parser.h"
+#include "cloud_print/gcp20/prototype/dns_txt_builder.h"
#include "net/base/big_endian.h"
+#include "net/base/dns_util.h"
+#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/dns/dns_protocol.h"
@@ -16,29 +22,46 @@ namespace {
const char* kDefaultIpAddressMulticast = "224.0.0.251";
const uint16 kDefaultPortMulticast = 5353;
-// TODO(maksymb): Add possibility to set constants via command line arguments
-const uint32 kDefaultTTL = 60*60; // in seconds
+const double kTimeToNextAnnouncement = 0.8; // relatively to TTL
+const int kDnsBufSize = 65537;
+
+void DoNothing(int /*var*/) {
+ NOTREACHED();
+}
} // namespace
-DnsSdServer::DnsSdServer() : is_online_(false) {
- // Do nothing
+DnsSdServer::DnsSdServer()
+ : is_online_(false),
+ recv_buf_(new net::IOBufferWithSize(kDnsBufSize)) {
}
DnsSdServer::~DnsSdServer() {
Shutdown();
+
+ delete response_builder_factory_;
}
-bool DnsSdServer::Start() {
+bool DnsSdServer::Start(
+ DnsResponseBuilderFactoryInterface* response_builder_factory,
+ const uint32 full_ttl) {
if (is_online_)
return true;
if (!CreateSocket())
return false;
+ // Initializing server with parameters from arguments.
+ response_builder_factory_ = response_builder_factory;
+ full_ttl_ = full_ttl;
+
LOG(INFO) << "DNS server started";
+ LOG(WARNING) << "DNS server does not support probing";
- SendAnnouncement(kDefaultTTL);
+ SendAnnouncement(full_ttl_);
+ base::Closure callback = base::Bind(&DnsSdServer::OnDatagramReceived,
+ base::Unretained(this));
+ base::MessageLoop::current()->PostTask(FROM_HERE, callback);
is_online_ = true;
return true;
@@ -48,23 +71,19 @@ void DnsSdServer::Update() {
if (!is_online_)
return;
- SendAnnouncement(kDefaultTTL);
+ SendAnnouncement(full_ttl_);
}
void DnsSdServer::Shutdown() {
if (!is_online_)
return;
- SendAnnouncement(0); // ttl is 0
+ SendAnnouncement(0); // TTL is 0
socket_->Close();
is_online_ = false;
LOG(INFO) << "DNS server stopped";
}
-void DnsSdServer::ProcessMessages() {
- NOTIMPLEMENTED(); // implement this
-}
-
bool DnsSdServer::CreateSocket() {
net::IPAddressNumber local_ip_any;
bool success = net::ParseIPLiteralToNumber("0.0.0.0", &local_ip_any);
@@ -103,35 +122,157 @@ bool DnsSdServer::CreateSocket() {
return true;
}
-bool DnsSdServer::CheckPendingQueries() {
- NOTIMPLEMENTED(); // implement this
- return false;
-}
-
-void DoNothing(int /*var*/) {
- // Do nothing
-}
-
-void DnsSdServer::SendAnnouncement(uint32 ttl) {
- // Create a message with allocated space for header.
- // DNS header is temporary empty.
- scoped_ptr<std::vector<uint8> > message(
- new std::vector<uint8>(sizeof(net::dns_protocol::Header), 0)); // all is 0
+void DnsSdServer::ProcessMessage(
+ int len, const scoped_refptr<net::IOBufferWithSize> &buf) {
+ VLOG(1) << "Received new message with length: " << len;
+
+ // Parse the message
+ DnsPacketParser parser(buf.get()->data(),
+ len,
+ sizeof(net::dns_protocol::Header));
+
+ net::dns_protocol::Header header;
+ net::BigEndianReader reader(buf.get()->data(), len);
+ bool success = reader.ReadU16(&header.id) &&
+ reader.ReadU16(&header.flags) &&
+ reader.ReadU16(&header.qdcount) &&
+ reader.ReadU16(&header.ancount) &&
+ reader.ReadU16(&header.nscount) &&
+ reader.ReadU16(&header.arcount);
+
+ if (!success)
+ return;
- // TODO(maksymb): Create and implement DnsResponse class
+ scoped_refptr<net::IOBufferWithSize> buffer(
+ CreateResponsePacket(header, &parser).get());
- // Preparing for sending
- scoped_refptr<net::IOBufferWithSize> buffer =
- new net::IOBufferWithSize(static_cast<int>(message.get()->size()));
- memcpy(buffer.get()->data(), message.get()->data(), message.get()->size());
+ if (buffer.get() == NULL)
+ return; // No answers.
// Create empty callback (we don't need it at all) and send packet
net::CompletionCallback callback = base::Bind(DoNothing);
+
+ bool multicast_respond =
+ CommandLine::ForCurrentProcess()->HasSwitch("multicast-respond");
socket_->SendTo(buffer.get(),
buffer.get()->size(),
- multicast_address_,
+ multicast_respond ? multicast_address_ : recv_address_,
callback);
+ VLOG(1) << "Responded to "
+ << (multicast_respond ? multicast_address_ : recv_address_).ToString();
+}
+
+scoped_refptr<net::IOBufferWithSize> DnsSdServer::CreateResponsePacket(
+ const net::dns_protocol::Header& header,
+ DnsPacketParser* parser) const {
+ scoped_ptr<DnsResponseBuilderInterface> builder(
+ response_builder_factory_->Create(header.id));
+
+ // TODO(maksymb): Handle truncated messages.
+
+ uint32 current_ttl;
+ if (time_until_live_ < base::Time::Now()) {
+ // This should not be reachable. But still we don't need to fail.
+ current_ttl = 0;
+ LOG(ERROR) << "|current_ttl| equals to zero.";
+ } else {
+ current_ttl = (time_until_live_ - base::Time::Now()).InSeconds();
+ }
+
+ DnsQueryRecord query;
+ // TODO(maksymb): Check known answers.
+ for (int query_idx = 0; query_idx < header.qdcount; ++query_idx) {
+ bool success = parser->ReadRecord(&query);
+ if (success) {
+ std::string log;
+ bool responded = false;
+ switch (query.qtype) {
+ // TODO(maksymb): Add IPv6 support.
+ case net::dns_protocol::kTypePTR:
+ log = "Processing PTR query";
+ if ((responded = builder->CheckPtr(query.qname)))
+ builder->AppendPtr(current_ttl);
+ break;
+ case net::dns_protocol::kTypeSRV:
+ log = "Processing SRV query";
+ if ((responded = builder->CheckSrv(query.qname)))
+ builder->AppendSrv(current_ttl);
+ break;
+ case net::dns_protocol::kTypeA:
+ log = "Processing A query";
+ if ((responded = builder->CheckA(query.qname)))
+ builder->AppendA(current_ttl);
+ break;
+ case net::dns_protocol::kTypeTXT:
+ log = "Processing TXT query";
+ if ((responded = builder->CheckTxt(query.qname)))
+ builder->AppendTxt(current_ttl);
+ break;
+ default:
+ log = "Unknown query type";
+ }
+ log += responded ? ": responded" : ": ignored";
+ VLOG(1) << log;
+ } else { // if (success)
+ LOG(INFO) << "Broken package";
+ break;
+ }
+ }
+
+ if (builder->HaveAnswers()) {
+ VLOG(1) << "Current TTL for respond: " << current_ttl;
+ return builder->Build();
+ }
+ return NULL;
+}
- LOG(INFO) << "Announcement was sent with TTL: " << ttl;
+void DnsSdServer::DoLoop(int rv) {
Vitaly Buka (NO REVIEWS) 2013/06/14 19:27:07 rename please to ReadFromSocket
maksymb 2013/06/14 22:17:14 Template: https://codereview.chromium.org/15733008
+ // TODO(maksymb): Check what happened if buffer will be overflowed
+ do {
+ if (rv > 0)
+ ProcessMessage(rv, recv_buf_);
+ rv = socket_->RecvFrom(recv_buf_,
+ recv_buf_->size(),
+ &recv_address_,
+ base::Bind(&DnsSdServer::DoLoop,
+ base::Unretained(this)));
+ } while (rv > 0);
+
+ // TODO(maksymb): Add handler for errors
+ DCHECK(rv == net::ERR_IO_PENDING);
+}
+
+void DnsSdServer::OnDatagramReceived() {
+ DoLoop(0);
+}
+
+void DnsSdServer::SendAnnouncement(uint32 ttl) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch("no-announcement") == false) {
Vitaly Buka (NO REVIEWS) 2013/06/14 19:27:07 if (!CommandLine::ForCurrentProcess()->HasSwitch("
maksymb 2013/06/14 22:17:14 Done.
+ scoped_ptr<DnsResponseBuilderInterface> builder(
+ response_builder_factory_->Create(0));
+ scoped_refptr<net::IOBufferWithSize> buffer(
+ builder->BuildAnnouncement(ttl));
+
+ // Create empty callback (we don't need it at all) and send packet
+ net::CompletionCallback callback = base::Bind(DoNothing);
Vitaly Buka (NO REVIEWS) 2013/06/14 19:27:07 &DoNothing but better just ti remove DoNothing an
maksymb 2013/06/14 22:17:14 Done.
+ socket_->SendTo(buffer.get(),
+ buffer.get()->size(),
+ multicast_address_,
+ callback);
+
+ VLOG(1) << "Announcement was sent with TTL: " << ttl;
+ }
+
+ time_until_live_ = base::Time::Now() +
+ base::TimeDelta::FromSeconds(full_ttl_);
+
+ // Schedule next announcement.
+ base::Closure update_callback = base::Bind(&DnsSdServer::Update,
Vitaly Buka (NO REVIEWS) 2013/06/14 19:27:07 remove update_callback and just put bind inside Po
maksymb 2013/06/14 22:17:14 Done.
+ base::Unretained(this));
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ update_callback,
+ base::TimeDelta::FromSeconds(static_cast<int64>(
+ kTimeToNextAnnouncement*full_ttl_)));
}

Powered by Google App Engine
This is Rietveld 408576698