mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
module-protocol-simple: use interface address as server address
Move the address:port parsing code to the net helper. Add a default address option. Pass the interface address to protocol-simple and use this as the default address for listening. This makes sure that when the user passes tcp:3400 that we don't end up publishing 0.0.0.0:3400 but the actual address of the interface we are listening on so that the snapcast discover can use this to notify the snapcast server. Fixes #4093
This commit is contained in:
parent
38d7dedf0c
commit
f5512e8b88
3 changed files with 88 additions and 43 deletions
|
|
@ -56,6 +56,8 @@
|
||||||
* sink for each connected client.
|
* sink for each connected client.
|
||||||
* - `playback`: boolean if playback is enabled. This will create a playback or
|
* - `playback`: boolean if playback is enabled. This will create a playback or
|
||||||
* source stream for each connected client.
|
* source stream for each connected client.
|
||||||
|
* - `local.ifname = <str>`: interface name to use
|
||||||
|
* - `local.ifaddress = <str>`: interface address to use
|
||||||
* - `server.address = []`: an array of server addresses to listen on as
|
* - `server.address = []`: an array of server addresses to listen on as
|
||||||
* tcp:(<ip>:)<port>.
|
* tcp:(<ip>:)<port>.
|
||||||
* - `capture.props`: optional properties for the capture stream
|
* - `capture.props`: optional properties for the capture stream
|
||||||
|
|
@ -208,6 +210,8 @@ struct impl {
|
||||||
struct pw_properties *capture_props;
|
struct pw_properties *capture_props;
|
||||||
struct pw_properties *playback_props;
|
struct pw_properties *playback_props;
|
||||||
|
|
||||||
|
char *ifname;
|
||||||
|
char *ifaddress;
|
||||||
bool capture;
|
bool capture;
|
||||||
bool playback;
|
bool playback;
|
||||||
|
|
||||||
|
|
@ -654,47 +658,16 @@ error:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t parse_port(const char *str, uint16_t def)
|
static int make_tcp_socket(struct server *server, const char *name, const char *ifname,
|
||||||
{
|
const char *ifaddress)
|
||||||
uint32_t val;
|
|
||||||
if (spa_atou32(str, &val, 0) && val <= 65535u)
|
|
||||||
return val;
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int make_tcp_socket(struct server *server, const char *name)
|
|
||||||
{
|
{
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
int res, fd, on;
|
int res, fd, on;
|
||||||
uint16_t port;
|
|
||||||
char *br = NULL, *col, *n;
|
|
||||||
socklen_t len = 0;
|
socklen_t len = 0;
|
||||||
|
|
||||||
n = strdupa(name);
|
if ((res = pw_net_parse_address_port(name, ifaddress, DEFAULT_PORT, &addr, &len)) < 0) {
|
||||||
|
pw_log_error("%p: can't parse address %s: %s", server,
|
||||||
col = strrchr(n, ':');
|
name, spa_strerror(res));
|
||||||
if (n[0] == '[') {
|
|
||||||
br = strchr(n, ']');
|
|
||||||
if (br == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
n++;
|
|
||||||
*br = 0;
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
if (br && col && col < br)
|
|
||||||
col = NULL;
|
|
||||||
|
|
||||||
if (col) {
|
|
||||||
*col = '\0';
|
|
||||||
port = parse_port(col+1, DEFAULT_PORT);
|
|
||||||
} else {
|
|
||||||
port = parse_port(n, DEFAULT_PORT);
|
|
||||||
n = strdupa("0.0.0.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = pw_net_parse_address(n, port, &addr, &len)) < 0) {
|
|
||||||
pw_log_error("%p: can't parse address:%s port:%d: %s", server,
|
|
||||||
n, port, spa_strerror(res));
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -703,7 +676,13 @@ static int make_tcp_socket(struct server *server, const char *name)
|
||||||
pw_log_error("%p: socket() failed: %m", server);
|
pw_log_error("%p: socket() failed: %m", server);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
#ifdef SO_BINDTODEVICE
|
||||||
|
if (ifname && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) {
|
||||||
|
res = -errno;
|
||||||
|
pw_log_error("%p: setsockopt(SO_BINDTODEVICE) failed: %m", server);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
on = 1;
|
on = 1;
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
|
||||||
pw_log_warn("%p: setsockopt(): %m", server);
|
pw_log_warn("%p: setsockopt(): %m", server);
|
||||||
|
|
@ -764,7 +743,7 @@ static struct server *create_server(struct impl *impl, const char *address)
|
||||||
spa_list_append(&impl->server_list, &server->link);
|
spa_list_append(&impl->server_list, &server->link);
|
||||||
|
|
||||||
if (spa_strstartswith(address, "tcp:")) {
|
if (spa_strstartswith(address, "tcp:")) {
|
||||||
fd = make_tcp_socket(server, address+4);
|
fd = make_tcp_socket(server, address+4, impl->ifname, impl->ifaddress);
|
||||||
} else {
|
} else {
|
||||||
pw_log_error("address %s does not start with tcp:", address);
|
pw_log_error("address %s does not start with tcp:", address);
|
||||||
fd = -EINVAL;
|
fd = -EINVAL;
|
||||||
|
|
@ -799,6 +778,8 @@ static void impl_free(struct impl *impl)
|
||||||
pw_properties_free(impl->capture_props);
|
pw_properties_free(impl->capture_props);
|
||||||
pw_properties_free(impl->playback_props);
|
pw_properties_free(impl->playback_props);
|
||||||
pw_properties_free(impl->props);
|
pw_properties_free(impl->props);
|
||||||
|
free(impl->ifname);
|
||||||
|
free(impl->ifaddress);
|
||||||
free(impl);
|
free(impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -976,6 +957,11 @@ static int parse_params(struct impl *impl)
|
||||||
pw_properties_setf(impl->playback_props, PW_KEY_NODE_RATE,
|
pw_properties_setf(impl->playback_props, PW_KEY_NODE_RATE,
|
||||||
"1/%u", impl->playback_info.rate);
|
"1/%u", impl->playback_info.rate);
|
||||||
|
|
||||||
|
str = pw_properties_get(impl->props, "local.ifname");
|
||||||
|
impl->ifname = str ? strdup(str) : NULL;
|
||||||
|
str = pw_properties_get(impl->props, "local.ifaddress");
|
||||||
|
impl->ifaddress = str ? strdup(str) : NULL;
|
||||||
|
|
||||||
if ((str = pw_properties_get(impl->props, "server.address")) == NULL)
|
if ((str = pw_properties_get(impl->props, "server.address")) == NULL)
|
||||||
str = DEFAULT_SERVER;
|
str = DEFAULT_SERVER;
|
||||||
|
|
||||||
|
|
@ -1056,9 +1042,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
bool ipv4;
|
bool ipv4;
|
||||||
|
|
||||||
if (pw_net_get_ip(&s->addr, ip, sizeof(ip), &ipv4, &port) >= 0)
|
if (pw_net_get_ip(&s->addr, ip, sizeof(ip), &ipv4, &port) < 0)
|
||||||
fprintf(f, " \"%s%s%s:%d\"", ipv4 ? "" : "[",
|
continue;
|
||||||
ip, ipv4 ? "" : "]", port);
|
|
||||||
|
fprintf(f, " \"%s%s%s:%d\"", ipv4 ? "" : "[", ip, ipv4 ? "" : "]", port);
|
||||||
}
|
}
|
||||||
fprintf(f, " ]");
|
fprintf(f, " ]");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@
|
||||||
#include "module-protocol-pulse/format.h"
|
#include "module-protocol-pulse/format.h"
|
||||||
#include "module-zeroconf-discover/avahi-poll.h"
|
#include "module-zeroconf-discover/avahi-poll.h"
|
||||||
|
|
||||||
|
#include "network-utils.h"
|
||||||
|
|
||||||
/** \page page_module_snapcast_discover Snapcast Discover
|
/** \page page_module_snapcast_discover Snapcast Discover
|
||||||
*
|
*
|
||||||
* Automatically creates a Snapcast sink device based on zeroconf
|
* Automatically creates a Snapcast sink device based on zeroconf
|
||||||
|
|
@ -465,9 +467,9 @@ static int add_snapcast_stream(struct impl *impl, struct tunnel *t,
|
||||||
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0) {
|
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0) {
|
||||||
t->server_address = strdup(v);
|
t->server_address = strdup(v);
|
||||||
snapcast_connect(t);
|
snapcast_connect(t);
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t format_from_name(const char *name, size_t len)
|
static inline uint32_t format_from_name(const char *name, size_t len)
|
||||||
|
|
@ -688,6 +690,7 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr
|
||||||
ifreq.ifr_ifindex = interface;
|
ifreq.ifr_ifindex = interface;
|
||||||
ioctl(fd, SIOCGIFNAME, &ifreq, sizeof(ifreq));
|
ioctl(fd, SIOCGIFNAME, &ifreq, sizeof(ifreq));
|
||||||
pw_properties_setf(props, "snapcast.ifname", "%s", ifreq.ifr_name);
|
pw_properties_setf(props, "snapcast.ifname", "%s", ifreq.ifr_name);
|
||||||
|
pw_properties_setf(props, "local.ifname", "%s", ifreq.ifr_name);
|
||||||
|
|
||||||
struct ifaddrs *if_addr, *ifp;
|
struct ifaddrs *if_addr, *ifp;
|
||||||
if (getifaddrs(&if_addr) < 0)
|
if (getifaddrs(&if_addr) < 0)
|
||||||
|
|
@ -711,6 +714,10 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr
|
||||||
family == AF_INET ? "" : "[",
|
family == AF_INET ? "" : "[",
|
||||||
hbuf,
|
hbuf,
|
||||||
family == AF_INET ? "" : "]");
|
family == AF_INET ? "" : "]");
|
||||||
|
pw_properties_setf(props, "local.ifaddress", "%s%s%s",
|
||||||
|
family == AF_INET ? "" : "[",
|
||||||
|
hbuf,
|
||||||
|
family == AF_INET ? "" : "]");
|
||||||
} else {
|
} else {
|
||||||
pw_log_warn("error: %m %d %s", res, gai_strerror(res));
|
pw_log_warn("error: %m %d %s", res, gai_strerror(res));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,44 @@ static inline int pw_net_parse_address(const char *address, uint16_t port,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint16_t pw_net_parse_port(const char *str, uint16_t def)
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
if (spa_atou32(str, &val, 0) && val <= 65535u)
|
||||||
|
return val;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pw_net_parse_address_port(const char *address,
|
||||||
|
const char *default_address, uint16_t default_port,
|
||||||
|
struct sockaddr_storage *addr, socklen_t *len)
|
||||||
|
{
|
||||||
|
uint16_t port;
|
||||||
|
char *br = NULL, *col, *n;
|
||||||
|
|
||||||
|
n = strdupa(address);
|
||||||
|
|
||||||
|
col = strrchr(n, ':');
|
||||||
|
if (n[0] == '[') {
|
||||||
|
br = strchr(n, ']');
|
||||||
|
if (br == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
n++;
|
||||||
|
*br = 0;
|
||||||
|
}
|
||||||
|
if (br && col && col < br)
|
||||||
|
col = NULL;
|
||||||
|
|
||||||
|
if (col) {
|
||||||
|
*col = '\0';
|
||||||
|
port = pw_net_parse_port(col+1, default_port);
|
||||||
|
} else {
|
||||||
|
port = pw_net_parse_port(n, default_port);
|
||||||
|
n = strdupa(default_address ? default_address : "0.0.0.0");
|
||||||
|
}
|
||||||
|
return pw_net_parse_address(n, port, addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int pw_net_get_ip(const struct sockaddr_storage *sa, char *ip, size_t len, bool *ip4, uint16_t *port)
|
static inline int pw_net_get_ip(const struct sockaddr_storage *sa, char *ip, size_t len, bool *ip4, uint16_t *port)
|
||||||
{
|
{
|
||||||
if (sa->ss_family == AF_INET) {
|
if (sa->ss_family == AF_INET) {
|
||||||
|
|
@ -75,4 +113,17 @@ static inline char *pw_net_get_ip_fmt(const struct sockaddr_storage *sa, char *i
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool pw_net_addr_is_any(struct sockaddr_storage *addr)
|
||||||
|
{
|
||||||
|
if (addr->ss_family == AF_INET) {
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in*)addr;
|
||||||
|
return sa->sin_addr.s_addr == INADDR_ANY;
|
||||||
|
} else if (addr->ss_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sa = (struct sockaddr_in6*)addr;
|
||||||
|
return memcmp(&sa->sin6_addr, &in6addr_any, sizeof(sa->sin6_addr));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* NETWORK_UTILS_H */
|
#endif /* NETWORK_UTILS_H */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue