Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion include/tinycsocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#ifndef TINYCSOCKET_INTERNAL_H_
#define TINYCSOCKET_INTERNAL_H_

static const char* const TCS_VERSION_TXT = "v0.3.70";
static const char* const TCS_VERSION_TXT = "v0.3.71";
static const char* const TCS_LICENSE_TXT =
"Copyright 2018 Markus Lindelöw\n"
"\n"
Expand Down Expand Up @@ -125,8 +125,10 @@ static const char* const TCS_LICENSE_TXT =
* - TcsResult tcs_opt_nonblocking_set(TcsSocket socket_ctx, bool do_nonblocking);
* - TcsResult tcs_opt_nonblocking_get(TcsSocket socket_ctx, bool* is_nonblocking);
* - TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_membership_add_str(TcsSocket socket_ctx, const char* multicast_address);
* - TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx, const struct TcsAddress* local_address, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_membership_drop_str(TcsSocket socket_ctx, const char* multicast_address);
* - TcsResult tcs_opt_membership_drop_from(TcsSocket socket_ctx, const struct TcsAddress* local_address, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_multicast_interface_set(TcsSocket socket_ctx, const struct TcsAddress* local_address);
* - TcsResult tcs_opt_multicast_loop_set(TcsSocket socket_ctx, bool do_loopback);
Expand Down Expand Up @@ -1681,6 +1683,21 @@ TcsResult tcs_opt_membership_drop_from(TcsSocket socket_ctx,
*/
TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);

/**
* @brief Join a multicast group by address string.
*
* Resolves the multicast address string and joins the group using the default local interface.
*
* @param socket_ctx socket to configure.
* @param multicast_address multicast group address string (e.g. "239.1.2.3" or "ff02::1").
* @return #TCS_SUCCESS if successful, otherwise the error code.
* @retval #TCS_ERROR_INVALID_ARGUMENT if multicast_address is NULL.
* @retval #TCS_ERROR_ADDRESS_LOOKUP_FAILED if the address string could not be resolved.
* @see tcs_opt_membership_add()
* @see tcs_opt_membership_drop_str()
*/
TcsResult tcs_opt_membership_add_str(TcsSocket socket_ctx, const char* multicast_address);

/**
* @brief Leave a multicast group using the default local interface.
*
Expand All @@ -1690,6 +1707,21 @@ TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress*
*/
TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);

/**
* @brief Leave a multicast group by address string.
*
* Parses the multicast address string and leaves the group using the default local interface.
*
* @param socket_ctx socket to configure.
* @param multicast_address multicast group address string (e.g. "239.1.2.3" or "ff02::1").
* @return #TCS_SUCCESS if successful, otherwise the error code.
* @retval #TCS_ERROR_INVALID_ARGUMENT if multicast_address is NULL.
* @retval #TCS_ERROR_ADDRESS_LOOKUP_FAILED if the address string could not be resolved.
* @see tcs_opt_membership_drop()
* @see tcs_opt_membership_add_str()
*/
TcsResult tcs_opt_membership_drop_str(TcsSocket socket_ctx, const char* multicast_address);

