blob: 2b9843bb7b852ad2ca55802032120b4a3ea4c639 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/net/mdns/cpp/fidl.h>
#include <lib/zx/time.h>
#include <string>
#include "src/lib/fxl/command_line.h"
#include "src/lib/inet/ip_address.h"
namespace mdns {
enum class CommandVerb {
class Command {
static const std::string kResolve;
static const std::string kSubscribe;
static const std::string kPublish;
static const std::string kUnsubscribe;
static const std::string kUnpublish;
static const std::string kHelp;
static const std::string kQuit;
static const std::string kAllServices;
static void ShowHelp(CommandVerb command_verb);
CommandVerb verb() const { return verb_; }
// Positional parameters.
const std::string& host_name() const { return host_name_; }
const std::string& service_name() const { return service_name_; }
const std::string& instance_name() const { return instance_name_; }
uint16_t port() const { return port_; }
const std::vector<std::string>& text() const { return text_; }
const std::vector<inet::IpAddress>& addresses() const { return addresses_; }
CommandVerb help_verb() const { return help_verb_; }
// Options.
zx::duration timeout() const { return timeout_; }
fuchsia::net::mdns::Media media() const { return media_; }
fuchsia::net::mdns::IpVersions ip_versions() const { return ip_versions_; }
bool exclude_local() const { return exclude_local_; }
bool exclude_local_proxies() const { return exclude_local_proxies_; }
bool probe() const { return probe_; }
uint16_t srv_priority() const { return srv_priority_; }
uint16_t srv_weight() const { return srv_weight_; }
zx::duration ptr_ttl() const { return ptr_ttl_; }
zx::duration srv_ttl() const { return srv_ttl_; }
zx::duration txt_ttl() const { return txt_ttl_; }
const std::string& proxy_host_name() const { return proxy_host_name_; }
void ShowHelp() const;
explicit Command(CommandVerb verb) : verb_(verb) {}
static Command ResolveHost(std::string host_name) {
Command result(CommandVerb::kResolveHost);
result.host_name_ = std::move(host_name);
return result;
static Command ResolveInstance(std::string instance_name, std::string service_name) {
Command result(CommandVerb::kResolveInstance);
result.service_name_ = std::move(service_name);
result.instance_name_ = std::move(instance_name);
return result;
static Command SubscribeHost(std::string host_name) {
Command result(CommandVerb::kSubscribeHost);
result.host_name_ = std::move(host_name);
return result;
static Command SubscribeService(std::string service_name) {
Command result(CommandVerb::kSubscribeService);
result.service_name_ = std::move(service_name);
return result;
static Command PublishHost(std::string host_name, std::vector<inet::IpAddress> addresses) {
Command result(CommandVerb::kPublishHost);
result.host_name_ = std::move(host_name);
result.addresses_ = std::move(addresses);
return result;
static Command PublishInstance(std::string instance_name, std::string service_name, uint16_t port,
std::vector<std::string> text) {
Command result(CommandVerb::kPublishInstance);
result.service_name_ = std::move(service_name);
result.instance_name_ = std::move(instance_name);
result.port_ = port;
result.text_ = std::move(text);
return result;
static Command UnsubscribeHost(std::string host_name) {
Command result(CommandVerb::kUnsubscribeHost);
result.host_name_ = std::move(host_name);
return result;
static Command UnsubscribeService(std::string service_name) {
Command result(CommandVerb::kUnsubscribeService);
result.service_name_ = std::move(service_name);
return result;
static Command UnpublishHost(std::string host_name) {
Command result(CommandVerb::kUnpublishHost);
result.host_name_ = std::move(host_name);
return result;
static Command UnpublishInstance(std::string instance_name, std::string service_name) {
Command result(CommandVerb::kUnpublishInstance);
result.instance_name_ = std::move(instance_name);
result.service_name_ = std::move(service_name);
return result;
static Command Help(CommandVerb help_verb = CommandVerb::kEmpty) {
Command result(CommandVerb::kHelp);
result.help_verb_ = help_verb;
return result;
static Command Quit() { return Command(CommandVerb::kQuit); }
static Command Malformed() { return Command(CommandVerb::kMalformed); }
static Command Empty() { return Command(CommandVerb::kEmpty); }
CommandVerb verb_;
std::string host_name_;
std::string service_name_;
std::string instance_name_;
uint16_t port_ = 0;
std::vector<std::string> text_;
std::vector<inet::IpAddress> addresses_;
CommandVerb help_verb_ = CommandVerb::kEmpty;
zx::duration timeout_ = zx::sec(3);
fuchsia::net::mdns::Media media_ =
fuchsia::net::mdns::Media::WIRED | fuchsia::net::mdns::Media::WIRELESS;
fuchsia::net::mdns::IpVersions ip_versions_ =
fuchsia::net::mdns::IpVersions::V4 | fuchsia::net::mdns::IpVersions::V6;
bool exclude_local_ = false;
bool exclude_local_proxies_ = false;
bool probe_ = true;
uint16_t srv_priority_ = 0;
uint16_t srv_weight_ = 0;
zx::duration ptr_ttl_ = zx::sec(4500);
zx::duration srv_ttl_ = zx::sec(120);
zx::duration txt_ttl_ = zx::sec(4500);
std::string proxy_host_name_;
friend class CommandParser;
class CommandParser {
explicit CommandParser(const std::string& command_line);
CommandParser(int argc, const char** argv);
~CommandParser() = default;
Command Parse();
static constexpr size_t kMaxDnsLabelLength = 63;
// A MatchXxx method returns true and updates |pos_| if the item is matched. If the item is not
// matched, the method returns false and leaves |pos_| unchanged. Reference parameters ending
// in '_out' are used to deliver parsed values to the caller.
// Matches zero or more whitespace-prefixed options. The set of allows options depends on
// |command.verb()|, which must be initialized.
bool MatchOptions(Command& command);
// Matches a host full name (including the '.local.' suffix) and delivers the host simple name
// (not including the suffix).
bool MatchHostName(std::string& value_out);
// Matches a full instance name and delivers the simple instance name and the service name.
bool MatchInstanceName(std::string& instance_name_out, std::string& service_name_out);
// Matches a service name, including the '._tcp' or '._udp.' suffix".
bool MatchServiceName(std::string& value_out);
// Matches a |uint16_t|.
bool MatchUint16(uint16_t& value_out);
// Matches a list of text strings.
bool MatchText(std::vector<std::string>& value_out);
// Matches a text string.
bool MatchTextString(std::string& value_out);
// Matches a list of IP addresses.
bool MatchAddresses(std::vector<inet::IpAddress>& value_out);
// Matches an IP address terminated by end-of-input, whitespace, or ','.
bool MatchAddress(inet::IpAddress& value_out);
// Matches a DNS label containing no whitespace.
bool MatchDnsLabel(std::string& value_out, size_t max_length = kMaxDnsLabelLength);
// Matches a positive number of seconds.
bool MatchSeconds(zx::duration& value_out);
// Matches one or more media values with comma separators.
bool MatchMedia(fuchsia::net::mdns::Media& value_out);
// Matches a media value.
bool MatchMedium(fuchsia::net::mdns::Media& value_out);
// Matches one or more IP versions values with comma separators.
bool MatchIpVersions(fuchsia::net::mdns::IpVersions& value_out);
// Matches an IP versions value.
bool MatchIpVersion(fuchsia::net::mdns::IpVersions& value_out);
// Matches true or false.
bool MatchBool(bool& value_out);
// Matches |literal|.
bool MatchLiteral(const std::string& literal);
// Matches a decimal digit.
bool MatchDigit(uint8_t& value_out);
// Matches one or more whitespace characters.
bool MatchWhitespace();
// Matches end-of-input. Does not update |pos_|.
bool MatchEnd() const { return pos_ == str_.size(); }
// Matches any amount of whitespace followed by end-of-input.
bool MatchWhitespaceEnd();
// Returns the number of characters remaining to be parsed.
size_t chars_remaining() const { return str_.size() - pos_; }
// Returns the characters remaining to be parsed.
const char* remaining_chars() { return &str_[pos_]; }
void ConsumeChars(size_t chars) { pos_ += chars; }
void SetCharsRemaining(size_t chars_remaining) {
FX_CHECK(chars_remaining <= str_.size());
pos_ = str_.size() - chars_remaining;
const std::string str_;
size_t pos_ = 0;
} // namespace mdns