diff --git a/include/patty/ax25.h b/include/patty/ax25.h index 24d4429..2c088f6 100644 --- a/include/patty/ax25.h +++ b/include/patty/ax25.h @@ -18,12 +18,12 @@ typedef struct _patty_ax25_addr { #pragma pack(pop) -typedef struct _patty_ax25 patty_ax25; typedef struct _patty_ax25_if patty_ax25_if; #include #include #include +#include #include #define PATTY_AX25_ADDRESS_SIZE 7 @@ -43,7 +43,8 @@ enum patty_ax25_sock_mode { }; enum patty_ax25_sock_opts { - PATTY_AX25_SOCK_NONBLOCK = 1 << 0 + PATTY_AX25_SOCK_NONBLOCK = 1 << 0, + PATTY_AX25_SOCK_PTY = 1 << 1 }; typedef struct _patty_ax25_sock { @@ -73,24 +74,6 @@ typedef struct _patty_ax25_sock { unsigned int hops; } patty_ax25_sock; -typedef struct _patty_ax25 { - patty_list *ifaces; - - patty_dict *socks, - *socks_by_addrpair; - - int fd, - fdmax; - - fd_set fds, - fds_r, - fds_w; -} patty_ax25; - -int patty_ax25_init(patty_ax25 *ax25); - -void patty_ax25_stop(patty_ax25 *ax25); - int patty_ax25_pton(const char *callsign, uint8_t ssid, patty_ax25_addr *addr); @@ -100,50 +83,39 @@ int patty_ax25_ntop(const patty_ax25_addr *addr, uint8_t *ssid, size_t len); -int patty_ax25_open(patty_ax25 *ax25, const char *ifname); +int patty_ax25_open(int server, + const char *ifname); -int patty_ax25_socket(patty_ax25 *ax25); +int patty_ax25_socket(int server, + int sockopts); -int patty_ax25_bind(patty_ax25 *ax25, +int patty_ax25_bind(int server, int socket, patty_ax25_addr *addr); -int patty_ax25_listen(patty_ax25 *ax25, +int patty_ax25_listen(int server, int socket); -int patty_ax25_accept(patty_ax25 *ax25, +int patty_ax25_accept(int server, int socket); -int patty_ax25_connect(patty_ax25 *ax25, +int patty_ax25_connect(int server, int socket, patty_ax25_addr *addr); -int patty_ax25_close(patty_ax25 *ax25, +int patty_ax25_close(int server, int socket); -/*int patty_ax25_next_event(patty_ax25 *ax25, - patty_ax25_event *ev);*/ - -ssize_t patty_ax25_sendto(patty_ax25 *ax25, +ssize_t patty_ax25_sendto(int server, int socket, const void *buf, size_t len, patty_ax25_addr *addr); -int patty_ax25_recvfrom(patty_ax25 *ax25, +int patty_ax25_recvfrom(int server, int socket, void *buf, size_t len, patty_ax25_addr *addr); -ssize_t patty_ax25_read(patty_ax25 *ax25, - int socket, - void *buf, - size_t len); - -ssize_t patty_ax25_write(patty_ax25 *ax25, - int socket, - const void *buf, - size_t len); - #endif /* _PATTY_AX25_H */ diff --git a/include/patty/ax25/client.h b/include/patty/ax25/client.h new file mode 100644 index 0000000..ce42ba3 --- /dev/null +++ b/include/patty/ax25/client.h @@ -0,0 +1,21 @@ +#ifndef _PATTY_AX25_CLIENT_H +#define _PATTY_AX25_CLIENT_H + +enum patty_ax25_client_call { + PATTY_AX25_CLIENT_UNKNOWN, + PATTY_AX25_CLIENT_SOCKET, + PATTY_AX25_CLIENT_BIND, + PATTY_AX25_CLIENT_LISTEN, + PATTY_AX25_CLIENT_ACCEPT, + PATTY_AX25_CLIENT_CONNECT, + PATTY_AX25_CLIENT_CLOSE, + PATTY_AX25_CLIENT_SENDTO, + PATTY_AX25_CLIENT_RECVFROM +}; + +ssize_t patty_ax25_client_send(int fd, + enum patty_ax25_client_call call, + void *data, + size_t len); + +#endif /* _PATTY_AX25_CLIENT_H */ diff --git a/include/patty/ax25/if.h b/include/patty/ax25/if.h index fa18a3c..9ea9d1d 100644 --- a/include/patty/ax25/if.h +++ b/include/patty/ax25/if.h @@ -48,13 +48,17 @@ int patty_ax25_if_add_addr(patty_ax25_if *iface, int patty_ax25_if_delete_addr(patty_ax25_if *iface, const char *callsign, uint8_t ssid); -patty_ax25_if *patty_ax25_get_if(patty_ax25 *ax25, const char *name); +patty_ax25_if *patty_ax25_get_if(patty_ax25_server *server, + const char *name); -int patty_ax25_if_each(patty_ax25 *ax25, - int (*callback)(patty_ax25_if *, void *), void *ctx); +int patty_ax25_if_each(patty_ax25_server *server, + int (*callback)(patty_ax25_if *, void *), + void *ctx); -int patty_ax25_add_if(patty_ax25 *ax25, patty_ax25_if *iface); +int patty_ax25_add_if(patty_ax25_server *server, + patty_ax25_if *iface); -int patty_ax25_delete_if(patty_ax25 *ax25, patty_ax25_if *iface); +int patty_ax25_delete_if(patty_ax25_server *server, + patty_ax25_if *iface); #endif /* _PATTY_AX25_IF_H */ diff --git a/include/patty/ax25/mux.h b/include/patty/ax25/mux.h deleted file mode 100644 index a2a92ca..0000000 --- a/include/patty/ax25/mux.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _PATTY_AX25_MUX_H -#define _PATTY_AX25_MUX_H - -enum patty_ax25_mux_data_type { - PATTY_AX25_MUX_VOID, - PATTY_AX25_MUX_INT, - PATTY_AX25_MUX_SSIZE_T, - PATTY_AX25_MUX_ADDR -}; - -enum patty_ax25_mux_request_type { - PATTY_AX25_MUX_UNKNOWN, - PATTY_AX25_MUX_SOCKET, - PATTY_AX25_MUX_BIND, - PATTY_AX25_MUX_LISTEN, - PATTY_AX25_MUX_ACCEPT, - PATTY_AX25_MUX_CONNECT, - PATTY_AX25_MUX_CLOSE, - PATTY_AX25_MUX_SENDTO, - PATTY_AX25_MUX_RECVFROM -}; - -ssize_t patty_ax25_mux_send(int fd, - enum patty_ax25_mux_request_type type, - void *data, - size_t len); - -ssize_t patty_ax25_mux_recv(int fd, - enum patty_ax25_mux_response_type *type, - void *data, - size_t len); - -#endif /* _PATTY_AX25_MUX_H */ diff --git a/include/patty/ax25/server.h b/include/patty/ax25/server.h new file mode 100644 index 0000000..50c7fa0 --- /dev/null +++ b/include/patty/ax25/server.h @@ -0,0 +1,24 @@ +#ifndef _PATTY_AX25_SERVER_H +#define _PATTY_AX25_SERVER_H + +typedef struct _patty_ax25_server { + patty_list *ifaces; + + patty_dict *socks, + *socks_by_addrpair; + + int fd, + fd_max; + + fd_set fds, + fds_r, + fds_w; +} patty_ax25_server; + +int patty_ax25_server_init(patty_ax25_server *server); + +void patty_ax25_server_stop(patty_ax25_server *server); + +int patty_ax25_server_run(patty_ax25_server *server); + +#endif /* _PATTY_AX25_SERVER_H */ diff --git a/src/Makefile b/src/Makefile index 3d50136..d1a0089 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,12 +8,12 @@ CFLAGS = $(CGFLAGS) -fPIC -Wall -O2 -I$(INCLUDE_PATH) LDFLAGS = HEADERS = kiss.h ax25.h ax25/if.h ax25/macros.h ax25/proto.h \ - ax25/frame.h list.h hash.h dict.h + ax25/frame.h ax25/server.h list.h hash.h dict.h OBJS = kiss.o ax25.o if.o frame.o \ - list.o hash.o dict.o + server.o list.o hash.o dict.o -EXAMPLES = iflist decode ptmx +EXAMPLES = decode ptmx HEADERS_BUILD = $(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/, $(HEADERS)) diff --git a/src/ax25.c b/src/ax25.c index a536177..9eb4e0b 100644 --- a/src/ax25.c +++ b/src/ax25.c @@ -5,184 +5,17 @@ #include -int patty_ax25_init(patty_ax25 *ax25) { - memset(ax25, '\0', sizeof(*ax25)); - - if ((ax25->ifaces = patty_list_new()) == NULL) { - goto error_list_new_ifaces; - } - - if ((ax25->socks = patty_dict_new()) == NULL) { - goto error_dict_new_socks; - } - - if ((ax25->socks_by_addrpair = patty_dict_new()) == NULL) { - goto error_dict_new_socks_by_addrpair; - } - - return 0; - -error_dict_new_socks_by_addrpair: - patty_dict_destroy(ax25->socks); - -error_dict_new_socks: - patty_list_destroy(ax25->ifaces); - -error_list_new_ifaces: - return -1; -} - -static int destroy_if(patty_ax25_if *iface, void *ctx) { - patty_ax25_if_destroy(iface); - - return 0; -} - -void patty_ax25_stop(patty_ax25 *ax25) { - patty_dict_destroy(ax25->socks_by_addrpair); - patty_dict_destroy(ax25->socks); - - patty_ax25_if_each(ax25, destroy_if, NULL); - patty_list_destroy(ax25->ifaces); -} - -static patty_ax25_sock *sock_by_fd(patty_ax25 *ax25, int fd) { - patty_ax25_sock *sock; - - if ((sock = patty_dict_get(ax25->socks, &fd, sizeof(fd))) == NULL) { - errno = EBADF; - - goto error_dict_get; - } - - return sock; - -error_dict_get: - return NULL; -} - -static inline void hash_init(uint32_t *hash) { - *hash = 0xffffffdf; -} - -static inline void hash_byte(uint32_t *hash, uint8_t c) { - *hash += c; - *hash += (*hash << 10); - *hash ^= (*hash >> 6); -} - -static inline void hash_addr(uint32_t *hash, patty_ax25_addr *addr) { - int i; - - for (i=0; icallsign[i] >> 1); - } - - hash_byte(hash, PATTY_AX25_ADDRESS_SSID_NUMBER(addr->ssid)); -} - -static inline void hash_end(uint32_t *hash) { - *hash += (*hash << 3); - *hash ^= (*hash >> 11); - *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_get_fd(patty_ax25 *ax25, - int fd) { - return patty_dict_get(ax25->socks, - NULL + fd, - sizeof(fd)); -} - -static patty_ax25_sock *sock_get_addrpair(patty_ax25 *ax25, - patty_ax25_addr *local, - patty_ax25_addr *remote) { - patty_dict_slot *slot; - - uint32_t hash = hash_addrpair(local, remote); - - if ((slot = patty_dict_slot_find(ax25->socks_by_addrpair, hash)) == NULL) { - errno = EBADF; - - goto error_dict_slot_find; - } - - return (patty_ax25_sock *)slot->value; - -error_dict_slot_find: - return NULL; -} - -static int sock_save(patty_ax25 *ax25, patty_ax25_sock *sock) { - uint32_t hash = hash_addrpair(&sock->local, &sock->remote); - - if (patty_dict_set(ax25->socks, - NULL + sock->fd, - sizeof(sock->fd), - sock) == NULL) { - goto error_dict_set; - } - - if (patty_dict_set_with_hash(ax25->socks_by_addrpair, - NULL + sock->fd, - sizeof(sock->fd), - sock, - hash) == NULL) { - goto error_dict_set; - } - - return sock->fd; - -error_dict_set: - return -1; -} - -static void sock_init(patty_ax25_sock *sock) { - memset(sock, '\0', sizeof(*sock)); - - sock->status = PATTY_AX25_SOCK_OPEN; - sock->mode = PATTY_AX25_SOCK_DM; - sock->n_maxlen = PATTY_AX25_FRAME_DEFAULT_MAXLEN; - sock->n_window = PATTY_AX25_FRAME_DEFAULT_WINDOW; -} - -int patty_ax25_socket(patty_ax25 *ax25) { - patty_ax25_sock *sock; - - if ((sock = malloc(sizeof(*sock))) == NULL) { - goto error_malloc_sock; - } - - sock_init(sock); - - sock->fd = ax25->fd++; - - if (sock_save(ax25, sock) < 0) { - goto error_sock_save; - } - - return sock->fd; - -error_sock_save: - free(sock); - -error_malloc_sock: - return -1; -} +enum remote_call { + PATTY_AX25_UNKNOWN, + PATTY_AX25_SOCKET, + PATTY_AX25_BIND, + PATTY_AX25_LISTEN, + PATTY_AX25_ACCEPT, + PATTY_AX25_CONNECT, + PATTY_AX25_CLOSE, + PATTY_AX25_SENDTO, + PATTY_AX25_RECVFROM +}; int patty_ax25_pton(const char *callsign, uint8_t ssid, @@ -269,106 +102,3 @@ int patty_ax25_ntop(const patty_ax25_addr *addr, error_invalid_args: return -1; } - -int patty_ax25_open(patty_ax25 *ax25, const char *ifname) { - patty_ax25_sock *sock; - - if ((sock = malloc(sizeof(*sock))) == NULL) { - goto error_malloc_sock; - } - - sock_init(sock); - - if ((sock->iface = patty_ax25_get_if(ax25, ifname)) == NULL) { - goto error_get_if; - } - - return sock_save(ax25, sock); - -error_get_if: - free(sock); - -error_malloc_sock: - return -1; -} - -int patty_ax25_bind(patty_ax25 *ax25, - int socket, - patty_ax25_addr *addr) { - patty_ax25_sock *sock; - - if ((sock = sock_get_fd(ax25, socket)) == NULL) { - goto error_sock_get_fd; - } - - /* - * If there is already a local address associated with this socket, then - * that's a problem. - */ - if (sock->local.callsign[0] != '\0') { - errno = EADDRINUSE; - - goto error_exists; - } - - memcpy(&sock->local, addr, sizeof(*addr)); - - return 0; - -error_exists: -error_sock_get_fd: - return -1; -} - -int patty_ax25_listen(patty_ax25 *ax25, - int socket) { - patty_ax25_sock *sock; - - if ((sock = sock_get_fd(ax25, socket)) == NULL) { - errno = EBADF; - - goto error_sock_get_fd; - } - - if (sock->local.callsign[0] == '\0') { - errno = EINVAL; - - goto error_invalid_fd; - } - - errno = ENOSYS; - -error_invalid_fd: -error_sock_get_fd: - return -1; -} - -int patty_ax25_connect(patty_ax25 *ax25, - int socket, - patty_ax25_addr *addr) { - patty_ax25_sock *sock; - - if ((sock = sock_get_fd(ax25, socket)) == NULL) { - goto error_sock_get_fd; - } - - if (sock->remote.callsign[0] != '\0') { - errno = EEXIST; - - goto error_exists; - } - - memcpy(&sock->remote, addr, sizeof(*addr)); - - return 0; - -error_exists: -error_sock_get_fd: - return -1; -} - -int patty_ax25_accept(patty_ax25 *ax25, int socket) { - errno = ENOSYS; - - return -1; -} diff --git a/src/if.c b/src/if.c index 1894150..f86a25a 100644 --- a/src/if.c +++ b/src/if.c @@ -221,11 +221,12 @@ error_ntop: return -1; } -patty_ax25_if *patty_ax25_get_if(patty_ax25 *ax25, const char *name) { +patty_ax25_if *patty_ax25_get_if(patty_ax25_server *server, + const char *name) { patty_list_iterator *iter; patty_ax25_if *iface; - if ((iter = patty_list_start(ax25->ifaces)) == NULL) { + if ((iter = patty_list_start(server->ifaces)) == NULL) { goto error_list_start; } @@ -243,11 +244,13 @@ error_list_start: return NULL; } -int patty_ax25_if_each(patty_ax25 *ax25, int (*callback)(patty_ax25_if *, void *), void *ctx) { +int patty_ax25_if_each(patty_ax25_server *server, + int (*callback)(patty_ax25_if *, void *), + void *ctx) { patty_list_iterator *iter; patty_ax25_if *iface; - if ((iter = patty_list_start(ax25->ifaces)) == NULL) { + if ((iter = patty_list_start(server->ifaces)) == NULL) { goto error_list_start; } @@ -268,22 +271,23 @@ error_list_start: return -1; } -int patty_ax25_add_if(patty_ax25 *ax25, patty_ax25_if *iface) { +int patty_ax25_add_if(patty_ax25_server *server, + patty_ax25_if *iface) { int fd; if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { - FD_SET(fd, &ax25->fds); + FD_SET(fd, &server->fds); - if (ax25->fdmax < fd + 1) { - ax25->fdmax = fd + 1; + if (server->fd_max < fd + 1) { + server->fd_max = fd + 1; } } - if (patty_dict_set(ax25->socks, NULL + fd, sizeof(fd), iface) == NULL) { + if (patty_dict_set(server->socks, NULL + fd, sizeof(fd), iface) == NULL) { goto error_dict_set; } - if (patty_list_append(ax25->ifaces, iface) == NULL) { + if (patty_list_append(server->ifaces, iface) == NULL) { goto error_list_append; } @@ -294,14 +298,15 @@ error_dict_set: return -1; } -int patty_ax25_delete_if(patty_ax25 *ax25, patty_ax25_if *iface) { - patty_list_item *item = ax25->ifaces->first; +int patty_ax25_delete_if(patty_ax25_server *server, + patty_ax25_if *iface) { + patty_list_item *item = server->ifaces->first; int fd, i = 0; while (item) { if (item->value == iface) { - if (patty_list_splice(ax25->ifaces, i) == NULL) { + if (patty_list_splice(server->ifaces, i) == NULL) { goto error_list_splice; } @@ -313,13 +318,13 @@ int patty_ax25_delete_if(patty_ax25 *ax25, patty_ax25_if *iface) { } if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { - FD_CLR(fd, &ax25->fds); + FD_CLR(fd, &server->fds); - if (ax25->fdmax == fd) { - ax25->fdmax--; + if (server->fd_max == fd) { + server->fd_max--; } - if (patty_dict_delete(ax25->socks, NULL + fd, sizeof(fd)) == NULL) { + if (patty_dict_delete(server->socks, NULL + fd, sizeof(fd)) == NULL) { goto error_dict_delete; } } diff --git a/src/iflist.c b/src/iflist.c deleted file mode 100644 index 917774f..0000000 --- a/src/iflist.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - -static void usage(int argc, char **argv, const char *message, ...) { - if (message) { - va_list args; - - va_start(args, message); - vfprintf(stderr, message, args); - fprintf(stderr, "\n"); - va_end(args); - } - - fprintf(stderr, "usage: %s device\n", argv[0]); - - exit(1); -} - -int addr_callback(char *callsign, uint8_t ssid, void *ctx) { - return printf(" %s/%d\n", callsign, ssid); -} - -int iface_callback(patty_ax25_if *iface, void *ctx) { - printf("%s:\n", iface->name); - - return patty_ax25_if_each_addr(iface, addr_callback, ctx); -} - -int main(int argc, char **argv) { - patty_ax25 ax25; - patty_ax25_if *iface; - - if (argc < 2) { - usage(argc, argv, "No TNC device provided"); - } else if (argc > 2) { - usage(argc, argv, NULL); - } - - if (patty_ax25_init(&ax25) < 0) { - perror("Unable to initialize AX.25 stack"); - - exit(127); - } - - if ((iface = patty_ax25_if_create(PATTY_AX25_IF_KISS_TNC, argv[1])) == NULL) { - perror("Unable to create interface"); - - exit(127); - } - - if (patty_ax25_if_add_addr(iface, "WX3RKR", 0) < 0) { - perror("Unable to add address"); - - exit(127); - } - - if (patty_ax25_add_if(&ax25, iface) < 0) { - perror("Unable to add interface"); - - exit(127); - } - - patty_ax25_if_each(&ax25, iface_callback, NULL); - - patty_ax25_stop(&ax25); - - return 0; -} diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..8793f18 --- /dev/null +++ b/src/server.c @@ -0,0 +1,386 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int patty_ax25_server_init(patty_ax25_server *server) { + memset(server, '\0', sizeof(*server)); + + if ((server->ifaces = patty_list_new()) == NULL) { + goto error_list_new_ifaces; + } + + if ((server->socks = patty_dict_new()) == NULL) { + goto error_dict_new_socks; + } + + if ((server->socks_by_addrpair = patty_dict_new()) == NULL) { + goto error_dict_new_socks_by_addrpair; + } + + return 0; + +error_dict_new_socks_by_addrpair: + patty_dict_destroy(server->socks); + +error_dict_new_socks: + patty_list_destroy(server->ifaces); + +error_list_new_ifaces: + return -1; +} + +static int destroy_if(patty_ax25_if *iface, void *ctx) { + patty_ax25_if_destroy(iface); + + return 0; +} + +void patty_ax25_server_stop(patty_ax25_server *server) { + patty_dict_destroy(server->socks_by_addrpair); + patty_dict_destroy(server->socks); + + patty_ax25_if_each(server, destroy_if, NULL); + patty_list_destroy(server->ifaces); +} + +static void sock_init(patty_ax25_sock *sock) { + memset(sock, '\0', sizeof(*sock)); + + sock->status = PATTY_AX25_SOCK_OPEN; + sock->mode = PATTY_AX25_SOCK_DM; + sock->n_maxlen = PATTY_AX25_FRAME_DEFAULT_MAXLEN; + sock->n_window = PATTY_AX25_FRAME_DEFAULT_WINDOW; +} + +static inline void hash_init(uint32_t *hash) { + *hash = 0xffffffdf; +} + +static inline void hash_byte(uint32_t *hash, uint8_t c) { + *hash += c; + *hash += (*hash << 10); + *hash ^= (*hash >> 6); +} + +static inline void hash_addr(uint32_t *hash, patty_ax25_addr *addr) { + int i; + + for (i=0; icallsign[i] >> 1); + } + + hash_byte(hash, PATTY_AX25_ADDRESS_SSID_NUMBER(addr->ssid)); +} + +static inline void hash_end(uint32_t *hash) { + *hash += (*hash << 3); + *hash ^= (*hash >> 11); + *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 int sock_save(patty_ax25_server *server, patty_ax25_sock *sock) { + uint32_t hash = hash_addrpair(&sock->local, &sock->remote); + + if (patty_dict_set(server->socks, + NULL + sock->fd, + sizeof(sock->fd), + sock) == NULL) { + goto error_dict_set; + } + + if (patty_dict_set_with_hash(server->socks_by_addrpair, + NULL + sock->fd, + sizeof(sock->fd), + sock, + hash) == NULL) { + goto error_dict_set; + } + + return sock->fd; + +error_dict_set: + return -1; +} + +static int server_open(patty_ax25_server *server, const char *ifname) { + patty_ax25_sock *sock; + + if ((sock = malloc(sizeof(*sock))) == NULL) { + goto error_malloc_sock; + } + + sock_init(sock); + + if ((sock->iface = patty_ax25_get_if(server, ifname)) == NULL) { + goto error_get_if; + } + + return sock_save(server, sock); + +error_get_if: + free(sock); + +error_malloc_sock: + return -1; +} + +static patty_ax25_sock *sock_by_fd(patty_ax25_server *server, int fd) { + patty_ax25_sock *sock; + + if ((sock = patty_dict_get(server->socks, &fd, sizeof(fd))) == NULL) { + errno = EBADF; + + goto error_dict_get; + } + + return sock; + +error_dict_get: + return NULL; +} + +static patty_ax25_sock *sock_get_fd(patty_ax25_server *server, + int fd) { + return patty_dict_get(server->socks, + NULL + fd, + sizeof(fd)); +} + +static patty_ax25_sock *sock_get_addrpair(patty_ax25_server *server, + patty_ax25_addr *local, + patty_ax25_addr *remote) { + patty_dict_slot *slot; + + uint32_t hash = hash_addrpair(local, remote); + + if ((slot = patty_dict_slot_find(server->socks_by_addrpair, hash)) == NULL) { + errno = EBADF; + + goto error_dict_slot_find; + } + + return (patty_ax25_sock *)slot->value; + +error_dict_slot_find: + return NULL; +} + +static int server_socket_pty(patty_ax25_server *server, + patty_ax25_sock *sock, + int client) { + int fd; + char name[64]; + size_t len; + + if ((fd = open("/dev/ptmx", O_RDWR)) < 0) { + goto error_open; + } + + if (grantpt(fd) < 0) { + goto error_grantpt; + } + + if (unlockpt(fd) < 0) { + goto error_unlockpt; + } + + if (ptsname_r(fd, name, sizeof(name)) < 0) { + goto error_ptsname_r; + } + + len = strnlen(name, sizeof(name) - 1); + + if (write(client, name, sizeof(len)) < 0) { + goto error_write; + } + + if (write(client, name, len) < 0) { + goto error_write; + } + + return sock->fd = fd; + +error_write: +error_ptsname_r: +error_unlockpt: +error_grantpt: + close(fd); + +error_open: + return -1; +} + +static int server_socket_unix(patty_ax25_server *server, + patty_ax25_sock *sock, + int client) { + int fd; + char name[256]; + size_t len; + + struct sockaddr_un addr; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + goto error_socket; + } + + if (snprintf(name, sizeof(name), "/var/run/patty/%d.sock", fd) < 0) { + goto error_snprintf_name; + } + + len = strnlen(name, sizeof(name)); + + addr.sun_family = AF_UNIX; + + memset(&addr, 0, sizeof(addr)); + strncpy(addr.sun_path, name, sizeof(addr.sun_path)); + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + goto error_bind; + } + + if (write(client, &len, sizeof(len)) < 0) { + goto error_write; + } + + if (write(client, name, len) < 0) { + goto error_write; + } + + return sock->fd = fd; + +error_write: +error_bind: +error_snprintf_name: + close(fd); + +error_socket: + return -1; +} + +static int server_socket(patty_ax25_server *server, + int client, + int sockopts) { + patty_ax25_sock *sock; + + if ((sock = malloc(sizeof(*sock))) == NULL) { + goto error_malloc_sock; + } + + sock_init(sock); + + if (sockopts & PATTY_AX25_SOCK_PTY) { + if (server_socket_pty(server, sock, client) < 0) { + goto error; + } + } + + return sock->fd; + +error: + free(sock); + +error_malloc_sock: + return -1; +} + +static int server_bind(patty_ax25_server *server, + int socket, + patty_ax25_addr *addr) { + patty_ax25_sock *sock; + + if ((sock = sock_get_fd(server, socket)) == NULL) { + goto error_sock_get_fd; + } + + /* + * If there is already a local address associated with this socket, then + * that's a problem. + */ + if (sock->local.callsign[0] != '\0') { + errno = EADDRINUSE; + + goto error_exists; + } + + memcpy(&sock->local, addr, sizeof(*addr)); + + return 0; + +error_exists: +error_sock_get_fd: + return -1; +} + +static int server_listen(patty_ax25_server *server, + int socket) { + patty_ax25_sock *sock; + + if ((sock = sock_get_fd(server, socket)) == NULL) { + errno = EBADF; + + goto error_sock_get_fd; + } + + if (sock->local.callsign[0] == '\0') { + errno = EINVAL; + + goto error_invalid_fd; + } + + errno = ENOSYS; + +error_invalid_fd: +error_sock_get_fd: + return -1; +} + +static int server_connect(patty_ax25_server *server, + int socket, + patty_ax25_addr *addr) { + patty_ax25_sock *sock; + + if ((sock = sock_get_fd(server, socket)) == NULL) { + goto error_sock_get_fd; + } + + if (sock->remote.callsign[0] != '\0') { + errno = EEXIST; + + goto error_exists; + } + + memcpy(&sock->remote, addr, sizeof(*addr)); + + return 0; + +error_exists: +error_sock_get_fd: + return -1; +} + +static int server_accept(patty_ax25_server *server, int socket) { + errno = ENOSYS; + + return -1; +}