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:
parent
0b8ce4f775
commit
20cacf4bed
3 changed files with 72 additions and 30 deletions
|
@ -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,
|
||||
|
|
26
src/client.c
26
src/client.c
|
@ -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;
|
||||
}
|
||||
|
|
64
src/server.c
64
src/server.c
|
@ -514,26 +514,35 @@ int patty_ax25_server_add_route(patty_ax25_server *server,
|
|||
}
|
||||
|
||||
static int respond_accept(int client,
|
||||
int fd,
|
||||
int eno,
|
||||
int ret,
|
||||
int eno) {
|
||||
patty_client_accept_response response = {
|
||||
.ret = ret,
|
||||
.eno = eno
|
||||
};
|
||||
|
||||
return write(client, &response, sizeof(response));
|
||||
}
|
||||
|
||||
static int notify_accept(int local,
|
||||
int remote,
|
||||
patty_ax25_addr *peer,
|
||||
char *path) {
|
||||
patty_client_accept_response response;
|
||||
patty_client_accept_message message;
|
||||
|
||||
memset(&response, '\0', sizeof(response));
|
||||
memset(&message, '\0', sizeof(message));
|
||||
|
||||
response.fd = fd;
|
||||
response.eno = eno;
|
||||
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, ¶ms) < 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:
|
||||
|
|
Loading…
Add table
Reference in a new issue