/**
* @brief Set the outgoing interface for multicast packets.
*
Expand Down Expand Up @@ -3417,6 +3449,8 @@ TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress*
return tcs_opt_membership_add_to(socket_ctx, &local_address, multicast_address);
}

// tcs_opt_membership_add_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx,
const struct TcsAddress* local_address,
const struct TcsAddress* multicast_address)
Expand Down Expand Up @@ -3499,6 +3533,8 @@ TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx,
return TCS_ERROR_NOT_IMPLEMENTED;
}

// tcs_opt_membership_drop_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address)
{
if (socket_ctx == TCS_SOCKET_INVALID)
Expand Down Expand Up @@ -5405,6 +5441,8 @@ TcsResult tcs_opt_nonblocking_get(TcsSocket socket_ctx, bool* is_non_blocking)
return TCS_ERROR_NOT_SUPPORTED;
}

// tcs_opt_membership_add_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress* multicast_address)
{
if (socket_ctx == TCS_SOCKET_INVALID)
Expand Down Expand Up @@ -5460,6 +5498,8 @@ TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx,
return TCS_ERROR_NOT_IMPLEMENTED;
}

// tcs_opt_membership_drop_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address)
{
if (socket_ctx == TCS_SOCKET_INVALID)
Expand Down Expand Up @@ -6784,8 +6824,36 @@ TcsResult tcs_opt_priority_get(TcsSocket socket_ctx, int* priority)
// tcs_opt_nonblocking_get() is defined in OS specific files

// tcs_opt_membership_add() is defined in OS specific files

TcsResult tcs_opt_membership_add_str(TcsSocket socket_ctx, const char* multicast_address)
{
if (multicast_address == NULL)
return TCS_ERROR_INVALID_ARGUMENT;

struct TcsAddress addr = TCS_ADDRESS_NONE;
TcsResult res = tcs_address_parse(multicast_address, &addr);
if (res != TCS_SUCCESS)
return res;

return tcs_opt_membership_add(socket_ctx, &addr);
}

// tcs_opt_membership_add_to() is defined in OS specific files
// tcs_opt_membership_drop() is defined in OS specific files

TcsResult tcs_opt_membership_drop_str(TcsSocket socket_ctx, const char* multicast_address)
{
if (multicast_address == NULL)
return TCS_ERROR_INVALID_ARGUMENT;

struct TcsAddress addr = TCS_ADDRESS_NONE;
TcsResult res = tcs_address_parse(multicast_address, &addr);
if (res != TCS_SUCCESS)
return res;

return tcs_opt_membership_drop(socket_ctx, &addr);
}

// tcs_opt_membership_drop_from() is defined in OS specific files

// ######## Address and Interface Utilities ########
Expand Down
28 changes: 28 additions & 0 deletions src/tinycsocket_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,36 @@ TcsResult tcs_opt_priority_get(TcsSocket socket_ctx, int* priority)
// tcs_opt_nonblocking_get() is defined in OS specific files

// tcs_opt_membership_add() is defined in OS specific files

TcsResult tcs_opt_membership_add_str(TcsSocket socket_ctx, const char* multicast_address)
{
if (multicast_address == NULL)
return TCS_ERROR_INVALID_ARGUMENT;

struct TcsAddress addr = TCS_ADDRESS_NONE;
TcsResult res = tcs_address_parse(multicast_address, &addr);
if (res != TCS_SUCCESS)
return res;

return tcs_opt_membership_add(socket_ctx, &addr);
}

// tcs_opt_membership_add_to() is defined in OS specific files
// tcs_opt_membership_drop() is defined in OS specific files

TcsResult tcs_opt_membership_drop_str(TcsSocket socket_ctx, const char* multicast_address)
{
if (multicast_address == NULL)
return TCS_ERROR_INVALID_ARGUMENT;

struct TcsAddress addr = TCS_ADDRESS_NONE;
TcsResult res = tcs_address_parse(multicast_address, &addr);
if (res != TCS_SUCCESS)
return res;

return tcs_opt_membership_drop(socket_ctx, &addr);
}

// tcs_opt_membership_drop_from() is defined in OS specific files

// ######## Address and Interface Utilities ########
Expand Down
34 changes: 33 additions & 1 deletion src/tinycsocket_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#ifndef TINYCSOCKET_INTERNAL_H_
#define TINYCSOCKET_INTERNAL_H_

static const char* const TCS_VERSION_TXT = "v0.3.70";
static const char* const TCS_VERSION_TXT = "v0.3.71";
static const char* const TCS_LICENSE_TXT =
"Copyright 2018 Markus Lindelöw\n"
"\n"
Expand Down Expand Up @@ -119,8 +119,10 @@ static const char* const TCS_LICENSE_TXT =
* - TcsResult tcs_opt_nonblocking_set(TcsSocket socket_ctx, bool do_nonblocking);
* - TcsResult tcs_opt_nonblocking_get(TcsSocket socket_ctx, bool* is_nonblocking);
* - TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_membership_add_str(TcsSocket socket_ctx, const char* multicast_address);
* - TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx, const struct TcsAddress* local_address, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_membership_drop_str(TcsSocket socket_ctx, const char* multicast_address);
* - TcsResult tcs_opt_membership_drop_from(TcsSocket socket_ctx, const struct TcsAddress* local_address, const struct TcsAddress* multicast_address);
* - TcsResult tcs_opt_multicast_interface_set(TcsSocket socket_ctx, const struct TcsAddress* local_address);
* - TcsResult tcs_opt_multicast_loop_set(TcsSocket socket_ctx, bool do_loopback);
Expand Down Expand Up @@ -1675,6 +1677,21 @@ TcsResult tcs_opt_membership_drop_from(TcsSocket socket_ctx,
*/
TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);

