diff --git a/include/patty/dict.h b/include/patty/dict.h index 6dd3039..b040dda 100644 --- a/include/patty/dict.h +++ b/include/patty/dict.h @@ -47,9 +47,9 @@ void *patty_dict_set_with_hash(patty_dict *dict, void *patty_dict_set(patty_dict *dict, void *key, size_t keysz, void *value); -void *patty_dict_delete_with_hash(patty_dict *dict, void *key, size_t keysz); +int patty_dict_delete_with_hash(patty_dict *dict, uint32_t hash); -void *patty_dict_delete(patty_dict *dict, void *key, size_t keysz); +int patty_dict_delete(patty_dict *dict, void *key, size_t keysz); void patty_dict_destroy(patty_dict *dict); diff --git a/src/dict.c b/src/dict.c index 0d0bb3c..e5a71c2 100644 --- a/src/dict.c +++ b/src/dict.c @@ -174,21 +174,23 @@ void *patty_dict_set(patty_dict *dict, void *key, size_t keysz, void *value) { patty_hash(key, keysz)); } -void *patty_dict_delete(patty_dict *dict, void *key, size_t keysz) { +int patty_dict_delete_with_hash(patty_dict *dict, uint32_t hash) { patty_dict_slot *slot; - void *value; - - uint32_t hash = patty_hash(key, keysz); if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { - return NULL; + goto error_dict_slot_find; } - value = slot->value; - memset(slot, '\0', sizeof(*slot)); - return value; + return 0; + +error_dict_slot_find: + return -1; +} + +int patty_dict_delete(patty_dict *dict, void *key, size_t keysz) { + return patty_dict_delete_with_hash(dict, patty_hash(key, keysz)); } static int dict_item_release(void *key, size_t keysz, void *value, void *ctx) { diff --git a/src/server.c b/src/server.c index 7a880fd..4143b7c 100644 --- a/src/server.c +++ b/src/server.c @@ -14,7 +14,6 @@ struct _patty_ax25_server { patty_list *ifaces; patty_dict *socks_by_fd, - *socks_bound, *socks_pending_accept, *socks_pending_connect, *socks_established; @@ -37,10 +36,6 @@ int patty_ax25_server_init(patty_ax25_server *server) { goto error_dict_new_socks_by_fd; } - if ((server->socks_bound = patty_dict_new()) == NULL) { - goto error_dict_new_socks_bound; - } - if ((server->socks_pending_accept = patty_dict_new()) == NULL) { goto error_dict_new_socks_pending_accept; } @@ -62,9 +57,6 @@ error_dict_new_socks_pending_connect: patty_dict_destroy(server->socks_pending_accept); error_dict_new_socks_pending_accept: - patty_dict_destroy(server->socks_bound); - -error_dict_new_socks_bound: patty_dict_destroy(server->socks_by_fd); error_dict_new_socks_by_fd: @@ -84,7 +76,6 @@ void patty_ax25_server_stop(patty_ax25_server *server) { 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_bound); patty_dict_destroy(server->socks_by_fd); patty_ax25_server_each_if(server, destroy_if, NULL); @@ -127,20 +118,6 @@ static inline void hash_end(uint32_t *hash) { *hash += (*hash << 15); } -static uint32_t hash_addrpair(patty_ax25_addr *local, - patty_ax25_addr *remote) { - uint32_t hash; - - hash_init(&hash); - - hash_addr(&hash, local); - hash_addr(&hash, remote); - - hash_end(&hash); - - return hash; -} - static patty_ax25_sock *sock_by_fd(patty_dict *dict, int fd) { return patty_dict_get(dict, @@ -175,7 +152,12 @@ static patty_ax25_sock *sock_by_addrpair(patty_dict *dict, patty_ax25_addr *remote) { patty_dict_slot *slot; - uint32_t hash = hash_addrpair(local, remote); + uint32_t hash; + + hash_init(&hash); + hash_addr(&hash, local); + hash_addr(&hash, remote); + hash_end(&hash); if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { errno = EEXIST; @@ -230,7 +212,12 @@ 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); + uint32_t hash; + + hash_init(&hash); + hash_addr(&hash, local); + hash_addr(&hash, remote); + hash_end(&hash); if (patty_dict_set_with_hash(dict, sock, @@ -246,6 +233,47 @@ error_dict_set_with_hash: return -1; } +static int sock_delete(patty_ax25_server *server, + patty_ax25_sock *sock) { + uint32_t hash_established, + hash_pending_connect, + hash_pending_accept; + + hash_init(&hash_established); + hash_addr(&hash_established, &sock->local); + hash_addr(&hash_established, &sock->remote); + hash_end(&hash_established); + + if (patty_dict_delete_with_hash(server->socks_established, hash_established) < 0) { + goto error_dict_delete_established; + } + + hash_init(&hash_pending_connect); + hash_addr(&hash_pending_connect, &sock->local); + hash_end(&hash_pending_connect); + + if (patty_dict_delete_with_hash(server->socks_pending_connect, hash_pending_connect) < 0) { + goto error_dict_delete_pending_connect; + } + + hash_init(&hash_pending_accept); + hash_addr(&hash_pending_accept, &sock->local); + hash_end(&hash_pending_accept); + + if (patty_dict_delete(server->socks_by_fd, NULL + sock->fd, sizeof(sock->fd)) < 0) { + goto error_dict_delete_by_fd; + } + + free(sock); + + return 0; + +error_dict_delete_by_fd: +error_dict_delete_pending_connect: +error_dict_delete_established: + return -1; +} + int patty_ax25_server_add_if(patty_ax25_server *server, patty_ax25_if *iface) { int fd; @@ -299,7 +327,7 @@ int patty_ax25_server_delete_if(patty_ax25_server *server, server->fd_max--; } - if (patty_dict_delete(server->socks_by_fd, NULL + fd, sizeof(fd)) == NULL) { + if (patty_dict_delete(server->socks_by_fd, NULL + fd, sizeof(fd)) < 0) { goto error_dict_delete; } } @@ -424,48 +452,31 @@ static int server_bind(patty_ax25_server *server, goto error_sock_by_fd; } - /* - * If there is already a local address associated with this socket, then - * that's a problem. - */ - if (sock->local.callsign[0] != '\0') { - response.ret = -1; - response.eno = EINVAL; + switch (sock->status) { + case PATTY_AX25_SOCK_LISTENING: + case PATTY_AX25_SOCK_ESTABLISHED: + response.ret = -1; + response.eno = EINVAL; - goto error_bound; - } + goto error_invalid_status; - if (patty_dict_get(server->socks_bound, - &sock->local, - sizeof(sock->local))) { - response.ret = -1; - response.eno = EADDRINUSE; - - goto error_inuse; + default: + break; } memcpy(&sock->local, &request.peer, sizeof(request.peer)); - if (patty_dict_set(server->socks_bound, - &sock->local, - sizeof(sock->local), - sock) == NULL) { - goto error_dict_set; - } + response.ret = 0; + response.eno = 0; +error_invalid_status: +error_sock_by_fd: if (write(client, &response, sizeof(response)) < 0) { goto error_io; } - response.ret = 0; - response.eno = 0; - -error_inuse: -error_bound: -error_sock_by_fd: return 0; -error_dict_set: error_io: return -1; } @@ -530,6 +541,8 @@ static int server_accept_pty(patty_ax25_server *server, goto error_ptsname_r; } + sock->type |= PATTY_AX25_SOCK_PTY; + response->ret = sock->fd; response->eno = 0; @@ -565,6 +578,8 @@ static int server_accept_unix(patty_ax25_server *server, goto error_bind; } + sock->type |= PATTY_AX25_SOCK_UNIX; + response->ret = sock->fd; response->eno = 0; @@ -603,6 +618,8 @@ static int server_accept(patty_ax25_server *server, sock_init(remote, local->type); + memcpy(&remote->local, &local->local, sizeof(remote->local)); + if (local->type & PATTY_AX25_SOCK_PTY) { if (server_accept_pty(server, &response, remote) < 0) { goto error_server_accept_pty; @@ -613,6 +630,18 @@ static int server_accept(patty_ax25_server *server, } } + if (sock_save_by_addr(server->socks_pending_accept, + remote, + &local->local) < 0) { + goto error_save_by_addr; + } + + if (sock_save_by_fd(server->socks_by_fd, remote) < 0) { + goto error_save_by_fd; + } + + return 0; + error_sock_by_fd: if (write(client, &response, sizeof(response)) < 0) { goto error_io; @@ -620,6 +649,8 @@ error_sock_by_fd: return 0; +error_save_by_fd: +error_save_by_addr: error_server_accept_unix: error_server_accept_pty: free(remote); @@ -647,23 +678,40 @@ static int server_connect(patty_ax25_server *server, goto error_sock_by_fd; } - if (sock->remote.callsign[0] != '\0') { - response.ret = -1; - response.eno = EEXIST; + switch (sock->status) { + case PATTY_AX25_SOCK_LISTENING: + response.ret = -1; + response.eno = EINVAL; - goto error_exists; + goto error_invalid_status; + + break; + + case PATTY_AX25_SOCK_ESTABLISHED: + response.ret = -1; + response.eno = EISCONN; + + goto error_invalid_status; + + break; + + default: + break; } memcpy(&sock->remote, &request.peer, sizeof(request.peer)); - if (sock_save_by_addrpair(server->socks_established, + if (sock_save_by_addrpair(server->socks_pending_connect, sock, &sock->local, &sock->remote) < 0) { goto error_sock_save_by_addrpair; } -error_exists: + response.ret = 0; + response.eno = 0; + +error_invalid_status: error_sock_by_fd: if (write(client, &response, sizeof(response)) < 0) { goto error_io; @@ -676,3 +724,50 @@ error_io: return -1; } +static int server_close(patty_ax25_server *server, + int client) { + patty_ax25_call_close_request request; + patty_ax25_call_close_response response; + + patty_ax25_sock *sock; + + if (read(client, &request, sizeof(request)) < 0) { + goto error_io; + } + + if ((sock = sock_by_fd(server->socks_by_fd, request.socket)) == NULL) { + response.ret = -1; + response.eno = EBADF; + + goto error_sock_by_fd; + } + + if (sock_delete(server, sock) < 0) { + response.ret = -1; + response.eno = EBADF; + + goto error_sock_delete; + } + + if (close(request.socket) < 0) { + response.ret = -1; + response.eno = errno; + + goto error_close; + } + + response.ret = 0; + response.eno = 0; + +error_close: +error_sock_delete: +error_sock_by_fd: + if (write(client, &response, sizeof(response)) < 0) { + goto error_io; + } + + return 0; + +error_io: + return -1; +}