From a575d8eeb075d9138f4677d66242462a2c4d5939 Mon Sep 17 00:00:00 2001 From: Jianhui Zhao Date: Wed, 3 Apr 2024 12:12:30 +0800 Subject: [PATCH] feat(socket): add support multicast ``` sock:setoption('ip_add_membership', { multiaddr = '224.0.0.2', interface = '0.0.0.0' }) sock:setoption('ip_drop_membership', { multiaddr = '224.0.0.2', interface = '0.0.0.0' }) sock:setoption('ipv6_add_membership', { multiaddr = 'ff02::1', interface = 0 }) sock:setoption('ipv6_drop_membership', { multiaddr = 'ff02::1', interface = 0 }) ``` Signed-off-by: Jianhui Zhao --- examples/network/multicast/recver.lua | 24 +++++++++++++ examples/network/multicast/sender.lua | 31 +++++++++++++++++ socket.c | 50 +++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100755 examples/network/multicast/recver.lua create mode 100755 examples/network/multicast/sender.lua diff --git a/examples/network/multicast/recver.lua b/examples/network/multicast/recver.lua new file mode 100755 index 0000000..4b014c3 --- /dev/null +++ b/examples/network/multicast/recver.lua @@ -0,0 +1,24 @@ +#!/usr/bin/env eco + +local socket = require 'eco.socket' +local sys = require 'eco.sys' + +sys.signal(sys.SIGINT, function() + print('\nGot SIGINT, now quit') + eco.unloop() +end) + +local multicast_addr = '224.0.0.2' +local multicast_port = 8080 + +local sock, err = socket.listen_udp(nil, multicast_port) +if not sock then + error(err) +end + +sock:setoption('ip_add_membership', { multiaddr = multicast_addr }) + +while true do + local data, peer = sock:recvfrom(1024) + print('recvfrom:', peer.ipaddr, peer.port, data) +end diff --git a/examples/network/multicast/sender.lua b/examples/network/multicast/sender.lua new file mode 100755 index 0000000..921669e --- /dev/null +++ b/examples/network/multicast/sender.lua @@ -0,0 +1,31 @@ +#!/usr/bin/env eco + +local socket = require 'eco.socket' +local bufio = require 'eco.bufio' +local file = require 'eco.file' +local sys = require 'eco.sys' + +sys.signal(sys.SIGINT, function() + print('\nGot SIGINT, now quit') + eco.unloop() +end) + +local multicast_addr = '224.0.0.2' +local multicast_port = 8080 + +local sock, err = socket.udp() +if not sock then + error(err) +end + +local b = bufio.new(0) + +while true do + file.write(0, 'Please input: ') + + local data = b:read('l') + + if data ~= '' then + sock:sendto(data, multicast_addr, multicast_port) + end +end diff --git a/socket.c b/socket.c index b9fef42..196c3bd 100644 --- a/socket.c +++ b/socket.c @@ -680,6 +680,52 @@ static int sockopt_set_bindtodevice(struct eco_socket *sock, lua_State *L, struc return sockopt_set(sock, L, o, &ifr, sizeof(ifr)); } +static int sockopt_set_ip_membership(struct eco_socket *sock, lua_State *L, struct sock_opt *o) +{ + struct ip_mreq mreq = {}; + const char *multiaddr; + + luaL_checktype(L, 3, LUA_TTABLE); + + lua_getfield(L, 3, "multiaddr"); + + multiaddr = lua_tostring(L, -1); + + if (!multiaddr || inet_pton(AF_INET, multiaddr, &mreq.imr_multiaddr) != 1) + luaL_argerror(L, 3, "multiaddr: not a valid IP address"); + + lua_getfield(L, 3, "interface"); + + if (lua_isstring(L, -1)) { + const char *interface = lua_tostring(L, -1); + if (inet_pton(AF_INET, interface, &mreq.imr_interface) != 1) + luaL_argerror(L, 3, "interface: not a valid IP address"); + } + + return sockopt_set(sock, L, o, &mreq, sizeof(mreq)); +} + +static int sockopt_set_ipv6_membership(struct eco_socket *sock, lua_State *L, struct sock_opt *o) +{ + struct ipv6_mreq mreq; + const char *multiaddr; + + luaL_checktype(L, 3, LUA_TTABLE); + + lua_getfield(L, 3, "multiaddr"); + + multiaddr = lua_tostring(L, -1); + + if (!multiaddr || inet_pton(AF_INET6, multiaddr, &mreq.ipv6mr_multiaddr) != 1) + luaL_argerror(L, 3, "multiaddr: not a valid IPv6 address"); + + lua_getfield(L, 3, "interface"); + + mreq.ipv6mr_interface = luaL_optinteger(L, -1, 0); + + return sockopt_set(sock, L, o, &mreq, sizeof(mreq)); +} + static struct sock_opt optsets[] = { {"reuseaddr", SOL_SOCKET, SO_REUSEADDR, sockopt_set_boolean}, {"reuseport", SOL_SOCKET, SO_REUSEPORT, sockopt_set_boolean}, @@ -693,7 +739,11 @@ static struct sock_opt optsets[] = { {"tcp_keepcnt", SOL_TCP, TCP_KEEPCNT, sockopt_set_int}, {"tcp_fastopen", SOL_TCP, TCP_FASTOPEN, sockopt_set_int}, {"tcp_nodelay", SOL_TCP, TCP_NODELAY, sockopt_set_boolean}, + {"ip_add_membership", SOL_IP, IP_ADD_MEMBERSHIP, sockopt_set_ip_membership}, + {"ip_drop_membership", SOL_IP, IP_DROP_MEMBERSHIP, sockopt_set_ip_membership}, {"ipv6_v6only", SOL_IPV6, IPV6_V6ONLY, sockopt_set_boolean}, + {"ipv6_add_membership", SOL_IPV6, IPV6_ADD_MEMBERSHIP, sockopt_set_ipv6_membership}, + {"ipv6_drop_membership", SOL_IPV6, IPV6_DROP_MEMBERSHIP, sockopt_set_ipv6_membership}, {"netlink_add_membership", SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, sockopt_set_int}, {"netlink_drop_membership", SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, sockopt_set_int}, {}