/**
* @brief Join a multicast group by address string.
*
* Resolves the multicast address string and joins the group using the default local interface.
*
* @param socket_ctx socket to configure.
* @param multicast_address multicast group address string (e.g. "239.1.2.3" or "ff02::1").
* @return #TCS_SUCCESS if successful, otherwise the error code.
* @retval #TCS_ERROR_INVALID_ARGUMENT if multicast_address is NULL.
* @retval #TCS_ERROR_ADDRESS_LOOKUP_FAILED if the address string could not be resolved.
* @see tcs_opt_membership_add()
* @see tcs_opt_membership_drop_str()
*/
TcsResult tcs_opt_membership_add_str(TcsSocket socket_ctx, const char* multicast_address);

/**
* @brief Leave a multicast group using the default local interface.
*
Expand All @@ -1684,6 +1701,21 @@ TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress*
*/
TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address);

/**
* @brief Leave a multicast group by address string.
*
* Parses the multicast address string and leaves the group using the default local interface.
*
* @param socket_ctx socket to configure.
* @param multicast_address multicast group address string (e.g. "239.1.2.3" or "ff02::1").
* @return #TCS_SUCCESS if successful, otherwise the error code.
* @retval #TCS_ERROR_INVALID_ARGUMENT if multicast_address is NULL.
* @retval #TCS_ERROR_ADDRESS_LOOKUP_FAILED if the address string could not be resolved.
* @see tcs_opt_membership_drop()
* @see tcs_opt_membership_add_str()
*/
TcsResult tcs_opt_membership_drop_str(TcsSocket socket_ctx, const char* multicast_address);

