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; } patty_client_accept_request;
typedef struct _patty_client_accept_response { typedef struct _patty_client_accept_response {
int fd; int ret;
int eno; int eno;
} patty_client_accept_response;
typedef struct _patty_client_accept_message {
int fd;
patty_ax25_addr peer; patty_ax25_addr peer;
char path[PATTY_AX25_SOCK_PATH_SIZE]; char path[PATTY_AX25_SOCK_PATH_SIZE];
} patty_client_accept_response; } patty_client_accept_message;
int patty_client_accept(patty_client *client, int patty_client_accept(patty_client *client,
int fd, int fd,

View file

@ -312,6 +312,7 @@ int patty_client_accept(patty_client *client,
patty_client_accept_request request; patty_client_accept_request request;
patty_client_accept_response response; patty_client_accept_response response;
patty_client_accept_message message;
patty_client_sock *local, patty_client_sock *local,
*remote; *remote;
@ -341,18 +342,33 @@ int patty_client_accept(patty_client *client,
goto error_io; 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) { if (read(client->fd, &response, sizeof(response)) < 0) {
goto error_io; goto error_io;
} }
if (response.fd >= 0) { if (response.ret < 0) {
memcpy(peer, &response.peer, sizeof(*peer)); errno = response.eno;
remote->fd = response.fd; return response.ret;
strncpy(remote->path, response.path, sizeof(remote->path));
} }
/*
* 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) { if ((pty = open(remote->path, O_RDWR)) < 0) {
goto error_open; 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, static int respond_accept(int client,
int fd, int ret,
int eno, int eno) {
patty_ax25_addr *peer, patty_client_accept_response response = {
char *path) { .ret = ret,
patty_client_accept_response response; .eno = eno
};
memset(&response, '\0', sizeof(response)); return write(client, &response, sizeof(response));
}
response.fd = fd; static int notify_accept(int local,
response.eno = eno; int remote,
patty_ax25_addr *peer,
char *path) {
patty_client_accept_message message;
memset(&message, '\0', sizeof(message));
message.fd = remote;
if (peer) { if (peer) {
memcpy(&response.peer, peer, sizeof(response.peer)); memcpy(&message.peer, peer, sizeof(message.peer));
} }
if (path) { 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) { 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) { 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: if (sock->state != PATTY_AX25_SOCK_LISTENING) {
return respond_accept(client, -1, EBADF, NULL, NULL); return respond_accept(client, -1, EINVAL);
}
return respond_accept(client, 0, 0);
error_io: error_io:
return -1; return -1;
@ -1228,8 +1242,10 @@ static int handle_sabm(patty_ax25_server *server,
patty_ax25_sock *local, *remote; patty_ax25_sock *local, *remote;
if ((local = sock_by_addr(server->socks_local, if ((local = sock_by_addr(server->socks_local,
&frame->dest)) == NULL) { &frame->dest)) == NULL
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); || local->type != PATTY_AX25_SOCK_STREAM
|| local->state != PATTY_AX25_SOCK_LISTENING) {
goto reply_dm;
} }
if ((client = client_by_sock(server, local)) < 0) { 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); save_reply_addr(remote, frame);
created = 1; created = 1;
} else if (remote->state != PATTY_AX25_SOCK_PENDING_ACCEPT) {
goto reply_dm;
} }
remote->state = PATTY_AX25_SOCK_ESTABLISHED; remote->state = PATTY_AX25_SOCK_ESTABLISHED;
@ -1280,15 +1298,18 @@ static int handle_sabm(patty_ax25_server *server,
fd_watch(server, remote->fd); fd_watch(server, remote->fd);
if (respond_accept(client, remote->fd, 0, &frame->src, remote->pty) < 0) { if (notify_accept(local->fd, remote->fd, &remote->remote, remote->pty) < 0) {
goto error_respond_accept; goto error_notify_accept;
} }
patty_timer_start(&remote->timer_t3, PATTY_AX25_SOCK_DEFAULT_KEEPALIVE); patty_timer_start(&remote->timer_t3, PATTY_AX25_SOCK_DEFAULT_KEEPALIVE);
return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL); 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_realloc_bufs:
error_sock_save: error_sock_save:
patty_ax25_sock_destroy(remote); patty_ax25_sock_destroy(remote);
@ -1673,9 +1694,7 @@ static int handle_xid(patty_ax25_server *server,
patty_ax25_sock_params_max(remote); patty_ax25_sock_params_max(remote);
if (patty_ax25_sock_params_negotiate(remote, &params) < 0) { if (patty_ax25_sock_params_negotiate(remote, &params) < 0) {
patty_ax25_sock_destroy(remote); goto error_sock_params_negotiate;
return respond_accept(client, -1, errno, NULL, NULL);
} }
save_reply_addr(remote, frame); save_reply_addr(remote, frame);
@ -1691,6 +1710,9 @@ reply_dm:
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
error_sock_save: error_sock_save:
error_sock_params_negotiate:
patty_ax25_sock_destroy(remote);
error_sock_new: error_sock_new:
error_client_by_sock: error_client_by_sock:
error_io: error_io: