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