Support master server address format in client

This still works

	$ ./DDNet "connect 127.0.0.1"

But now also this works

	$ ./DDNet "connect tw-0.6+udp://ger10.ddnet.org:8303"
	2023-07-16 14:07:50 I engine: running on unix-linux-amd64
	2023-07-16 14:07:50 I client: starting...
	2023-07-16 14:07:50 I client: version 17.1.1 on linux amd64
	2023-07-16 14:07:50 I client: git revision hash: 7f100e2620
	2023-07-16 14:07:50 I client: connecting to 'tw-0.6+udp://ger10.ddnet.org:8303'
	2023-07-16 14:07:50 I host_lookup: host='ger10.ddnet.org' port=8303 3
	2023-07-16 14:07:51 I client: connected, sending info
This commit is contained in:
ChillerDragon 2023-07-16 14:04:58 +02:00
parent 1170add71e
commit f701e2eb16
5 changed files with 112 additions and 31 deletions

View file

@ -1344,6 +1344,48 @@ static int parse_uint16(unsigned short *out, const char **str)
return 0;
}
int net_addr_from_url(NETADDR *addr, const char *string, char *host_buf, size_t host_buf_size)
{
char host[128];
int length;
int start = 0;
int end;
int failure;
const char *str = str_startswith(string, "tw-0.6+udp://");
if(!str)
return 1;
mem_zero(addr, sizeof(*addr));
length = str_length(str);
end = length;
for(int i = 0; i < length; i++)
{
if(str[i] == '@')
{
if(start != 0)
{
// Two at signs.
return true;
}
start = i + 1;
}
else if(str[i] == '/' || str[i] == '?' || str[i] == '#')
{
end = i;
break;
}
}
str_truncate(host, sizeof(host), str + start, end - start);
if(host_buf)
str_copy(host_buf, host, host_buf_size);
if((failure = net_addr_from_str(addr, host)))
return failure;
return failure;
}
int net_addr_from_str(NETADDR *addr, const char *string)
{
const char *str = string;

View file

@ -937,6 +937,31 @@ int net_addr_comp_noport(const NETADDR *a, const NETADDR *b);
*/
void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port);
/**
* Turns url string into a network address struct.
* The url format is tw-0.6+udp://{ipaddr}[:{port}]
* ipaddr: can be ipv4 or ipv6
* port: is a optional internet protocol port
*
* This format is used for parsing the master server, be careful before changing it.
*
* Examples:
* tw-0.6+udp://127.0.0.1
* tw-0.6+udp://127.0.0.1:8303
*
* @param addr Address to fill in.
* @param string String to parse.
* @param host_buf Pointer to a buffer to write the host to
* It will include the port if one is included in the url
* It can also be set to NULL then it will be ignored
* @param host_buf_size Size of the host buffer or 0 if no host_buf pointer is given
*
* @return 0 on success,
* positive if the input wasn't a valid DDNet URL,
* negative if the input is a valid DDNet URL but the host part was not a valid IPv4/IPv6 address
*/
int net_addr_from_url(NETADDR *addr, const char *string, char *host_buf, size_t host_buf_size);
/**
* Turns string into a network address.
*

View file

@ -770,14 +770,19 @@ void CClient::Connect(const char *pAddress, const char *pPassword)
while((pNextAddr = str_next_token(pNextAddr, ",", aBuffer, sizeof(aBuffer))))
{
NETADDR NextAddr;
if(net_host_lookup(aBuffer, &NextAddr, m_aNetClient[CONN_MAIN].NetType()) != 0)
char aHost[128];
int url = net_addr_from_url(&NextAddr, aBuffer, aHost, sizeof(aHost));
if(url > 0)
str_copy(aHost, aBuffer);
if(net_host_lookup(aHost, &NextAddr, m_aNetClient[CONN_MAIN].NetType()) != 0)
{
log_error("client", "could not find address of %s", aBuffer);
log_error("client", "could not find address of %s", aHost);
continue;
}
if(NumConnectAddrs == (int)std::size(aConnectAddrs))
{
log_warn("client", "too many connect addresses, ignoring %s", aBuffer);
log_warn("client", "too many connect addresses, ignoring %s", aHost);
continue;
}
if(NextAddr.port == 0)

View file

@ -369,34 +369,7 @@ void CServerBrowserHttp::Refresh()
}
bool ServerbrowserParseUrl(NETADDR *pOut, const char *pUrl)
{
char aHost[128];
const char *pRest = str_startswith(pUrl, "tw-0.6+udp://");
if(!pRest)
{
return true;
}
int Length = str_length(pRest);
int Start = 0;
int End = Length;
for(int i = 0; i < Length; i++)
{
if(pRest[i] == '@')
{
if(Start != 0)
{
// Two at signs.
return true;
}
Start = i + 1;
}
else if(pRest[i] == '/' || pRest[i] == '?' || pRest[i] == '#')
{
End = i;
break;
}
}
str_truncate(aHost, sizeof(aHost), pRest + Start, End - Start);
return net_addr_from_str(pOut, aHost) != 0;
return net_addr_from_url(pOut, pUrl, nullptr, 0) != 0;
}
bool CServerBrowserHttp::Validate(json_value *pJson)
{

View file

@ -2,6 +2,42 @@
#include <base/system.h>
TEST(NetAddr, FromUrlString)
{
NETADDR Addr;
char aBuf1[NETADDR_MAXSTRSIZE];
char aBuf2[NETADDR_MAXSTRSIZE];
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+udp://127.0", nullptr, 0), -1); // invalid ip
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+udp://ddnet.org", nullptr, 0), -1); // invalid ip
EXPECT_EQ(net_addr_from_url(&Addr, "127.0.0.1", nullptr, 0), 1); // not a URL
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.9+udp://127.0.0.1", nullptr, 0), 1); // invalid tw protocol
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.7+udp://127.0.0.1", nullptr, 0), 1); // unsupported tw protocol
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+tcp://127.0.0.1", nullptr, 0), 1); // invalid internet protocol
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+udp://127.0.0.1", nullptr, 0), 0);
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf1, "127.0.0.1:0");
EXPECT_STREQ(aBuf2, "127.0.0.1");
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+udp://127.0.0.1", nullptr, 0), 0);
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf1, "127.0.0.1:0");
EXPECT_STREQ(aBuf2, "127.0.0.1");
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+udp://[0123:4567:89ab:cdef:1:2:3:4]:5678", nullptr, 0), 0);
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf1, "[123:4567:89ab:cdef:1:2:3:4]:5678");
EXPECT_STREQ(aBuf2, "[123:4567:89ab:cdef:1:2:3:4]");
char aHost[128];
EXPECT_EQ(net_addr_from_url(&Addr, "tw-0.6+udp://ger10.ddnet.org:5678", aHost, sizeof(aHost)), -1);
EXPECT_STREQ(aHost, "ger10.ddnet.org:5678");
}
TEST(NetAddr, FromStr)
{
NETADDR Addr;