/**
* @brief Set the outgoing interface for multicast packets.
*
Expand Down
4 changes: 4 additions & 0 deletions src/tinycsocket_posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,8 @@ TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress*
return tcs_opt_membership_add_to(socket_ctx, &local_address, multicast_address);
}

// tcs_opt_membership_add_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx,
const struct TcsAddress* local_address,
const struct TcsAddress* multicast_address)
Expand Down Expand Up @@ -1278,6 +1280,8 @@ TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx,
return TCS_ERROR_NOT_IMPLEMENTED;
}

// tcs_opt_membership_drop_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address)
{
if (socket_ctx == TCS_SOCKET_INVALID)
Expand Down
4 changes: 4 additions & 0 deletions src/tinycsocket_win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,8 @@ TcsResult tcs_opt_nonblocking_get(TcsSocket socket_ctx, bool* is_non_blocking)
return TCS_ERROR_NOT_SUPPORTED;
}

// tcs_opt_membership_add_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_add(TcsSocket socket_ctx, const struct TcsAddress* multicast_address)
{
if (socket_ctx == TCS_SOCKET_INVALID)
Expand Down Expand Up @@ -1319,6 +1321,8 @@ TcsResult tcs_opt_membership_add_to(TcsSocket socket_ctx,
return TCS_ERROR_NOT_IMPLEMENTED;
}

// tcs_opt_membership_drop_str() is defined in tinycsocket_common.c

TcsResult tcs_opt_membership_drop(TcsSocket socket_ctx, const struct TcsAddress* multicast_address)
{
if (socket_ctx == TCS_SOCKET_INVALID)
Expand Down
66 changes: 65 additions & 1 deletion tests/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ TEST_CASE("Example from README")
size_t bytes_received = 0;
CHECK(tcs_receive(client_socket, recv_buffer, 8192, TCS_FLAG_NONE, &bytes_received) == TCS_SUCCESS);
TcsResult shutdown_res = tcs_shutdown(client_socket, TCS_SD_BOTH);
CHECK((shutdown_res == TCS_SUCCESS || shutdown_res == TCS_ERROR_NOT_CONNECTED));
CHECK((shutdown_res == TCS_SUCCESS || shutdown_res == TCS_ERROR_NOT_CONNECTED ||
shutdown_res == TCS_ERROR_CONNECTION_RESET));
CHECK(tcs_close(&client_socket) == TCS_SUCCESS);

REQUIRE(tcs_lib_free() == TCS_SUCCESS);
Expand Down Expand Up @@ -1516,6 +1517,28 @@ TEST_CASE("Simple Multicast Add Membership")
REQUIRE(tcs_lib_free() == TCS_SUCCESS);
}

TEST_CASE("tcs_opt_membership_add_str")
{
// Setup
REQUIRE(tcs_lib_init() == TCS_SUCCESS);

TcsAddress loopback = TCS_ADDRESS_NONE;
loopback.family = TCS_AF_IP4;
loopback.data.ip4.address = TCS_ADDRESS_LOOPBACK_IP4;
loopback.data.ip4.port = 1902;

TcsSocket socket = TCS_SOCKET_INVALID;
CHECK(tcs_socket(&socket, TCS_AF_IP4, TCS_SOCK_DGRAM, 0) == TCS_SUCCESS);
CHECK(tcs_bind(socket, &loopback) == TCS_SUCCESS);

// When/Then
CHECK(tcs_opt_membership_add_str(socket, "239.255.255.251") == TCS_SUCCESS);

// Clean up
CHECK(tcs_close(&socket) == TCS_SUCCESS);
REQUIRE(tcs_lib_free() == TCS_SUCCESS);
}

TEST_CASE("Multicast Add-Drop-Add Membership")
{
// Setup
Expand Down Expand Up @@ -1573,6 +1596,29 @@ TEST_CASE("Multicast Add-Drop-Add Membership")
REQUIRE(tcs_lib_free() == TCS_SUCCESS);
}

TEST_CASE("tcs_opt_membership_drop_str")
{
// Setup
REQUIRE(tcs_lib_init() == TCS_SUCCESS);

TcsAddress loopback = TCS_ADDRESS_NONE;
loopback.family = TCS_AF_IP4;
loopback.data.ip4.address = TCS_ADDRESS_LOOPBACK_IP4;
loopback.data.ip4.port = 1903;

TcsSocket socket = TCS_SOCKET_INVALID;
CHECK(tcs_socket(&socket, TCS_AF_IP4, TCS_SOCK_DGRAM, 0) == TCS_SUCCESS);
CHECK(tcs_bind(socket, &loopback) == TCS_SUCCESS);

// When/Then
CHECK(tcs_opt_membership_add_str(socket, "239.255.255.251") == TCS_SUCCESS);
CHECK(tcs_opt_membership_drop_str(socket, "239.255.255.251") == TCS_SUCCESS);

// Clean up
CHECK(tcs_close(&socket) == TCS_SUCCESS);
REQUIRE(tcs_lib_free() == TCS_SUCCESS);
}

#if defined(__linux__)
TEST_CASE("Simple AVTP talker")
{
Expand Down Expand Up @@ -2170,6 +2216,24 @@ TEST_CASE("tcs_socket_packet_str DGRAM")
// Clean up
REQUIRE(tcs_lib_free() == TCS_SUCCESS);
}

TEST_CASE("tcs_socket_packet multicast add and drop str")
{
// Setup
REQUIRE(tcs_lib_init() == TCS_SUCCESS);

// Given - create and bind a DGRAM packet socket on lo
TcsSocket socket = TCS_SOCKET_INVALID;
CHECK(tcs_socket_packet_str(&socket, "lo", 0x22F0, TCS_SOCK_DGRAM) == TCS_SUCCESS);

// When/Then - join and leave a multicast MAC group via str
CHECK(tcs_opt_membership_add_str(socket, "91:e0:f0:00:fe:00") == TCS_SUCCESS);
CHECK(tcs_opt_membership_drop_str(socket, "91:e0:f0:00:fe:00") == TCS_SUCCESS);

// Clean up
CHECK(tcs_close(&socket) == TCS_SUCCESS);
REQUIRE(tcs_lib_free() == TCS_SUCCESS);
}
#endif

TEST_CASE("tcs_socket_packet invalid arguments")
Expand Down
Loading