Skip to content

Commit 273f6d3

Browse files
committed
add get_sockaddr + tests
to convert textual representation of host:port to sockaddr having this new function, we can also test get_sockaddr_str
1 parent 82aed4b commit 273f6d3

File tree

5 files changed

+123
-4
lines changed

5 files changed

+123
-4
lines changed

src/rtp/net_udp.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,13 @@ int udp_fd(socket_udp * s)
13941394
return 0;
13951395
}
13961396

1397+
/**
1398+
* @param[in] mode IP version preference (4 or 6) or 0 for none;
1399+
if 0 is requested, v4-mapped IPv6 address is returned
1400+
* @param[out] mode sockaddr struct version - 4 for input mode 4, 6 otherwise
1401+
*
1402+
* @returns 0 on success, GAI error on failure
1403+
*/
13971404
int resolve_addrinfo(const char *addr, uint16_t tx_port,
13981405
struct sockaddr_storage *dst, socklen_t *len, int *mode)
13991406
{

src/utils/net.c

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
3535
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3636
*/
37+
/**
38+
* @todo
39+
* move/use common network defs from compat/net.h
40+
*/
41+
42+
#include "utils/net.h"
3743

3844
#ifdef _WIN32
3945
#include <winsock2.h>
@@ -49,20 +55,19 @@ typedef SOCKET fd_t;
4955
#include <sys/socket.h>
5056
#include <sys/types.h>
5157
#include <unistd.h>
52-
#define closesocket close
5358
#define INVALID_SOCKET (-1)
5459
typedef int fd_t;
5560
#endif
5661

5762
#include <assert.h>
5863
#include <ctype.h>
5964
#include <errno.h>
60-
#include <limits.h>
6165
#include <stdint.h>
6266
#include <stdlib.h>
6367
#include <string.h>
6468

65-
#include "utils/net.h"
69+
#include "rtp/net_udp.h" // for resolve_addrinfo
70+
#include "utils/macros.h" // for STR_LEN
6671
#include "utils/windows.h"
6772

6873
#include "debug.h"
@@ -406,7 +411,7 @@ bool is_ipv6_supported(void)
406411
return false;
407412
}
408413
if (fd != INVALID_SOCKET) {
409-
closesocket(fd);
414+
CLOSESOCKET(fd);
410415
}
411416
return true;
412417
}
@@ -451,6 +456,68 @@ get_sockaddr_str(const struct sockaddr *sa, unsigned sa_len, char *buf,
451456
return buf;
452457
}
453458

