module-protocol-native: Handle pending connect

Do not return an error immediately if connect() fails with EAGAIN. Check
if it completed successfully with getsockopt() when the socket becomes
writable instead.

This is the way to handle non-blocking connect() by the book but after
testing it seems that the case when connect() fails with EAGAIN is when
the listen backlog is full on the server side and in that case the
server socket is closed. So even though connect() completes successfully
according to getsockopt() the client socket is no longer usable
(on_remote_data() will get both SPA_IO_OUT and SPA_IO_HUP in mask on the
first call after connect() returned EAGAIN).
This commit is contained in:
Jonas Holmberg 2021-04-21 19:01:22 +02:00 committed by Wim Taymans
parent 330e694e63
commit 1e6b7b8a83
2 changed files with 24 additions and 2 deletions

View file

@ -29,6 +29,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -106,6 +107,7 @@ struct client {
int ref;
unsigned int connected:1;
unsigned int disconnecting:1;
unsigned int need_flush:1;
unsigned int paused:1;
@ -826,6 +828,21 @@ on_remote_data(void *data, int fd, uint32_t mask)
goto error;
}
if (mask & SPA_IO_OUT || impl->need_flush) {
if (!impl->connected) {
socklen_t len = sizeof res;
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &len) < 0) {
res = -errno;
pw_log_error(NAME" getsockopt: %m");
goto error;
}
if (res != 0) {
res = -res;
goto error;
}
impl->connected = true;
pw_log_debug(NAME" %p: connected, fd %d", impl, fd);
}
impl->need_flush = false;
res = pw_protocol_native_connection_flush(conn);
if (res >= 0) {
@ -881,6 +898,7 @@ static int impl_connect_fd(struct pw_protocol_client *client, int fd, bool do_cl
struct client *impl = SPA_CONTAINER_OF(client, struct client, this);
int res;
impl->connected = false;
impl->disconnecting = false;
pw_protocol_native_connection_set_fd(impl->connection, fd);