1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
// Copyright (c) 2015-2018 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "SoapySocketDefs.hpp"
#include "SoapyURLUtils.hpp"
#include <cstring> //memset
#include <string>
#include <cassert>
SockAddrData::SockAddrData(void)
{
return;
}
SockAddrData::SockAddrData(const struct sockaddr *addr, const int addrlen)
{
_storage.resize(addrlen);
std::memcpy(_storage.data(), addr, addrlen);
}
const struct sockaddr *SockAddrData::addr(void) const
{
return (const struct sockaddr *)_storage.data();
}
size_t SockAddrData::addrlen(void) const
{
return _storage.size();
}
SoapyURL::SoapyURL(void)
{
return;
}
SoapyURL::SoapyURL(const std::string &scheme, const std::string &node, const std::string &service):
_scheme(scheme),
_node(node),
_service(service)
{
return;
}
SoapyURL::SoapyURL(const std::string &url)
{
//extract the scheme
std::string urlRest = url;
auto schemeEnd = url.find("://");
if (schemeEnd != std::string::npos)
{
_scheme = url.substr(0, schemeEnd);
urlRest = url.substr(schemeEnd+3);
}
//extract node name and service port
bool inBracket = false;
bool inService = false;
for (size_t i = 0; i < urlRest.size(); i++)
{
const char ch = urlRest[i];
if (inBracket and ch == ']')
{
inBracket = false;
continue;
}
if (not inBracket and ch == '[')
{
inBracket = true;
continue;
}
if (inBracket)
{
_node += ch;
continue;
}
if (inService)
{
_service += ch;
continue;
}
if (not inService and ch == ':')
{
inService = true;
continue;
}
if (not inService)
{
_node += ch;
continue;
}
}
}
SoapyURL::SoapyURL(const struct sockaddr *addr)
{
char *s = NULL;
switch(addr->sa_family)
{
case AF_INET: {
auto *addr_in = (const struct sockaddr_in *)addr;
s = (char *)malloc(INET_ADDRSTRLEN);
inet_ntop(AF_INET, (void *)&(addr_in->sin_addr), s, INET_ADDRSTRLEN);
_node = s;
_service = std::to_string(ntohs(addr_in->sin_port));
break;
}
case AF_INET6: {
auto *addr_in6 = (const struct sockaddr_in6 *)addr;
s = (char *)malloc(INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, (void *)&(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
_node = s;
//support scoped address node
if (addr_in6->sin6_scope_id != 0)
{
_node += "%" + std::to_string(addr_in6->sin6_scope_id);
}
_service = std::to_string(ntohs(addr_in6->sin6_port));
break;
}
default:
break;
}
free(s);
}
SoapyURL::SoapyURL(const SockAddrData &addr)
{
*this = SoapyURL(addr.addr());
}
std::string SoapyURL::toSockAddr(SockAddrData &addr) const
{
SockAddrData result;
//unspecified service, cant continue
if (_service.empty()) return "service not specified";
//configure the hint
struct addrinfo hints, *servinfo = NULL;
std::memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = this->getType();
//get address info
int ret = getaddrinfo(_node.c_str(), _service.c_str(), &hints, &servinfo);
if (ret != 0) return gai_strerror(ret);
//iterate through possible matches
struct addrinfo *p = NULL;
for (p = servinfo; p != NULL; p = p->ai_next)
{
//eliminate unsupported family types
if (p->ai_family != AF_INET and p->ai_family != AF_INET6) continue;
//found a match
assert(p->ai_family == p->ai_addr->sa_family);
addr = SockAddrData(p->ai_addr, p->ai_addrlen);
break;
}
//cleanup
freeaddrinfo(servinfo);
//no results
if (p == NULL) return "no lookup results";
return ""; //OK
}
std::string SoapyURL::toString(void) const
{
std::string url;
//add the scheme
if (not _scheme.empty()) url += _scheme + "://";
//add the node with ipv6 escape brackets
if (_node.find(":") != std::string::npos) url += "[" + _node + "]";
else url += _node;
//and the service
if (not _service.empty()) url += ":" + _service;
return url;
}
std::string SoapyURL::getScheme(void) const
{
return _scheme;
}
std::string SoapyURL::getNode(void) const
{
return _node;
}
std::string SoapyURL::getService(void) const
{
return _service;
}
void SoapyURL::setScheme(const std::string &scheme)
{
_scheme = scheme;
}
void SoapyURL::setNode(const std::string &node)
{
_node = node;
}
void SoapyURL::setService(const std::string &service)
{
_service = service;
}
int SoapyURL::getType(void) const
{
if (_scheme == "tcp") return SOCK_STREAM;
if (_scheme == "udp") return SOCK_DGRAM;
return SOCK_STREAM; //assume
}
|