From 8761a4e3c2c5e36d7494a96c4ee576d7cbaa067a Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Wed, 22 Jul 2020 22:02:26 -0400 Subject: [PATCH] Refactor to adhere better to AX.25 v2.2 Changes: * Don't use a separate dict for keeping track of sockets pending accept and sockets pending connect; rely more on the semantic meaning of the enum patty_ax25_sock_status values * Ensure DISC frames are acknowledged by UA frames * Ensure a receiving system only shuts down a connection after receiving a UA frame in response to a sent DISC frame * Ensure a sending system only shuts down a connection just prior to sending a UA frame in response to a received DISC frame * Don't use the P/F flag for the connection management U frames; implicitly assume the P/F flag is set to 1, and always send frames with a true P/F flag --- include/patty/ax25/sock.h | 3 +- src/server.c | 550 ++++++++++++++++++++++---------------- 2 files changed, 319 insertions(+), 234 deletions(-) diff --git a/include/patty/ax25/sock.h b/include/patty/ax25/sock.h index 37c8c89..c40f135 100644 --- a/include/patty/ax25/sock.h +++ b/include/patty/ax25/sock.h @@ -30,7 +30,8 @@ enum patty_ax25_sock_status { PATTY_AX25_SOCK_LISTENING, PATTY_AX25_SOCK_PENDING_ACCEPT, PATTY_AX25_SOCK_PENDING_CONNECT, - PATTY_AX25_SOCK_ESTABLISHED + PATTY_AX25_SOCK_ESTABLISHED, + PATTY_AX25_SOCK_PROMISC }; enum patty_ax25_sock_mode { diff --git a/src/server.c b/src/server.c index d020eea..3231a21 100644 --- a/src/server.c +++ b/src/server.c @@ -29,9 +29,9 @@ struct _patty_ax25_server { patty_ax25_route_table *routes; patty_dict *socks_by_fd, - *socks_pending_accept, - *socks_pending_connect, - *socks_established; + *socks_by_client, + *socks_local, + *socks_remote; patty_dict *clients, *clients_by_sock; @@ -60,16 +60,16 @@ patty_ax25_server *patty_ax25_server_new(const char *path) { goto error_dict_new_socks_by_fd; } - if ((server->socks_pending_accept = patty_dict_new()) == NULL) { - goto error_dict_new_socks_pending_accept; + if ((server->socks_by_client = patty_dict_new()) == NULL) { + goto error_dict_new_socks_by_client; } - if ((server->socks_pending_connect = patty_dict_new()) == NULL) { - goto error_dict_new_socks_pending_connect; + if ((server->socks_local = patty_dict_new()) == NULL) { + goto error_dict_new_socks_local; } - if ((server->socks_established = patty_dict_new()) == NULL) { - goto error_dict_new_socks_established; + if ((server->socks_remote = patty_dict_new()) == NULL) { + goto error_dict_new_socks_remote; } if ((server->clients = patty_dict_new()) == NULL) { @@ -86,15 +86,15 @@ error_dict_new_clients_by_sock: patty_dict_destroy(server->clients); error_dict_new_clients: - patty_dict_destroy(server->socks_established); + patty_dict_destroy(server->socks_remote); -error_dict_new_socks_established: - patty_dict_destroy(server->socks_pending_connect); +error_dict_new_socks_remote: + patty_dict_destroy(server->socks_local); -error_dict_new_socks_pending_connect: - patty_dict_destroy(server->socks_pending_accept); +error_dict_new_socks_local: + patty_dict_destroy(server->socks_by_client); -error_dict_new_socks_pending_accept: +error_dict_new_socks_by_client: patty_dict_destroy(server->socks_by_fd); error_dict_new_socks_by_fd: @@ -116,12 +116,19 @@ static int destroy_if(patty_ax25_if *iface, void *ctx) { return 0; } +static int destroy_socks_by_client_entry(uint32_t key, void *value, void *ctx) { + patty_dict_destroy((patty_dict *)value); + + return 0; +} + void patty_ax25_server_destroy(patty_ax25_server *server) { patty_dict_destroy(server->clients_by_sock); patty_dict_destroy(server->clients); - patty_dict_destroy(server->socks_established); - patty_dict_destroy(server->socks_pending_connect); - patty_dict_destroy(server->socks_pending_accept); + patty_dict_destroy(server->socks_remote); + patty_dict_destroy(server->socks_local); + patty_dict_each(server->socks_by_client, destroy_socks_by_client_entry, NULL); + patty_dict_destroy(server->socks_by_client); patty_dict_destroy(server->socks_by_fd); patty_ax25_server_each_if(server, destroy_if, NULL); @@ -185,9 +192,7 @@ static patty_ax25_sock *sock_by_addrpair(patty_dict *dict, } static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) { - if (patty_dict_set(dict, - (uint32_t)sock->fd, - sock) == NULL) { + if (patty_dict_set(dict, (uint32_t)sock->fd, sock) == NULL) { goto error_dict_set; } @@ -229,7 +234,8 @@ error_dict_set: static inline int client_delete_by_sock(patty_ax25_server *server, patty_ax25_sock *sock) { - return patty_dict_delete(server->clients_by_sock, (uint32_t)sock->fd); + return patty_dict_delete(server->clients_by_sock, + (uint32_t)sock->fd); } static inline uint32_t hash_addr(patty_ax25_addr *addr) { @@ -254,87 +260,132 @@ static inline uint32_t hash_addrpair(patty_ax25_addr *local, return hash; } -static int sock_save_by_addr(patty_dict *dict, - patty_ax25_sock *sock, - patty_ax25_addr *addr) { - uint32_t hash = hash_addr(addr); +static int sock_save_local(patty_ax25_server *server, + patty_ax25_sock *sock) { + uint32_t hash = hash_addr(&sock->local); - if (patty_dict_set(dict, - hash, - sock) == NULL) { - goto error_dict_set; + return patty_dict_set(server->socks_local, hash, sock) == NULL? -1: 0; +} + +static int sock_save_remote(patty_ax25_server *server, + patty_ax25_sock *sock) { + uint32_t hash = hash_addrpair(&sock->local, &sock->remote); + + return patty_dict_set(server->socks_remote, hash, sock) == NULL? -1: 0; +} + +static int sock_delete_local(patty_ax25_server *server, + patty_ax25_sock *sock) { + uint32_t hash = hash_addr(&sock->local); + + return patty_dict_delete(server->socks_local, hash); +} + +static int sock_delete_remote(patty_ax25_server *server, + patty_ax25_sock *sock) { + uint32_t hash = hash_addrpair(&sock->local, &sock->remote); + + return patty_dict_delete(server->socks_remote, hash); +} + +static int sock_shutdown(patty_ax25_server *server, + patty_ax25_sock *sock) { + fd_clear(server, sock->fd); + + return sock->status == PATTY_AX25_SOCK_ESTABLISHED? + patty_ax25_sock_send_disc(sock, PATTY_AX25_FRAME_POLL): 0; +} + +static int sock_save(patty_ax25_server *server, + int client, + patty_ax25_sock *sock) { + patty_dict *socks; + + switch (sock->status) { + case PATTY_AX25_SOCK_LISTENING: + if (sock_save_local(server, sock) < 0) { + goto error_sock_save_local; + } + + break; + + case PATTY_AX25_SOCK_PENDING_ACCEPT: + case PATTY_AX25_SOCK_PENDING_CONNECT: + case PATTY_AX25_SOCK_ESTABLISHED: + if (sock_save_remote(server, sock) < 0) { + goto error_sock_save_remote; + } + + break; + + case PATTY_AX25_SOCK_CLOSED: + case PATTY_AX25_SOCK_PROMISC: + break; } - return 0; - -error_dict_set: - return -1; -} - -static int sock_save_by_addrpair(patty_dict *dict, - patty_ax25_sock *sock, - patty_ax25_addr *local, - patty_ax25_addr *remote) { - uint32_t hash = hash_addrpair(local, remote); - - if (patty_dict_set(dict, - hash, - sock) == NULL) { - goto error_dict_set; + if (client_save_by_sock(server, client, sock) < 0) { + goto error_client_save_by_sock; } - return 0; + if ((socks = patty_dict_get(server->socks_by_client, client)) == NULL) { + goto error_dict_get_socks_by_client; + } -error_dict_set: + if (sock_save_by_fd(socks, sock) < 0) { + goto error_sock_save_by_fd; + } + + return sock_save_by_fd(server->socks_by_fd, sock); + +error_sock_save_by_fd: +error_dict_get_socks_by_client: +error_client_save_by_sock: +error_sock_save_remote: +error_sock_save_local: return -1; } -static int sock_delete_by_addr(patty_dict *dict, - patty_ax25_addr *addr) { - uint32_t hash = hash_addr(addr); - - return patty_dict_delete(dict, hash); -} - -static int sock_delete_by_addrpair(patty_dict *dict, - patty_ax25_addr *local, - patty_ax25_addr *remote) { - uint32_t hash = hash_addrpair(local, remote); - - return patty_dict_delete(dict, hash); -} - static int sock_close(patty_ax25_server *server, patty_ax25_sock *sock) { - if (sock->status == PATTY_AX25_SOCK_ESTABLISHED) { - if (patty_ax25_sock_send_disc(sock, PATTY_AX25_FRAME_POLL) < 0) { - goto error_sock_send_disc; - } + int client; + patty_dict *socks; - if (sock_delete_by_addrpair(server->socks_established, - &sock->local, - &sock->remote) < 0) { - goto error_sock_delete_by_addrpair_established; - } + switch (sock->status) { + case PATTY_AX25_SOCK_LISTENING: + if (sock_delete_local(server, sock) < 0) { + goto error_sock_delete_local; + } + + break; + + case PATTY_AX25_SOCK_PENDING_ACCEPT: + case PATTY_AX25_SOCK_PENDING_CONNECT: + case PATTY_AX25_SOCK_ESTABLISHED: + if (sock_delete_remote(server, sock) < 0) { + goto error_sock_delete_remote; + } + + break; + + case PATTY_AX25_SOCK_CLOSED: + case PATTY_AX25_SOCK_PROMISC: + break; } - if (sock->status == PATTY_AX25_SOCK_PENDING_CONNECT) { - if (sock_delete_by_addrpair(server->socks_pending_connect, - &sock->local, - &sock->remote) < 0) { - goto error_sock_delete_by_addrpair_pending_connect; - } + if ((client = client_by_sock(server, sock)) < 0) { + goto error_client_by_sock; } - if (sock->status == PATTY_AX25_SOCK_PENDING_ACCEPT) { - if (sock_delete_by_addr(server->socks_pending_accept, - &sock->local) < 0) { - goto error_sock_delete_by_addr_pending_accept; - } + if ((socks = patty_dict_get(server->socks_by_client, client)) == NULL) { + goto error_dict_get_socks_by_client; + } + + if (patty_dict_delete(socks, (uint32_t)sock->fd) < 0) { + goto error_dict_delete_by_fd_socks; } if (patty_dict_delete(server->socks_by_fd, (uint32_t)sock->fd) < 0) { - goto error_dict_delete_by_fd_socks; + goto error_dict_delete_by_fd_socks_by_fd; } (void)client_delete_by_sock(server, sock); @@ -345,11 +396,12 @@ static int sock_close(patty_ax25_server *server, return 0; +error_dict_delete_by_fd_socks_by_fd: error_dict_delete_by_fd_socks: -error_sock_delete_by_addr_pending_accept: -error_sock_delete_by_addrpair_pending_connect: -error_sock_delete_by_addrpair_established: -error_sock_send_disc: +error_dict_get_socks_by_client: +error_client_by_sock: +error_sock_delete_remote: +error_sock_delete_local: return -1; } @@ -391,16 +443,11 @@ int patty_ax25_server_delete_if(patty_ax25_server *server, } if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { - fd_watch(server, fd); - - if (patty_dict_delete(server->socks_by_fd, (uint32_t)fd) < 0) { - goto error_dict_delete; - } + fd_clear(server, fd); } return 0; -error_dict_delete: error_list_splice: return -1; } @@ -463,15 +510,8 @@ static int server_socket(patty_ax25_server *server, goto error_sock_new; } - if (sock_save_by_fd(server->socks_by_fd, sock) < 0) { - response.ret = -1; - response.eno = errno; - - goto error_sock_save_by_fd; - } - - if (client_save_by_sock(server, client, sock) < 0) { - goto error_client_save_by_sock; + if (sock_save(server, client, sock) < 0) { + goto error_sock_save; } response.ret = sock->fd; @@ -481,8 +521,7 @@ static int server_socket(patty_ax25_server *server, return write(client, &response, sizeof(response)); -error_client_save_by_sock: -error_sock_save_by_fd: +error_sock_save: patty_ax25_sock_destroy(sock); error_sock_new: @@ -533,9 +572,7 @@ static int server_setsockopt(patty_ax25_server *server, patty_ax25_sock_bind_if(sock, iface); - if (sock_save_by_fd(server->socks_established, sock) < 0) { - goto error_sock_save_by_fd; - } + sock->status = PATTY_AX25_SOCK_PROMISC; fd_watch(server, sock->fd); @@ -558,7 +595,6 @@ error_invalid_type: error_invalid_opt: return write(client, &response, sizeof(response)); -error_sock_save_by_fd: error_read: return -1; } @@ -632,6 +668,10 @@ static int server_listen(patty_ax25_server *server, sock->status = PATTY_AX25_SOCK_LISTENING; + if (sock_save_local(server, sock) < 0) { + goto error_sock_save_local; + } + response.ret = 0; response.eno = 0; @@ -639,6 +679,7 @@ error_invalid_fd: error_sock_by_fd: return write(client, &response, sizeof(response)); +error_sock_save_local: error_io: return -1; } @@ -661,18 +702,11 @@ static int server_accept(patty_ax25_server *server, goto error_sock_by_fd; } - if (sock_save_by_addr(server->socks_pending_accept, - sock, - &sock->local) < 0) { - goto error_save_by_addr; - } - return 0; error_sock_by_fd: return write(client, &response, sizeof(response)); -error_save_by_addr: error_io: return -1; } @@ -759,11 +793,8 @@ static int server_connect(patty_ax25_server *server, sock->status = PATTY_AX25_SOCK_PENDING_CONNECT; - if (sock_save_by_addrpair(server->socks_pending_connect, - sock, - &sock->local, - &sock->remote) < 0) { - goto error_sock_save_by_addrpair; + if (sock_save_remote(server, sock) < 0) { + goto error_sock_save_remote; } if (client_save_by_sock(server, client, sock) < 0) { @@ -795,7 +826,7 @@ error_sock_by_fd: return write(client, &response, sizeof(response)); error_client_save_by_sock: -error_sock_save_by_addrpair: +error_sock_save_remote: error_io: return -1; } @@ -806,6 +837,7 @@ static int server_close(patty_ax25_server *server, patty_ax25_call_close_response response; patty_ax25_sock *sock; + patty_dict *socks; if (read(client, &request, sizeof(request)) < 0) { goto error_io; @@ -818,17 +850,33 @@ static int server_close(patty_ax25_server *server, goto error_sock_by_fd; } + if ((socks = patty_dict_get(server->socks_by_client, client)) == NULL) { + response.ret = -1; + response.eno = EBADF; + + goto error_dict_get_socks_by_client; + } + + if (sock_shutdown(server, sock) < 0) { + response.ret = -1; + response.eno = errno; + + goto error_sock_shutdown; + } + if (sock_close(server, sock) < 0) { response.ret = -1; response.eno = EBADF; - goto error_sock_delete; + goto error_sock_close; } response.ret = 0; response.eno = 0; -error_sock_delete: +error_sock_close: +error_sock_shutdown: +error_dict_get_socks_by_client: error_sock_by_fd: return write(client, &response, sizeof(response)); @@ -896,6 +944,7 @@ static int accept_client(patty_ax25_server *server) { int fd; struct sockaddr addr; socklen_t addrlen = sizeof(addr); + patty_dict *socks; memset(&addr, '\0', addrlen); @@ -907,8 +956,16 @@ static int accept_client(patty_ax25_server *server) { goto error_accept; } + if ((socks = patty_dict_new()) == NULL) { + goto error_dict_new; + } + if (patty_dict_set(server->clients, (uint32_t)fd, NULL + fd) == NULL) { - goto error_dict_set; + goto error_dict_set_clients; + } + + if (patty_dict_set(server->socks_by_client, (uint32_t)fd, socks) == NULL) { + goto error_dict_set_socks_by_client; } fd_watch(server, fd); @@ -916,13 +973,31 @@ static int accept_client(patty_ax25_server *server) { done: return 0; -error_dict_set: +error_dict_set_socks_by_client: +error_dict_set_clients: + patty_dict_destroy(socks); + +error_dict_new: close(fd); error_accept: return -1; } +static int client_sock_close(uint32_t key, void *value, void *ctx) { + patty_ax25_server *server = ctx; + patty_ax25_sock *sock = value; + + if (sock_shutdown(server, sock) < 0) { + goto error_sock_shutdown; + } + + return sock_close(server, sock); + +error_sock_shutdown: + return -1; +} + static int handle_client(uint32_t key, void *value, void *ctx) { @@ -939,10 +1014,21 @@ static int handle_client(uint32_t key, if ((readlen = read(client, &call, sizeof(call))) < 0) { goto error_io; } else if (readlen == 0) { + patty_dict *socks; + fd_clear(server, client); + if ((socks = patty_dict_get(server->socks_by_client, client)) != NULL) { + (void)patty_dict_each(socks, client_sock_close, server); + (void)patty_dict_destroy(socks); + } + + if (patty_dict_delete(server->socks_by_client, key) < 0) { + goto error_dict_delete_socks_by_client; + } + if (patty_dict_delete(server->clients, key) < 0) { - goto error_dict_delete; + goto error_dict_delete_clients; } if (close(client) < 0) { @@ -968,7 +1054,8 @@ done: return 0; error_not_implemented: -error_dict_delete: +error_dict_delete_socks_by_client: +error_dict_delete_clients: error_io: return -1; } @@ -1000,6 +1087,8 @@ static int reply_to(patty_ax25_if *iface, patty_ax25_frame *reply) { ssize_t len; + frame->cr = PATTY_AX25_FRAME_RESPONSE; + if ((len = patty_ax25_frame_encode_reply_to(frame, reply, iface->tx_buf, @@ -1036,11 +1125,6 @@ static int reply_ua(patty_ax25_if *iface, .infolen = 0 }; - char callsign[7]; - uint8_t ssid; - - patty_ax25_ntop(&frame->dest, callsign, &ssid, sizeof(callsign)); - return reply_to(iface, frame, &reply); } @@ -1049,23 +1133,26 @@ static int handle_frmr(patty_ax25_server *server, patty_ax25_frame *frame) { patty_ax25_sock *sock; - if ((sock = sock_by_addrpair(server->socks_pending_connect, + if ((sock = sock_by_addrpair(server->socks_remote, &frame->dest, &frame->src)) == NULL) { return 0; } - return patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL); + return sock->status == PATTY_AX25_SOCK_PENDING_CONNECT? + patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL): 0; } static int handle_sabm(patty_ax25_server *server, patty_ax25_if *iface, patty_ax25_frame *frame) { - int client; + int client, + created = 0; + patty_ax25_sock *local, *remote; patty_ax25_call_accept_response response; - if ((local = sock_by_addr(server->socks_pending_accept, + if ((local = sock_by_addr(server->socks_local, &frame->dest)) == NULL) { return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); } @@ -1074,45 +1161,41 @@ static int handle_sabm(patty_ax25_server *server, goto error_client_by_sock; } - if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) { - goto error_sock_new; + /* + * Look to see if there is already a remote socket created based on an XID + * packet previously received. + */ + if ((remote = sock_by_addrpair(server->socks_remote, + &frame->dest, + &frame->src)) == NULL) { + /* + * If there is no existing remote socket, we should create one, and + * associate it with the client. + */ + if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) { + goto error_sock_new; + } + + save_reply_addr(remote, frame); + + created = 1; } remote->status = PATTY_AX25_SOCK_ESTABLISHED; - remote->mode = (frame->type == PATTY_AX25_FRAME_SABM)? - PATTY_AX25_SOCK_SABM: PATTY_AX25_SOCK_SABME; + remote->mode = (frame->type == PATTY_AX25_FRAME_SABME)? + PATTY_AX25_SOCK_SABME: PATTY_AX25_SOCK_SABM; patty_ax25_sock_bind_if(remote, iface); - save_reply_addr(remote, frame); - - if (sock_save_by_fd(server->socks_by_fd, remote) < 0) { - goto error_sock_save_by_fd; - } - - if (sock_save_by_addrpair(server->socks_established, - remote, - &remote->local, - &remote->remote) < 0) { - goto error_sock_save_by_addrpair; - } - - if (sock_delete_by_addr(server->socks_pending_accept, - &local->local) < 0) { - goto error_sock_delete_by_addr; - } - - if (frame->pf) { - if (reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL) < 0) { - goto error_reply_ua; + if (created) { + if (sock_save(server, client, remote) < 0) { + goto error_sock_save; } } + fd_watch(server, remote->fd); + memset(&response, '\0', sizeof(response)); - - response.ret = 0; - response.eno = 0; - memcpy(&response.peer, &frame->src, sizeof(patty_ax25_addr)); memcpy(&response.path, &remote->path, sizeof(response.path)); @@ -1120,15 +1203,10 @@ static int handle_sabm(patty_ax25_server *server, goto error_write; } - fd_watch(server, remote->fd); - - return 0; + return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL); error_write: -error_reply_ua: -error_sock_delete_by_addr: -error_sock_save_by_addrpair: -error_sock_save_by_fd: +error_sock_save: patty_ax25_sock_destroy(remote); error_sock_new: @@ -1143,34 +1221,34 @@ static int handle_ua(patty_ax25_server *server, patty_ax25_sock *sock; patty_ax25_call_connect_response response; - if ((sock = sock_by_addrpair(server->socks_pending_connect, + if ((sock = sock_by_addrpair(server->socks_remote, &frame->dest, &frame->src)) == NULL) { return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); } - if ((client = client_by_sock(server, sock)) < 0) { - goto error_client_by_sock; + switch (sock->status) { + case PATTY_AX25_SOCK_PENDING_CONNECT: + break; + + case PATTY_AX25_SOCK_ESTABLISHED: + return sock_close(server, sock); + + default: + return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); } sock->status = PATTY_AX25_SOCK_ESTABLISHED; - if (sock->mode == PATTY_AX25_SOCK_DM) { - sock->mode = PATTY_AX25_SOCK_SABM; + if ((client = client_by_sock(server, sock)) < 0) { + goto error_client_by_sock; } - if (sock_save_by_addrpair(server->socks_established, - sock, - &sock->local, - &sock->remote) < 0) { - goto error_save_by_addrpair; + if (sock_save(server, client, sock) < 0) { + goto error_sock_save; } - if (sock_delete_by_addrpair(server->socks_pending_connect, - &sock->local, - &sock->remote) < 0) { - goto error_delete_by_addrpair; - } + fd_watch(server, sock->fd); response.ret = 0; response.eno = 0; @@ -1179,15 +1257,12 @@ static int handle_ua(patty_ax25_server *server, goto error_write; } - fd_watch(server, sock->fd); - return 0; error_write: +error_sock_save: patty_ax25_sock_destroy(sock); -error_delete_by_addrpair: -error_save_by_addrpair: error_client_by_sock: return -1; } @@ -1199,26 +1274,18 @@ static int handle_dm(patty_ax25_server *server, patty_ax25_sock *sock; patty_ax25_call_connect_response response; - if ((sock = sock_by_addrpair(server->socks_established, - &frame->dest, - &frame->src)) != NULL) { - return sock_close(server, sock); - } - - if ((sock = sock_by_addrpair(server->socks_pending_connect, + if ((sock = sock_by_addrpair(server->socks_remote, &frame->dest, &frame->src)) == NULL) { return 0; } - if ((client = client_by_sock(server, sock)) < 0) { - goto error_client_by_sock; + if (sock->status != PATTY_AX25_SOCK_PENDING_CONNECT) { + return 0; } - if (sock_delete_by_addrpair(server->socks_pending_connect, - &frame->dest, - &frame->src) < 0) { - goto error_delete_by_addrpair; + if ((client = client_by_sock(server, sock)) < 0) { + goto error_client_by_sock; } response.ret = -1; @@ -1233,7 +1300,6 @@ static int handle_dm(patty_ax25_server *server, return 0; error_write: -error_delete_by_addrpair: error_client_by_sock: return -1; } @@ -1269,25 +1335,19 @@ static int handle_disc(patty_ax25_server *server, patty_ax25_frame *frame) { patty_ax25_sock *sock; - if ((sock = sock_by_addrpair(server->socks_established, + if ((sock = sock_by_addrpair(server->socks_remote, &frame->dest, &frame->src)) == NULL) { - goto done; + return 0; } - if (sock_close(server, sock) < 0) { - goto error_sock_delete; + if (sock->status != PATTY_AX25_SOCK_ESTABLISHED) { + return frame->pf? reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL): 0; } -done: - if (frame->pf) { - return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); - } + (void)sock_close(server, sock); - return 0; - -error_sock_delete: - return -1; + return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL); } static int handle_rej(patty_ax25_server *server, @@ -1339,18 +1399,25 @@ static int handle_xid(patty_ax25_server *server, } /* - * First, check if this XID packet is for a pending outbound connection. + * First, check if this XID packet is a response to an XID used to initiate + * an outbound connection. */ - if ((remote = sock_by_addrpair(server->socks_pending_connect, + if ((remote = sock_by_addrpair(server->socks_remote, &frame->dest, &frame->src)) != NULL) { + if (remote->status != PATTY_AX25_SOCK_PENDING_CONNECT) { + goto reply_dm; + } + /* * Since we've received an XID packet, we can assume that the remote * station is capable of speaking AX.25 v2.2. Therefore, we should * upgrade the socket defaults accordingly, and negotiate downwards * as necessary. */ - patty_ax25_sock_upgrade(remote); + if (patty_ax25_sock_upgrade(remote) < 0) { + goto error_sock_upgrade; + } if (patty_ax25_sock_params_set(remote, ¶ms) < 0) { goto error_sock_params_set; @@ -1365,15 +1432,27 @@ static int handle_xid(patty_ax25_server *server, return patty_ax25_sock_send_sabme(remote, PATTY_AX25_FRAME_POLL); } else { + remote->mode = PATTY_AX25_SOCK_SABM; + return patty_ax25_sock_send_sabm(remote, PATTY_AX25_FRAME_POLL); } } /* - * Second, check if this XID packet is for a socket pending accept. + * Second, check if this XID packet is for a listening socket. */ - if ((local = sock_by_addr(server->socks_pending_accept, + if ((local = sock_by_addr(server->socks_local, &frame->dest)) != NULL) { + int client; + + if (local->status != PATTY_AX25_SOCK_LISTENING) { + goto reply_dm; + } + + if ((client = client_by_sock(server, local)) < 0) { + goto error_client_by_sock; + } + if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) { goto error_sock_new; } @@ -1394,18 +1473,21 @@ static int handle_xid(patty_ax25_server *server, save_reply_addr(remote, frame); - if (sock_save_by_fd(server->socks_by_fd, remote) < 0) { - goto error_sock_save_by_fd; + if (sock_save(server, client, remote) < 0) { + goto error_sock_save; } return patty_ax25_sock_send_xid(remote, PATTY_AX25_FRAME_RESPONSE); } +reply_dm: return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); -error_sock_save_by_fd: +error_sock_save: error_sock_new: +error_client_by_sock: error_sock_params_set: +error_sock_upgrade: error_io: return -1; } @@ -1428,7 +1510,7 @@ static int handle_frame(patty_ax25_server *server, offset += decoded; } - if ((sock = sock_by_addrpair(server->socks_established, + if ((sock = sock_by_addrpair(server->socks_remote, &frame.dest, &frame.src)) != NULL) { if (sock->mode == PATTY_AX25_SOCK_SABME) { @@ -1469,17 +1551,19 @@ error_io: static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) { int fd = patty_kiss_tnc_fd(iface->tnc); - void *buf; - ssize_t readlen; - if (!FD_ISSET(fd, &server->fds_r)) { goto done; } do { + void *buf; + ssize_t readlen; + if ((readlen = patty_ax25_if_recv(iface, &buf)) < 0) { goto error_io; } else if (readlen == 0) { + close(fd); + fd_clear(server, fd); goto done; @@ -1530,14 +1614,14 @@ static int handle_sock(uint32_t key, if ((len = read(sock->fd, sock->rx_buf, sock->n_maxlen_rx)) < 0) { if (errno == EIO) { - (void)sock_close(server, sock); + (void)sock_shutdown(server, sock); goto done; } goto error_io; } else if (len == 0) { - sock_close(server, sock); + (void)sock_shutdown(server, sock); goto done; } @@ -1555,7 +1639,7 @@ error_io: } static int handle_socks(patty_ax25_server *server) { - return patty_dict_each(server->socks_established, handle_sock, server); + return patty_dict_each(server->socks_by_fd, handle_sock, server); } int patty_ax25_server_run(patty_ax25_server *server) {