459+
/**
460+
* @brief counterpart of get_sockaddr_str()
461+
*
462+
* @param mode mode to enforce 4, 6 or 0 (auto, as @ref resolve_addrinfo
463+
* returns v4-mapped IPv6 address for 0, the returned address will be aiways in
464+
* sockaddr_in6, either native or v4-mapped)
465+
*
466+
* @note
467+
* Even for dot-decimal IPv4 address, sockaddr_in6 struct with v4-mapped
468+
* address may be returned (Linux).
469+
*
470+
* Converts from textual representation of <host>:<port> to sockaddr_storage.
471+
* IPv6 numeric addresses must be enclosed in [] brackets.
472+
*/
473+
struct sockaddr_storage
474+
get_sockaddr(const char *hostport, int mode)
475+
{
476+
struct sockaddr_storage ret;
477+
socklen_t socklen_unused = 0;
478+
char host[STR_LEN];
479+
480+
ret.ss_family = AF_UNSPEC;
481+
const char *const rightmost_colon = strrchr(hostport, ':');
482+
if (rightmost_colon == NULL) {
483+
MSG(ERROR, "Address %s not in format host:port!\n", hostport);
484+
return ret;
485+
}
486+
if (rightmost_colon == hostport) {
487+
MSG(ERROR, "Empty host spec: %s!\n", hostport);
488+
return ret;
489+
}
490+
491+
const char *const port_str = rightmost_colon + 1;
492+
char *endptr = NULL;
493+
long port = strtol(port_str, &endptr, 10);
494+
if (*endptr != '\0') {
495+
MSG(ERROR, "Wrong port value: %s\n", port_str);
496+
return ret;
497+
}
498+
if (port < 0 || port > UINT16_MAX) {
499+
MSG(ERROR, "Port %ld out of range!\n", port);
500+
return ret;
501+
}
502+
503+
const char *host_start = hostport;
504+
const char *host_end = rightmost_colon;
505+
if (*host_start == '[') { // skip IPv6 []
506+
host_start += 1;
507+
if (host_end[-1] != ']') {
508+
MSG(ERROR, "Malformed IPv6 host (missing ]): %s\n",
509+
hostport);
510+
return ret;
511+
}
512+
host_end -= 1;
513+
}
514+
515+
const size_t len = host_end - host_start;
516+
snprintf(host, MIN(sizeof host, len + 1), "%s", host_start);
517+
resolve_addrinfo(host, port, &ret, &socklen_unused, &mode);
518+
return ret;
519+
}
520+
454521
const char *ug_gai_strerror(int errcode)
455522
{
456523
#ifdef _WIN32

src/utils/net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ bool get_local_addresses(struct sockaddr_storage *addrs, size_t *len, int ip_ver
8989
bool is_ipv6_supported(void);
9090
char *get_sockaddr_str(const struct sockaddr *sa, unsigned sa_len, char *buf,
9191
size_t n);
92+
struct sockaddr_storage get_sockaddr(const char *hostport, int mode);
9293
const char *ug_gai_strerror(int errcode);
9394

9495
#ifdef _WIN32

test/misc_test.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "color.h"
88
#include "types.h"
9+
#include "utils/net.h"
910
#include "utils/string.h"
1011
#include "unit_common.h"
1112
#include "video.h"
@@ -15,6 +16,7 @@ extern "C" {
1516
int misc_test_color_coeff_range();
1617
int misc_test_replace_all();
1718
int misc_test_video_desc_io_op_symmetry();
19+
int misc_test_net_getsockaddr();
1820
}
1921

2022
using namespace std;
@@ -66,6 +68,46 @@ misc_test_color_coeff_range()
6668
return 0;
6769
}
6870

71+
int
72+
misc_test_net_getsockaddr()
73+
{
74+
struct {
75+
const char *str;
76+
int ip_mode;
77+
} test_cases[] = {
78+
{ "10.0.0.1:10", 4 },
79+
{ "[100::1:abcd]:10", 6 },
80+
#if defined __APPLE__
81+
{ "[fe80::123%lo0]:1000", 6 },
82+
#elif defined __linux__
83+
{ "[fe80::123%lo]:1000", 6 },
84+
#elif defined _WIN32
85+
{ "[fe80::123%1]:1000", 6 },
86+
#endif
87+
};
88+
for (unsigned i = 0; i < sizeof test_cases / sizeof test_cases[0];
89+
++i) {
90+
struct sockaddr_storage ss =
91+
get_sockaddr(test_cases[i].str, test_cases[i].ip_mode);
92+
char buf[ADDR_STR_BUF_LEN] = "";
93+
get_sockaddr_str((struct sockaddr *) &ss, sizeof ss, buf,
94+
sizeof buf);
95+
char msg[2048];
96+
snprintf(msg, sizeof msg,
97+
"get_sockaddr_str conversion of '%s' failed",
98+
test_cases[i].str);
99+
ASSERT_MESSAGE(msg, ss.ss_family != AF_UNSPEC);
100+
snprintf(
101+
msg, sizeof msg,
102+
"sockaddr output string '%s' doesn't match the input '%s'",
103+
buf, test_cases[i].str);
104+
105+
ASSERT_MESSAGE(msg, strcmp(test_cases[i].str, buf) == 0);
106+
}
107+
108+
return 0;
109+
}
110+
69111
#ifdef __clang__
70112
#pragma clang diagnostic ignored "-Wstring-concatenation"
71113
#endif

test/run_tests.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ DECLARE_TEST(get_framerate_test_free);
8787
DECLARE_TEST(gpujpeg_test_simple);
8888
DECLARE_TEST(libavcodec_test_get_decoder_from_uv_to_uv);
8989
DECLARE_TEST(misc_test_color_coeff_range);
90+
DECLARE_TEST(misc_test_net_getsockaddr);
9091
DECLARE_TEST(misc_test_replace_all);
9192
DECLARE_TEST(misc_test_video_desc_io_op_symmetry);
9293

@@ -121,6 +122,7 @@ struct {
121122
DEFINE_TEST(gpujpeg_test_simple),
122123
DEFINE_TEST(libavcodec_test_get_decoder_from_uv_to_uv),
123124
DEFINE_TEST(misc_test_color_coeff_range),
125+
DEFINE_TEST(misc_test_net_getsockaddr),
124126
DEFINE_TEST(misc_test_replace_all),
125127
DEFINE_TEST(misc_test_video_desc_io_op_symmetry),
126128
};

0 commit comments

Comments
 (0)