Shaka Packager SDK
udp_options.cc
1 // Copyright 2016 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/file/udp_options.h>
8 
9 #include <iterator>
10 
11 #include <absl/flags/flag.h>
12 #include <absl/log/check.h>
13 #include <absl/log/log.h>
14 #include <absl/strings/numbers.h>
15 #include <absl/strings/str_split.h>
16 
17 #include <packager/kv_pairs/kv_pairs.h>
18 
19 ABSL_FLAG(std::string,
20  udp_interface_address,
21  "",
22  "IP address of the interface over which to receive UDP unicast"
23  " or multicast streams");
24 
25 namespace shaka {
26 
27 namespace {
28 
29 enum FieldType {
30  kUnknownField = 0,
31  kBufferSizeField,
32  kInterfaceAddressField,
33  kMulticastSourceField,
34  kReuseField,
35  kTimeoutField,
36 };
37 
38 struct FieldNameToTypeMapping {
39  const char* field_name;
40  FieldType field_type;
41 };
42 
43 const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
44  {"buffer_size", kBufferSizeField},
45  {"interface", kInterfaceAddressField},
46  {"reuse", kReuseField},
47  {"source", kMulticastSourceField},
48  {"timeout", kTimeoutField},
49 };
50 
51 FieldType GetFieldType(const std::string& field_name) {
52  for (size_t idx = 0; idx < std::size(kFieldNameTypeMappings); ++idx) {
53  if (field_name == kFieldNameTypeMappings[idx].field_name)
54  return kFieldNameTypeMappings[idx].field_type;
55  }
56  return kUnknownField;
57 }
58 
59 bool StringToAddressAndPort(std::string_view addr_and_port,
60  std::string* addr,
61  uint16_t* port) {
62  DCHECK(addr);
63  DCHECK(port);
64 
65  const size_t colon_pos = addr_and_port.find(':');
66  if (colon_pos == std::string_view::npos) {
67  return false;
68  }
69  *addr = addr_and_port.substr(0, colon_pos);
70 
71  // NOTE: SimpleAtoi will not take a uint16_t. So we check the bounds of the
72  // value and then cast to uint16_t.
73  uint32_t port_value;
74  if (!absl::SimpleAtoi(addr_and_port.substr(colon_pos + 1), &port_value) ||
75  (port_value > 65535)) {
76  return false;
77  }
78  *port = static_cast<uint16_t>(port_value);
79  return true;
80 }
81 
82 } // namespace
83 
84 std::unique_ptr<UdpOptions> UdpOptions::ParseFromString(
85  std::string_view udp_url) {
86  std::unique_ptr<UdpOptions> options(new UdpOptions);
87 
88  const size_t question_mark_pos = udp_url.find('?');
89  std::string_view address_str = udp_url.substr(0, question_mark_pos);
90 
91  if (question_mark_pos != std::string_view::npos) {
92  std::string_view options_str = udp_url.substr(question_mark_pos + 1);
93  std::vector<KVPair> kv_pairs = SplitStringIntoKeyValuePairs(options_str);
94 
95  for (const auto& pair : kv_pairs) {
96  switch (GetFieldType(pair.first)) {
97  case kBufferSizeField:
98  if (!absl::SimpleAtoi(pair.second, &options->buffer_size_)) {
99  LOG(ERROR) << "Invalid udp option for buffer_size field "
100  << pair.second;
101  return nullptr;
102  }
103  break;
104  case kInterfaceAddressField:
105  options->interface_address_ = pair.second;
106  break;
107  case kMulticastSourceField:
108  options->source_address_ = pair.second;
109  options->is_source_specific_multicast_ = true;
110  break;
111  case kReuseField: {
112  int reuse_value = 0;
113  if (!absl::SimpleAtoi(pair.second, &reuse_value)) {
114  LOG(ERROR) << "Invalid udp option for reuse field " << pair.second;
115  return nullptr;
116  }
117  options->reuse_ = reuse_value > 0;
118  break;
119  }
120  case kTimeoutField:
121  if (!absl::SimpleAtoi(pair.second, &options->timeout_us_)) {
122  LOG(ERROR) << "Invalid udp option for timeout field "
123  << pair.second;
124  return nullptr;
125  }
126  break;
127  default:
128  LOG(ERROR) << "Unknown field in udp options (\"" << pair.first
129  << "\").";
130  return nullptr;
131  }
132  }
133  }
134 
135  if (!absl::GetFlag(FLAGS_udp_interface_address).empty()) {
136  LOG(WARNING) << "--udp_interface_address is deprecated. Consider switching "
137  "to udp options instead, something like "
138  "udp:://ip:port?interface=interface_ip.";
139  options->interface_address_ = absl::GetFlag(FLAGS_udp_interface_address);
140  }
141 
142  if (!StringToAddressAndPort(address_str, &options->address_,
143  &options->port_)) {
144  LOG(ERROR) << "Malformed address:port UDP url " << address_str;
145  return nullptr;
146  }
147  return options;
148 }
149 
150 } // namespace shaka
Options parsed from UDP url string of the form: udp://ip:port[?options].
Definition: udp_options.h:13
static std::unique_ptr< UdpOptions > ParseFromString(std::string_view udp_url)
Definition: udp_options.cc:84
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66