Shaka Packager SDK
Loading...
Searching...
No Matches
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
19ABSL_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
25namespace shaka {
26
27namespace {
28
29enum FieldType {
30 kUnknownField = 0,
31 kBufferSizeField,
32 kInterfaceAddressField,
33 kMulticastSourceField,
34 kReuseField,
35 kTimeoutField,
36};
37
38struct FieldNameToTypeMapping {
39 const char* field_name;
40 FieldType field_type;
41};
42
43const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
44 {"buffer_size", kBufferSizeField},
45 {"interface", kInterfaceAddressField},
46 {"reuse", kReuseField},
47 {"source", kMulticastSourceField},
48 {"timeout", kTimeoutField},
49};
50
51FieldType 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
59bool 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
84std::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)
All the methods that are virtual are virtual for mocking.