diff --git a/include/patty/ax25.h b/include/patty/ax25.h index 2c088f6..1bdc752 100644 --- a/include/patty/ax25.h +++ b/include/patty/ax25.h @@ -8,6 +8,11 @@ #include #include +#define PATTY_AX25_ADDRESS_SIZE 7 +#define PATTY_AX25_CALLSIGN_LEN 6 +#define PATTY_AX25_IF_NAME_SIZE 8 +#define PATTY_AX25_SOCK_PATH_SIZE 256 + #pragma pack(push) #pragma pack(1) @@ -24,14 +29,11 @@ typedef struct _patty_ax25_if patty_ax25_if; #include #include #include +#include #include -#define PATTY_AX25_ADDRESS_SIZE 7 -#define PATTY_AX25_CALLSIGN_LEN 6 - enum patty_ax25_sock_status { PATTY_AX25_SOCK_CLOSED, - PATTY_AX25_SOCK_OPEN, PATTY_AX25_SOCK_LISTENING, PATTY_AX25_SOCK_ESTABLISHED }; @@ -42,15 +44,18 @@ enum patty_ax25_sock_mode { PATTY_AX25_SOCK_SABME }; -enum patty_ax25_sock_opts { - PATTY_AX25_SOCK_NONBLOCK = 1 << 0, - PATTY_AX25_SOCK_PTY = 1 << 1 +enum patty_ax25_sock_type { + PATTY_AX25_SOCK_NONE, + PATTY_AX25_SOCK_UNIX = 1 << 0, + PATTY_AX25_SOCK_PTY = 1 << 1, + PATTY_AX25_SOCK_RAW = 1 << 2, + PATTY_AX25_SOCK_NONBLOCK = 1 << 3 }; typedef struct _patty_ax25_sock { enum patty_ax25_sock_status status; enum patty_ax25_sock_mode mode; - enum patty_ax25_sock_opts opts; + enum patty_ax25_sock_type type; time_t timer_ack, timer_response, @@ -64,6 +69,7 @@ typedef struct _patty_ax25_sock { seq_recv; int fd; + char path[PATTY_AX25_SOCK_PATH_SIZE]; patty_ax25_if *iface; @@ -83,39 +89,4 @@ int patty_ax25_ntop(const patty_ax25_addr *addr, uint8_t *ssid, size_t len); -int patty_ax25_open(int server, - const char *ifname); - -int patty_ax25_socket(int server, - int sockopts); - -int patty_ax25_bind(int server, - int socket, - patty_ax25_addr *addr); - -int patty_ax25_listen(int server, - int socket); - -int patty_ax25_accept(int server, - int socket); - -int patty_ax25_connect(int server, - int socket, - patty_ax25_addr *addr); - -int patty_ax25_close(int server, - int socket); - -ssize_t patty_ax25_sendto(int server, - int socket, - const void *buf, - size_t len, - patty_ax25_addr *addr); - -int patty_ax25_recvfrom(int server, - int socket, - void *buf, - size_t len, - patty_ax25_addr *addr); - #endif /* _PATTY_AX25_H */ diff --git a/include/patty/ax25/call.h b/include/patty/ax25/call.h new file mode 100644 index 0000000..cb8618f --- /dev/null +++ b/include/patty/ax25/call.h @@ -0,0 +1,134 @@ +#ifndef _PATTY_AX25_CALL_H +#define _PATTY_AX25_CALL_H + +enum patty_ax25_call { + PATTY_AX25_CALL_UNKNOWN, + PATTY_AX25_CALL_SOCKET, + PATTY_AX25_CALL_BIND, + PATTY_AX25_CALL_LISTEN, + PATTY_AX25_CALL_ACCEPT, + PATTY_AX25_CALL_CONNECT, + PATTY_AX25_CALL_CLOSE, + PATTY_AX25_CALL_SENDTO, + PATTY_AX25_CALL_RECVFROM +}; + +/* + * socket() + */ +typedef struct _patty_ax25_call_socket_request { + int type; +} patty_ax25_call_socket_request; + +typedef struct _patty_ax25_response_socket { + int ret; + int eno; +} patty_ax25_call_socket_response; + +int patty_ax25_call_socket(int server, + int type); + +/* + * bind() + */ +typedef struct _patty_ax25_call_bind_request { + int socket; + patty_ax25_addr peer; +} patty_ax25_call_bind_request; + +typedef struct _patty_ax25_call_bind_response { + int ret; + int eno; +} patty_ax25_call_bind_response; + +int patty_ax25_call_bind(int server, + int socket, + patty_ax25_addr *addr); + +/* + * listen() + */ +typedef struct _patty_ax25_call_listen_request { + int socket; +} patty_ax25_call_listen_request; + +typedef struct _patty_ax25_call_listen_response { + int ret; + int eno; +} patty_ax25_call_listen_response; + +int patty_ax25_call_listen(int server, + int socket); + +/* + * accept() + */ +typedef struct _patty_ax25_call_accept_request { + int socket; +} patty_ax25_call_accept_request; + +typedef struct _patty_ax25_call_accept_response { + int ret; + int eno; + char path[PATTY_AX25_SOCK_PATH_SIZE]; + patty_ax25_addr peer; +} patty_ax25_call_accept_response; + +int patty_ax25_call_accept(int server, + int socket, + patty_ax25_addr *peer, + char *path); + +/* + * connect() + */ +typedef struct _patty_ax25_call_connect_request { + int socket; + patty_ax25_addr peer; +} patty_ax25_call_connect_request; + +typedef struct _patty_ax25_call_connect_response { + int ret; + int eno; + char path[PATTY_AX25_SOCK_PATH_SIZE]; +} patty_ax25_call_connect_response; + +int patty_ax25_call_connect(int server, + int socket, + patty_ax25_addr *peer, + char *path); + +/* + * close() + */ +typedef struct _patty_ax25_call_close_request { + int socket; +} patty_ax25_call_close_request; + +typedef struct _patty_ax25_call_close_response { + int ret; + int eno; +} patty_ax25_call_close_response; + +int patty_ax25_call_close(int server, + int socket); + +/* + * sendto() + */ +ssize_t patty_ax25_call_sendto(int server, + int socket, + const void *buf, + size_t len, + patty_ax25_addr *addr); + +/* + * recvfrom() + */ +int patty_ax25_call_recvfrom(int server, + int socket, + void *buf, + size_t len, + patty_ax25_addr *addr); + +#endif /* _PATTY_AX25_CALL_H */ diff --git a/include/patty/ax25/client.h b/include/patty/ax25/client.h deleted file mode 100644 index ce42ba3..0000000 --- a/include/patty/ax25/client.h +++ /dev/null @@ -1,21 +0,0 @@ -#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 9ea9d1d..f0d31f1 100644 --- a/include/patty/ax25/if.h +++ b/include/patty/ax25/if.h @@ -48,17 +48,4 @@ 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_server *server, - const char *name); - -int patty_ax25_if_each(patty_ax25_server *server, - int (*callback)(patty_ax25_if *, void *), - void *ctx); - -int patty_ax25_add_if(patty_ax25_server *server, - 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/server.h b/include/patty/ax25/server.h index 50c7fa0..49324fc 100644 --- a/include/patty/ax25/server.h +++ b/include/patty/ax25/server.h @@ -1,19 +1,7 @@ #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; +typedef struct _patty_ax25_server patty_ax25_server; int patty_ax25_server_init(patty_ax25_server *server); @@ -21,4 +9,17 @@ void patty_ax25_server_stop(patty_ax25_server *server); int patty_ax25_server_run(patty_ax25_server *server); +int patty_ax25_server_add_if(patty_ax25_server *server, + patty_ax25_if *iface); + +int patty_ax25_server_delete_if(patty_ax25_server *server, + patty_ax25_if *iface); + +patty_ax25_if *patty_ax25_server_get_if(patty_ax25_server *server, + const char *name); + +int patty_ax25_server_each_if(patty_ax25_server *server, + int (*callback)(patty_ax25_if *, void *), + void *ctx); + #endif /* _PATTY_AX25_SERVER_H */ diff --git a/include/patty/list.h b/include/patty/list.h index 8a6f82a..05299d6 100644 --- a/include/patty/list.h +++ b/include/patty/list.h @@ -5,25 +5,24 @@ #include typedef struct _patty_list_item { - struct _patty_list_item * prev; - struct _patty_list_item * next; + struct _patty_list_item *prev, + *next; - void * value; + void *value; } patty_list_item; typedef struct _patty_list { - uint64_t size; uint64_t length; - patty_list_item * first; - patty_list_item * last; + patty_list_item *first, + *last; } patty_list; typedef struct _patty_list_iterator { patty_list *list; size_t index; - patty_list_item * item; + patty_list_item *item; } patty_list_iterator; typedef void (*patty_list_callback)(void *item, void *ctx); @@ -44,6 +43,8 @@ void *patty_list_last(patty_list *list); void *patty_list_pop(patty_list *list); +void *patty_list_shift(patty_list *list); + void *patty_list_splice(patty_list *list, off_t index); void *patty_list_insert(patty_list *list, off_t index); diff --git a/src/Makefile b/src/Makefile index d1a0089..77ce641 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,11 +7,10 @@ CC = $(CROSS)cc CFLAGS = $(CGFLAGS) -fPIC -Wall -O2 -I$(INCLUDE_PATH) LDFLAGS = -HEADERS = kiss.h ax25.h ax25/if.h ax25/macros.h ax25/proto.h \ +HEADERS = kiss.h ax25.h ax25/if.h ax25/macros.h ax25/proto.h ax25/call.h \ ax25/frame.h ax25/server.h list.h hash.h dict.h -OBJS = kiss.o ax25.o if.o frame.o \ - server.o list.o hash.o dict.o +OBJS = kiss.o ax25.o if.o call.o frame.o server.o list.o hash.o dict.o EXAMPLES = decode ptmx diff --git a/src/ax25.c b/src/ax25.c index 9eb4e0b..7db7920 100644 --- a/src/ax25.c +++ b/src/ax25.c @@ -5,18 +5,6 @@ #include -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, patty_ax25_addr *addr) { diff --git a/src/if.c b/src/if.c index f86a25a..87deb09 100644 --- a/src/if.c +++ b/src/if.c @@ -221,117 +221,3 @@ error_ntop: return -1; } -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(server->ifaces)) == NULL) { - goto error_list_start; - } - - while ((iface = patty_list_next(iter)) != NULL) { - if (strncmp(iface->name, name, sizeof(iface->name)) == 0) { - patty_list_finish(iter); - - return iface; - } - } - - patty_list_finish(iter); - -error_list_start: - return NULL; -} - -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(server->ifaces)) == NULL) { - goto error_list_start; - } - - while ((iface = patty_list_next(iter)) != NULL) { - if (callback(iface, ctx) < 0) { - goto error_callback; - } - } - - patty_list_finish(iter); - - return 0; - -error_callback: - patty_list_finish(iter); - -error_list_start: - return -1; -} - -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, &server->fds); - - if (server->fd_max < fd + 1) { - server->fd_max = fd + 1; - } - } - - if (patty_dict_set(server->socks, NULL + fd, sizeof(fd), iface) == NULL) { - goto error_dict_set; - } - - if (patty_list_append(server->ifaces, iface) == NULL) { - goto error_list_append; - } - - return 0; - -error_list_append: -error_dict_set: - return -1; -} - -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(server->ifaces, i) == NULL) { - goto error_list_splice; - } - - return 0; - } - - item = item->next; - i++; - } - - if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { - FD_CLR(fd, &server->fds); - - if (server->fd_max == fd) { - server->fd_max--; - } - - if (patty_dict_delete(server->socks, NULL + fd, sizeof(fd)) == NULL) { - goto error_dict_delete; - } - } - - return 0; - -error_dict_delete: -error_list_splice: - return -1; -} diff --git a/src/list.c b/src/list.c index 605fc1a..9e0f40e 100644 --- a/src/list.c +++ b/src/list.c @@ -12,7 +12,6 @@ patty_list *patty_list_new() { } list->length = 0; - list->size = 0; list->first = NULL; list->last = NULL; @@ -92,29 +91,53 @@ void *patty_list_last(patty_list *list) { } void *patty_list_pop(patty_list *list) { - patty_list_item *item = list->first; - patty_list_item *last = NULL; + void *value; + patty_list_item *item = list->last; - while (item != NULL) { - if (item->next == NULL) { - void *ret = item->value; - - if (last == NULL) { - list->first = NULL; - } else { - last->next = NULL; - } - - free(item); - - return ret; - } - - last = item; - item = item->next; + if (item == NULL) { + return NULL; } - return NULL; + if (list->last->prev) { + list->last = list->last->prev; + list->last->next = NULL; + } else { + list->first = NULL; + list->last = NULL; + } + + list->length--; + + value = item->value; + + free(item); + + return value; +} + +void *patty_list_shift(patty_list *list) { + void *value; + patty_list_item *item = list->first; + + if (item == NULL) { + return NULL; + } + + if (list->first->next) { + list->first = list->first->next; + list->first->prev = NULL; + } else { + list->first = NULL; + list->last = NULL; + } + + list->length--; + + value = item->value; + + free(item); + + return value; } void *patty_list_splice(patty_list *list, off_t index) { diff --git a/src/server.c b/src/server.c index 8793f18..7589cc9 100644 --- a/src/server.c +++ b/src/server.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -9,6 +10,22 @@ #include +struct _patty_ax25_server { + patty_list *ifaces; + + patty_dict *socks, + *socks_by_addrpair, + *socks_bound; + + int fd_max; + + fd_set fds_watch, + fds_r, + fds_w; + + patty_list *pending_accept; +}; + int patty_ax25_server_init(patty_ax25_server *server) { memset(server, '\0', sizeof(*server)); @@ -24,8 +41,22 @@ int patty_ax25_server_init(patty_ax25_server *server) { goto error_dict_new_socks_by_addrpair; } + if ((server->socks_bound = patty_dict_new()) == NULL) { + goto error_dict_new_socks_bound; + } + + if ((server->pending_accept = patty_list_new()) == NULL) { + goto error_list_new_pending_accept; + } + return 0; +error_list_new_pending_accept: + patty_dict_destroy(server->socks_bound); + +error_dict_new_socks_bound: + patty_dict_destroy(server->socks_by_addrpair); + error_dict_new_socks_by_addrpair: patty_dict_destroy(server->socks); @@ -46,15 +77,16 @@ 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_ax25_server_each_if(server, destroy_if, NULL); patty_list_destroy(server->ifaces); } -static void sock_init(patty_ax25_sock *sock) { +static void sock_init(patty_ax25_sock *sock, enum patty_ax25_sock_type type) { memset(sock, '\0', sizeof(*sock)); - sock->status = PATTY_AX25_SOCK_OPEN; + sock->status = PATTY_AX25_SOCK_CLOSED; sock->mode = PATTY_AX25_SOCK_DM; + sock->type = type; sock->n_maxlen = PATTY_AX25_FRAME_DEFAULT_MAXLEN; sock->n_window = PATTY_AX25_FRAME_DEFAULT_WINDOW; } @@ -123,28 +155,6 @@ 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; @@ -186,175 +196,6 @@ 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) { @@ -379,8 +220,385 @@ error_sock_get_fd: return -1; } -static int server_accept(patty_ax25_server *server, int socket) { - errno = ENOSYS; +int patty_ax25_server_add_if(patty_ax25_server *server, + patty_ax25_if *iface) { + int fd; + if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { + FD_SET(fd, &server->fds_watch); + + if (server->fd_max < fd + 1) { + server->fd_max = fd + 1; + } + } + + if (patty_dict_set(server->socks, NULL + fd, sizeof(fd), iface) == NULL) { + goto error_dict_set; + } + + if (patty_list_append(server->ifaces, iface) == NULL) { + goto error_list_append; + } + + return 0; + +error_list_append: +error_dict_set: + return -1; +} + +int patty_ax25_server_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(server->ifaces, i) == NULL) { + goto error_list_splice; + } + + return 0; + } + + item = item->next; + i++; + } + + if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) { + FD_CLR(fd, &server->fds_watch); + + if (server->fd_max == fd) { + server->fd_max--; + } + + if (patty_dict_delete(server->socks, NULL + fd, sizeof(fd)) == NULL) { + goto error_dict_delete; + } + } + + return 0; + +error_dict_delete: +error_list_splice: + return -1; +} + +patty_ax25_if *patty_ax25_server_get_if(patty_ax25_server *server, + const char *name) { + patty_list_iterator *iter; + patty_ax25_if *iface; + + if ((iter = patty_list_start(server->ifaces)) == NULL) { + goto error_list_start; + } + + while ((iface = patty_list_next(iter)) != NULL) { + if (strncmp(iface->name, name, sizeof(iface->name)) == 0) { + patty_list_finish(iter); + + return iface; + } + } + + patty_list_finish(iter); + +error_list_start: + return NULL; +} + +int patty_ax25_server_each_if(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(server->ifaces)) == NULL) { + goto error_list_start; + } + + while ((iface = patty_list_next(iter)) != NULL) { + if (callback(iface, ctx) < 0) { + goto error_callback; + } + } + + patty_list_finish(iter); + + return 0; + +error_callback: + patty_list_finish(iter); + +error_list_start: + return -1; +} + +static int server_socket(patty_ax25_server *server, + int client) { + patty_ax25_call_socket_request request; + patty_ax25_call_socket_response response; + + patty_ax25_sock *sock; + + if ((sock = malloc(sizeof(*sock))) == NULL) { + goto error_malloc_sock; + } + + sock_init(sock, request.type); + + if ((sock->fd = open("/dev/null", O_RDWR)) < 0) { + goto error_io; + } + + if (read(client, &request, sizeof(request)) < 0) { + goto error_io; + } + + response.ret = sock->fd; + response.eno = 0; + + if (sock_save(server, sock) < 0) { + response.ret = -1; + response.eno = errno; + + goto error_sock_save; + } + +error_sock_save: + if (write(client, &response, sizeof(response)) < 0) { + goto error_io; + } + + return 0; + +error_io: + free(sock); + +error_malloc_sock: + return -1; +} + +static int server_bind(patty_ax25_server *server, + int client) { + patty_ax25_call_bind_request request; + patty_ax25_call_bind_response response; + + patty_ax25_sock *sock; + + if (read(client, &request, sizeof(request)) < 0) { + goto error_io; + } + + if ((sock = sock_get_fd(server, request.socket)) == NULL) { + response.ret = -1; + response.eno = EBADF; + + 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') { + response.ret = -1; + response.eno = EINVAL; + + goto error_bound; + } + + if (patty_dict_get(server->socks_bound, + &sock->local, + sizeof(sock->local))) { + response.ret = -1; + response.eno = EADDRINUSE; + + goto error_inuse; + } + + 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; + } + + if (write(client, &response, sizeof(response)) < 0) { + goto error_io; + } + + response.ret = 0; + response.eno = 0; + +error_inuse: +error_bound: +error_sock_get_fd: + return 0; + +error_dict_set: +error_io: + return -1; +} + +static int server_listen(patty_ax25_server *server, + int client) { + patty_ax25_call_listen_request request; + patty_ax25_call_listen_response response; + + patty_ax25_sock *sock; + + if (read(client, &request, sizeof(request)) < 0) { + goto error_io; + } + + if ((sock = sock_get_fd(server, request.socket)) == NULL) { + response.ret = -1; + response.eno = EBADF; + + goto error_sock_get_fd; + } + + if (sock->local.callsign[0] == '\0') { + response.eno = EINVAL; + + goto error_invalid_fd; + } + + sock->status = PATTY_AX25_SOCK_LISTENING; + + response.ret = 0; + response.eno = 0; + +error_invalid_fd: +error_sock_get_fd: + if (write(client, &response, sizeof(response)) < 0) { + goto error_io; + } + + return 0; + +error_io: + return -1; +} + +static int server_accept_pty(patty_ax25_server *server, + patty_ax25_call_accept_response *response, + patty_ax25_sock *sock) { + if ((sock->fd = open("/dev/ptmx", O_RDWR)) < 0) { + goto error_open; + } + + if (grantpt(sock->fd) < 0) { + goto error_grantpt; + } + + if (unlockpt(sock->fd) < 0) { + goto error_unlockpt; + } + + if (ptsname_r(sock->fd, response->path, PATTY_AX25_SOCK_PATH_SIZE) < 0) { + goto error_ptsname_r; + } + + response->ret = sock->fd; + response->eno = 0; + + return 0; + +error_ptsname_r: +error_unlockpt: +error_grantpt: + close(sock->fd); + +error_open: + return -1; +} + +static int server_accept_unix(patty_ax25_server *server, + patty_ax25_call_accept_response *response, + patty_ax25_sock *sock) { + struct sockaddr_un addr; + + if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + goto error_socket; + } + + if (snprintf(response->path, PATTY_AX25_SOCK_PATH_SIZE, "/var/run/patty/%d.sock", sock->fd) < 0) { + goto error_snprintf; + } + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, response->path, sizeof(addr.sun_path)); + + if (bind(sock->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + goto error_bind; + } + + response->ret = sock->fd; + response->eno = 0; + + return 0; + +error_bind: +error_snprintf: + close(sock->fd); + +error_socket: + return -1; +} + +static int server_accept(patty_ax25_server *server, + int client) { + patty_ax25_call_accept_request request; + patty_ax25_call_accept_response response; + + patty_ax25_sock *local, + *remote; + + if (read(client, &request, sizeof(request)) < 0) { + goto error_io; + } + + if ((local = sock_get_fd(server, request.socket)) == NULL) { + response.ret = -1; + response.eno = EBADF; + + goto error_sock_get_fd; + } + + if ((remote = malloc(sizeof(*remote))) == NULL) { + goto error_malloc_remote; + } + + sock_init(remote, local->type); + + if (local->type & PATTY_AX25_SOCK_PTY) { + if (server_accept_pty(server, &response, remote) < 0) { + goto error_server_accept_pty; + } + } else { + if (server_accept_unix(server, &response, remote) < 0) { + goto error_server_accept_unix; + } + } + +error_sock_get_fd: + if (write(client, &response, sizeof(response)) < 0) { + goto error_io; + } + + return 0; + +error_server_accept_unix: +error_server_accept_pty: + free(remote); + +error_malloc_remote: +error_io: return -1; }