Open BitFis opened 3 months ago
Several things here.
IP_MULTICAST_LOOP is for IPv4 sockets. With it enabled, an application sending a multicast packet, this multicast packet will be received by any other application listening on a different socket on the same host. I do not think this is supported for IPv6.
With IPV6_MULTICAST_LOOP enabled, this allows the transmitting socket to also receive the multicast packet. As I read it, this has not control over other sockets on the same host added to the same multicast group.
It probably is best to add in a new function (like coap_mcast_set_hops()
) that can enable / disable IPV6_MULTICAST_LOOP / IPV_MULTICAST_LOOP on hte correct socket for the CoAP session - e.g. coap_mcast_set_ipv4_loop()
and coap_mcast_set_ipv6_loop()
@mrdeep1 thank you for the fast response.
Thanks for the hint just realized the mixup. I also found the multicast binding coap_join_mcast_group_intf
opens a new socket
so I am happy with your suggestion:
coap_mcast_set_ipv6_loop(coap_session_t *session, bool enable);
coap_mcast_set_ipv4_loop(coap_session_t *session, bool enable);
Would you like some help with the implementation?
For historical code compatibility reasons, bool is not currently supported, so these parameters would have to be an int with value 0 or 1.
For IPv6, using coap_join_mcast_group_intf()
just updates the server listening socket with listening on the appropriate multicast address on the appropriate interface. This however does not work for a client.
It is unclear to me as to what is your actual use case here.
The use case; I have multiple servers listening on the same multicast address + port and sending to the same multicast address + port.
A very basic event based system with ipv6 multicast.
To prevent the servers receiving their own messages (which leads to issues), I need to filter by source. But since there is this handy option IPV6_MULTICAST_LOOP
I would prefer to use this.
OK, so if I understand you correctly, you have a server A (well more than one, named B, C, D etc.) listening on a multicast address (group) + port. Then someone sends a multicast packet X, received by server A, and this server then decides to send out a multicast packet Y to the same multicast IP (group) and port. So, server B (and C, D etc) receive the original multicast packet X (but don't send out a multicast packet otherwise you will likely get a packet storm) as well as the multicast packet Y transmitted by A.
So, your issue is that Server A gets confused when it also sees the multicast packet Y it just sent. If that is the case, then IPV6_MULTICAST_LOOP simply needs to be disabled when coap_join_mcast_group_intf()
is called - or am I missing something?
Exactly the issue, From the example, A is a router with two interfaces and the function coap_join_mcast_group_intf()
would elegantly prevent that 😇 .
OK - then I think that all is needed is to disable IPV6_MULTICAST_LOOP
in coap_join_mcast_group_intf()
and there is no need for any additional functions. You are welcome to just raise a PR for that, as I consider that to be a bug.
Let me verify, disabling IPV6_MULTICAST_LOOP
on the sending socket worked, thought i am not sure disabling it on the receiving socket will work, the ibm docs say:
... The API uses IPV6_MULTICAST_LOOP socket option to enable or disable the loopback of OUTGOING multicast datagrams ... https://www.ibm.com/docs/en/zos/2.1.0?topic=options-ipv6-multicast-loop
Yes, it will only disable the sending socket receiving the multicast packet it just transmitted.
So disabling via coap_join_mcast_group_intf()
wont work,
since if I use coap_session_create_client()
to send the udp multicast message,
it will open a new socket which does not configure IPV6_MULTICAST_LOOP
, aka. IPV6_MULTICAST_LOOP
is enabled
and I still receive the multicast message.
Or am I missing something and I should not be using coap_session_create_client
or have to ensure coap_session_create_client
is already created for sending before calling coap_join_mcast_group_intf
?
You probably have understood it fully, but just to ensure we are on the same page, here a test implementation to verify: https://github.com/BitFis/example-multicast ,
If i have two sockets on the same linux/posix device. Socket A is the server listening socket and Socket B is the sending session socket.
Setting IPV6_MULTICAST_LOOP
(IPMUL) to disable on socket A, i will still receive the multicast messages from socket B. But having IPMUL on socket A enabled and disabled on socket B, I wont receive the multicast messages. So to solve this, either we add a coap_mcast_set_ipv4/6_loop
function or/and disable IPV6_MULTICAST_LOOP
by default. Thought all processes on the same machine will not receive the mutlicast messages, which may be desired by some for testing etc.
At least thats my current understanding of this configuration.
Ok. So one application is listening on socket that has multicast enabled as a server. It then opens new connection, sends multicast packet on new connection which is then picked up on the server side listening socket.
Not sure how to fix this for IPv6. Need to research this.
I think we simply need to disable IPV6_MULTICAST_LOOP when creating client type sockets.
Works for me, thought do you want to provide an option to enable loopback if desired? Aka. provide the new api anyways?
After checking further and having a few discussions, I would recommend not disabling IPV6_MULTICAST_LOOP
when creating the client type sockets.
In case its disabled no other local process will be able to receive the multicast message of the coap_client which might lead to issues for some setups on only one host. By example if a client and a server (router) are on the same machine and the client wants to send/publish an mcast message to all devices and the server (router). Also for testing and debugging this could confuse developers and may lead to unnecessary questions / bug reports.
I would recommend the coap_mcast_set_ipv4/6_loop
function and use it like the hop function. And only deviate from the standard linux configuation with functions.
May I open an PR to create a first draft for this new api functions?
Sure - go ahead and create a PR.
I do think that the client socket created by coap_proxy_get_ongoing_session()
should by default have IPV6_MULTICAST_LOOP disabled if the listening endpoint of the proxy/relay application has invoked coap_join_mcast_group_intf()
to safely protect against a multicast packet loop.
See #1502 which should fix your loop back issue for the client part of your application sending a mcast packet which is picked up by the server part of your application.
Will verify this, thanks. A side question, there is currently no functionality which detects duplicate messages via message id?
A side question, there is currently no functionality which detects duplicate messages via message id?
Not sure what you are trying to ask here - client or server side? There is some code that does this checking but possibly not in the areas you are thinking about. Please give a Use Case.
Hello, its a bit off topic of this issue, but I am thinking of server side in context of RFC7252 - 4.5. Message Deduplication.
The recipient SHOULD acknowledge each
duplicate copy of a Confirmable message using the same
Acknowledgement or Reset message but SHOULD process any request or
response in the message only once.
I am aware there some relaxation options, but just curious on if and how this is implemented. Maybe enabling ignoring a sent multicast message as duplicate.
Confirmable (CON) messages are explicitly not allowed for Multicast packets, so this is definitely off topic and should be raised in another issue.
Will verify this, thanks.
@BitFis Have you been able to verify that #1502 fixes your loopback issue?
Thank you for the update, I hope I will be able to verify soonish. Otherwise feel free to close this issue in the next few weeks. We can reopen accordingly.
Is your feature request related to a problem? Please describe.
Unable to configure IP_MULTICAST_LOOP which is important to define the correct behavior for sending multicast ipv6 packages.
Describe the solution you would like
Probably would be best to provide a function to retrieve the socket file descriptor.
Describe alternatives you have considered
Trying to retrieve the fid from
coap_context_get_coap_fd
. Not possible since the fid is well hidden in the epoll context. Alternatively directly accessing the socket fid, thought I prefer not to make libcoap a compile time depedency by using the internal includes.Alternatively an api for the
IP_MULTICAST_LOOP
behavior could be provided, Thought providing access to the fid would also support other socket option configurations without requiring new functions and therefore may be more future proof.Example API:
Additional context
Happy to alternatives. Also would provide an PR if support is welcome.