Improve accept(); allow select(2) on listeners

Changes:

    * Add validation to accept() to ensure file descriptors provided
      refer to SOCK_STREAM sockets in the SOCK_LISTENING state

    * Rather than writing a reply to the patty client socket when
      accepting a SABM or SABME request, write a message to the
      remote end of the listening socket; this avoids issues wherein
      a client receives an unexpected accept() response that may be
      unrelated to another pending request; this also allows client
      code to use select(2) on listening sockets

    * In patty_client_accept(), send the initial request to validate
      that the local socket can accept connections, and then wait for
      a connection to be made, reading a message written to the
      listening socket from the patty server

    * Allow select(2) to notify on accepted connections
This commit is contained in:
XANTRONIX Development 2020-08-12 00:19:46 -04:00 committed by XANTRONIX Industrial
parent 0b8ce4f775
commit 20cacf4bed
3 changed files with 72 additions and 30 deletions

View file

@ -120,11 +120,15 @@ typedef struct _patty_client_accept_request {
} patty_client_accept_request;
typedef struct _patty_client_accept_response {
int fd;
int ret;
int eno;
} patty_client_accept_response;
typedef struct _patty_client_accept_message {
int fd;
patty_ax25_addr peer;
char path[PATTY_AX25_SOCK_PATH_SIZE];
} patty_client_accept_response;
} patty_client_accept_message;
int patty_client_accept(patty_client *client,
int fd,

View file

@ -312,6 +312,7 @@ int patty_client_accept(patty_client *client,
patty_client_accept_request request;
patty_client_accept_response response;
patty_client_accept_message message;
patty_client_sock *local,
*remote;
@ -341,18 +342,33 @@ int patty_client_accept(patty_client *client,
goto error_io;
}
/*
* First, the server will tell us if the fd specified in accept() is indeed
* accepting connections.
*/
if (read(client->fd, &response, sizeof(response)) < 0) {
goto error_io;
}
if (response.fd >= 0) {
memcpy(peer, &response.peer, sizeof(*peer));
if (response.ret < 0) {
errno = response.eno;
remote->fd = response.fd;
strncpy(remote->path, response.path, sizeof(remote->path));
return response.ret;
}
/*
* Next, we will wait for the server to receive a SABM or SABME frame, and
* notify us via the listening socket that a connection has been accepted.
*/
if (read(fd, &message, sizeof(message)) < 0) {
goto error_io;
}
remote->fd = message.fd;
memcpy(peer, &message.peer, sizeof(*peer));
strncpy(remote->path, message.path, sizeof(remote->path));
if ((pty = open(remote->path, O_RDWR)) < 0) {
goto error_open;
}

View file

@ -514,26 +514,35 @@ int patty_ax25_server_add_route(patty_ax25_server *server,
}
static int respond_accept(int client,
int fd,
int eno,
patty_ax25_addr *peer,
char *path) {
patty_client_accept_response response;
int ret,
int eno) {
patty_client_accept_response response = {
.ret = ret,
.eno = eno
};
memset(&response, '\0', sizeof(response));
return write(client, &response, sizeof(response));
}
response.fd = fd;
response.eno = eno;
static int notify_accept(int local,
int remote,
patty_ax25_addr *peer,
char *path) {
patty_client_accept_message message;
memset(&message, '\0', sizeof(message));
message.fd = remote;
if (peer) {
memcpy(&response.peer, peer, sizeof(response.peer));
memcpy(&message.peer, peer, sizeof(message.peer));
}
if (path) {
strncpy(response.path, path, sizeof(response.path)-1);
strncpy(message.path, path, sizeof(message.path)-1);
}
return write(client, &response, sizeof(response));
return write(local, &message, sizeof(message));
}
static int respond_connect(int client, int ret, int eno) {
@ -770,13 +779,18 @@ static int server_accept(patty_ax25_server *server,
}
if ((sock = sock_by_fd(server->socks_by_fd, request.fd)) == NULL) {
goto error_sock_by_fd;
return respond_accept(client, -1, EBADF);
}
return 0;
if (sock->type != PATTY_AX25_SOCK_STREAM) {
return respond_accept(client, -1, EOPNOTSUPP);
}
error_sock_by_fd:
return respond_accept(client, -1, EBADF, NULL, NULL);
if (sock->state != PATTY_AX25_SOCK_LISTENING) {
return respond_accept(client, -1, EINVAL);
}
return respond_accept(client, 0, 0);
error_io:
return -1;
@ -1228,8 +1242,10 @@ static int handle_sabm(patty_ax25_server *server,
patty_ax25_sock *local, *remote;
if ((local = sock_by_addr(server->socks_local,
&frame->dest)) == NULL) {
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
&frame->dest)) == NULL
|| local->type != PATTY_AX25_SOCK_STREAM
|| local->state != PATTY_AX25_SOCK_LISTENING) {
goto reply_dm;
}
if ((client = client_by_sock(server, local)) < 0) {
@ -1254,6 +1270,8 @@ static int handle_sabm(patty_ax25_server *server,
save_reply_addr(remote, frame);
created = 1;
} else if (remote->state != PATTY_AX25_SOCK_PENDING_ACCEPT) {
goto reply_dm;
}
remote->state = PATTY_AX25_SOCK_ESTABLISHED;
@ -1280,15 +1298,18 @@ static int handle_sabm(patty_ax25_server *server,
fd_watch(server, remote->fd);
if (respond_accept(client, remote->fd, 0, &frame->src, remote->pty) < 0) {
goto error_respond_accept;
if (notify_accept(local->fd, remote->fd, &remote->remote, remote->pty) < 0) {
goto error_notify_accept;
}
patty_timer_start(&remote->timer_t3, PATTY_AX25_SOCK_DEFAULT_KEEPALIVE);
return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL);
error_respond_accept:
reply_dm:
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
error_notify_accept:
error_sock_realloc_bufs:
error_sock_save:
patty_ax25_sock_destroy(remote);
@ -1673,9 +1694,7 @@ static int handle_xid(patty_ax25_server *server,
patty_ax25_sock_params_max(remote);
if (patty_ax25_sock_params_negotiate(remote, &params) < 0) {
patty_ax25_sock_destroy(remote);
return respond_accept(client, -1, errno, NULL, NULL);
goto error_sock_params_negotiate;
}
save_reply_addr(remote, frame);
@ -1691,6 +1710,9 @@ reply_dm:
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
error_sock_save:
error_sock_params_negotiate:
patty_ax25_sock_destroy(remote);
error_sock_new:
error_client_by_sock:
error_io: