mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
raop: connect TCP socket
Connect to the server TCP socket in TCP mode. Use getaddrinfo to resolve hostname.
This commit is contained in:
parent
ceeaf6c2f9
commit
c03d10296b
2 changed files with 87 additions and 44 deletions
|
|
@ -173,6 +173,7 @@ struct impl {
|
||||||
|
|
||||||
uint16_t server_port;
|
uint16_t server_port;
|
||||||
int server_fd;
|
int server_fd;
|
||||||
|
struct spa_source *server_source;
|
||||||
|
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
uint32_t delay;
|
uint32_t delay;
|
||||||
|
|
@ -537,7 +538,7 @@ error:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int connect_udp_socket(struct impl *impl, int fd, uint16_t port)
|
static int connect_socket(struct impl *impl, int type, int fd, uint16_t port)
|
||||||
{
|
{
|
||||||
const char *host;
|
const char *host;
|
||||||
struct sockaddr_in sa4;
|
struct sockaddr_in sa4;
|
||||||
|
|
@ -566,12 +567,13 @@ static int connect_udp_socket(struct impl *impl, int fd, uint16_t port)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd < 0 &&
|
if (fd < 0 &&
|
||||||
(fd = socket(af, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) {
|
(fd = socket(af, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) {
|
||||||
pw_log_error("socket failed: %m");
|
pw_log_error("socket failed: %m");
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(fd, sa, salen) < 0) {
|
res = connect(fd, sa, salen);
|
||||||
|
if (res < 0 && errno != EINPROGRESS) {
|
||||||
res = -errno;
|
res = -errno;
|
||||||
pw_log_error("connect failed: %m");
|
pw_log_error("connect failed: %m");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -726,6 +728,37 @@ static int rtsp_do_record(struct impl *impl)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_server_source_io(void *data, int fd, uint32_t mask)
|
||||||
|
{
|
||||||
|
struct impl *impl = data;
|
||||||
|
|
||||||
|
if (mask & (SPA_IO_ERR | SPA_IO_HUP))
|
||||||
|
goto error;
|
||||||
|
if (mask & SPA_IO_OUT) {
|
||||||
|
int res;
|
||||||
|
socklen_t len;
|
||||||
|
|
||||||
|
pw_loop_update_io(impl->loop, impl->server_source,
|
||||||
|
impl->server_source->mask & ~SPA_IO_OUT);
|
||||||
|
|
||||||
|
len = sizeof(res);
|
||||||
|
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &len) < 0) {
|
||||||
|
pw_log_error("getsockopt: %m");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (res != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
impl->ready = true;
|
||||||
|
if (pw_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
|
||||||
|
rtsp_do_record(impl);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
error:
|
||||||
|
pw_loop_update_io(impl->loop, impl->server_source, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void rtsp_setup_reply(void *data, int status, const struct spa_dict *headers)
|
static void rtsp_setup_reply(void *data, int status, const struct spa_dict *headers)
|
||||||
{
|
{
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
|
|
@ -763,10 +796,19 @@ static void rtsp_setup_reply(void *data, int status, const struct spa_dict *head
|
||||||
pw_log_error("missing server port in Transport");
|
pw_log_error("missing server port in Transport");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pw_getrandom(&impl->seq, sizeof(impl->seq), 0);
|
||||||
|
pw_getrandom(&impl->rtptime, sizeof(impl->rtptime), 0);
|
||||||
|
|
||||||
pw_log_info("server port:%u", impl->server_port);
|
pw_log_info("server port:%u", impl->server_port);
|
||||||
|
|
||||||
switch (impl->protocol) {
|
switch (impl->protocol) {
|
||||||
case PROTO_TCP:
|
case PROTO_TCP:
|
||||||
|
if ((impl->server_fd = connect_socket(impl, SOCK_STREAM, -1, impl->server_port)) <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
impl->server_source = pw_loop_add_io(impl->loop, impl->server_fd,
|
||||||
|
SPA_IO_OUT, false, on_server_source_io, impl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROTO_UDP:
|
case PROTO_UDP:
|
||||||
|
|
@ -776,11 +818,11 @@ static void rtsp_setup_reply(void *data, int status, const struct spa_dict *head
|
||||||
}
|
}
|
||||||
pw_log_info("control:%u timing:%u", control_port, timing_port);
|
pw_log_info("control:%u timing:%u", control_port, timing_port);
|
||||||
|
|
||||||
if ((impl->server_fd = connect_udp_socket(impl, -1, impl->server_port)) <= 0)
|
if ((impl->server_fd = connect_socket(impl, SOCK_DGRAM, -1, impl->server_port)) <= 0)
|
||||||
return;
|
return;
|
||||||
if ((impl->control_fd = connect_udp_socket(impl, impl->control_fd, control_port)) <= 0)
|
if ((impl->control_fd = connect_socket(impl, SOCK_DGRAM, impl->control_fd, control_port)) <= 0)
|
||||||
return;
|
return;
|
||||||
if ((impl->timing_fd = connect_udp_socket(impl, impl->timing_fd, timing_port)) <= 0)
|
if ((impl->timing_fd = connect_socket(impl, SOCK_DGRAM, impl->timing_fd, timing_port)) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ntp = ntp_now(CLOCK_MONOTONIC);
|
ntp = ntp_now(CLOCK_MONOTONIC);
|
||||||
|
|
@ -790,18 +832,14 @@ static void rtsp_setup_reply(void *data, int status, const struct spa_dict *head
|
||||||
SPA_IO_IN, false, on_timing_source_io, impl);
|
SPA_IO_IN, false, on_timing_source_io, impl);
|
||||||
impl->control_source = pw_loop_add_io(impl->loop, impl->control_fd,
|
impl->control_source = pw_loop_add_io(impl->loop, impl->control_fd,
|
||||||
SPA_IO_IN, false, on_control_source_io, impl);
|
SPA_IO_IN, false, on_control_source_io, impl);
|
||||||
|
|
||||||
|
impl->ready = true;
|
||||||
|
if (pw_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
|
||||||
|
rtsp_do_record(impl);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pw_getrandom(&impl->seq, sizeof(impl->seq), 0);
|
|
||||||
pw_getrandom(&impl->rtptime, sizeof(impl->rtptime), 0);
|
|
||||||
|
|
||||||
impl->ready = true;
|
|
||||||
|
|
||||||
if (pw_stream_get_state(impl->stream, NULL) == PW_STREAM_STATE_STREAMING)
|
|
||||||
rtsp_do_record(impl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtsp_do_setup(struct impl *impl)
|
static int rtsp_do_setup(struct impl *impl)
|
||||||
|
|
@ -1168,6 +1206,10 @@ static void connection_cleanup(struct impl *impl)
|
||||||
close(impl->timing_fd);
|
close(impl->timing_fd);
|
||||||
impl->timing_fd = -1;
|
impl->timing_fd = -1;
|
||||||
}
|
}
|
||||||
|
if (impl->server_source != NULL) {
|
||||||
|
pw_loop_destroy_source(impl->loop, impl->server_source);
|
||||||
|
impl->server_source = NULL;
|
||||||
|
}
|
||||||
if (impl->timing_source != NULL) {
|
if (impl->timing_source != NULL) {
|
||||||
pw_loop_destroy_source(impl->loop, impl->timing_source);
|
pw_loop_destroy_source(impl->loop, impl->timing_source);
|
||||||
impl->timing_source = NULL;
|
impl->timing_source = NULL;
|
||||||
|
|
|
||||||
|
|
@ -388,51 +388,52 @@ error:
|
||||||
int pw_rtsp_client_connect(struct pw_rtsp_client *client,
|
int pw_rtsp_client_connect(struct pw_rtsp_client *client,
|
||||||
const char *hostname, uint16_t port, const char *session_id)
|
const char *hostname, uint16_t port, const char *session_id)
|
||||||
{
|
{
|
||||||
struct sockaddr_in my_addr, dest_addr;
|
struct addrinfo hints;
|
||||||
struct hostent *h;
|
struct addrinfo *result, *rp;
|
||||||
int fd;
|
int res, fd;
|
||||||
|
char port_str[12];
|
||||||
|
|
||||||
if (client->source != NULL)
|
if (client->source != NULL)
|
||||||
pw_rtsp_client_disconnect(client);
|
pw_rtsp_client_disconnect(client);
|
||||||
|
|
||||||
pw_log_info("%p: connect %s:%u", client, hostname, port);
|
pw_log_info("%p: connect %s:%u", client, hostname, port);
|
||||||
fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
spa_zero(my_addr);
|
memset(&hints, 0, sizeof(hints));
|
||||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
hints.ai_family = AF_UNSPEC;
|
||||||
my_addr.sin_family = AF_INET;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
my_addr.sin_port = 0;
|
hints.ai_flags = 0;
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
|
||||||
|
spa_scnprintf(port_str, sizeof(port_str), "%u", port);
|
||||||
|
|
||||||
|
if ((res = getaddrinfo(hostname, port_str, &hints, &result)) != 0) {
|
||||||
|
pw_log_error("getaddrinfo: %s", gai_strerror(res));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||||
|
fd = socket(rp->ai_family,
|
||||||
|
rp->ai_socktype | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||||
|
rp->ai_protocol);
|
||||||
|
if (fd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
res = connect(fd, rp->ai_addr, rp->ai_addrlen);
|
||||||
|
if (res == 0 || (res < 0 && errno == EINPROGRESS))
|
||||||
|
break;
|
||||||
|
|
||||||
if (bind(fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
|
|
||||||
pw_log_error("%p: bind failed: %m", client);
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return -errno;
|
|
||||||
}
|
}
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
h = gethostbyname(hostname);
|
if (rp == NULL) {
|
||||||
if (h != NULL) {
|
pw_log_error("Could not connect to %s:%u", hostname, port);
|
||||||
dest_addr.sin_family = h->h_addrtype;
|
return -EINVAL;
|
||||||
memcpy((char*) &dest_addr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
|
|
||||||
} else {
|
|
||||||
dest_addr.sin_family = AF_INET;
|
|
||||||
if ((dest_addr.sin_addr.s_addr = inet_addr(hostname)) == 0xFFFFFFFF)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
dest_addr.sin_port = htons(port);
|
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) < 0) {
|
|
||||||
if (errno != EINPROGRESS) {
|
|
||||||
pw_log_error("%p: connect failed: %m", client);
|
|
||||||
close(fd);
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client->source = pw_loop_add_io(client->loop, fd,
|
client->source = pw_loop_add_io(client->loop, fd,
|
||||||
SPA_IO_IN | SPA_IO_OUT | SPA_IO_HUP | SPA_IO_ERR,
|
SPA_IO_IN | SPA_IO_OUT | SPA_IO_HUP | SPA_IO_ERR,
|
||||||
true, on_source_io, client);
|
true, on_source_io, client);
|
||||||
|
|
||||||
if (client->source == NULL) {
|
if (client->source == NULL) {
|
||||||
pw_log_error("%p: source create failed: %m", client);
|
pw_log_error("%p: source create failed: %m", client);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue