2020-06-16 18:48:29 -04:00
|
|
|
#define _GNU_SOURCE
|
2020-06-16 01:59:47 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2020-06-25 01:04:04 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2020-06-16 01:59:47 -04:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <patty/ax25.h>
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
typedef int (*patty_ax25_server_call)(patty_ax25_server *, int);
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
struct _patty_ax25_server {
|
2020-06-20 19:37:03 -04:00
|
|
|
int fd, /* fd of UNIX domain socket */
|
|
|
|
fd_max;
|
|
|
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
|
|
|
fd_set fds_watch, /* fds to monitor with select() */
|
|
|
|
fds_socks, /* fds belonging to socks */
|
|
|
|
fds_clients, /* fds belonging to clients */
|
|
|
|
fds_r, /* fds select()ed for reading */
|
|
|
|
fds_w; /* fds select()ed for writing */
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
patty_list *ifaces;
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
patty_dict *socks_by_fd,
|
|
|
|
*socks_pending_accept,
|
|
|
|
*socks_pending_connect,
|
|
|
|
*socks_established;
|
2020-06-16 18:48:29 -04:00
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
patty_dict *clients,
|
|
|
|
*clients_by_sock;
|
2020-06-16 18:48:29 -04:00
|
|
|
};
|
|
|
|
|
2020-06-24 23:56:31 -04:00
|
|
|
patty_ax25_server *patty_ax25_server_new() {
|
|
|
|
patty_ax25_server *server;
|
|
|
|
|
|
|
|
if ((server = malloc(sizeof(*server))) == NULL) {
|
|
|
|
goto error_malloc_server;
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:59:47 -04:00
|
|
|
memset(server, '\0', sizeof(*server));
|
|
|
|
|
|
|
|
if ((server->ifaces = patty_list_new()) == NULL) {
|
|
|
|
goto error_list_new_ifaces;
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((server->socks_by_fd = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_socks_by_fd;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((server->socks_pending_accept = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_socks_pending_accept;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((server->socks_pending_connect = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_socks_pending_connect;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((server->socks_established = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_socks_established;
|
2020-06-16 18:48:29 -04:00
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
if ((server->clients = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_clients;
|
|
|
|
}
|
|
|
|
|
2020-06-20 03:01:52 -04:00
|
|
|
if ((server->clients_by_sock = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_clients_by_sock;
|
|
|
|
}
|
|
|
|
|
2020-06-24 23:56:31 -04:00
|
|
|
return server;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-20 03:01:52 -04:00
|
|
|
error_dict_new_clients_by_sock:
|
2020-06-20 19:37:03 -04:00
|
|
|
patty_dict_destroy(server->clients);
|
|
|
|
|
|
|
|
error_dict_new_clients:
|
2020-06-20 03:01:52 -04:00
|
|
|
patty_dict_destroy(server->socks_established);
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
error_dict_new_socks_established:
|
|
|
|
patty_dict_destroy(server->socks_pending_connect);
|
|
|
|
|
|
|
|
error_dict_new_socks_pending_connect:
|
|
|
|
patty_dict_destroy(server->socks_pending_accept);
|
|
|
|
|
|
|
|
error_dict_new_socks_pending_accept:
|
|
|
|
patty_dict_destroy(server->socks_by_fd);
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
error_dict_new_socks_by_fd:
|
2020-06-16 01:59:47 -04:00
|
|
|
patty_list_destroy(server->ifaces);
|
|
|
|
|
|
|
|
error_list_new_ifaces:
|
2020-06-24 23:56:31 -04:00
|
|
|
free(server);
|
|
|
|
|
|
|
|
error_malloc_server:
|
|
|
|
return NULL;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int destroy_if(patty_ax25_if *iface, void *ctx) {
|
|
|
|
patty_ax25_if_destroy(iface);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
static void sock_init(patty_ax25_sock *sock, enum patty_ax25_sock_type type) {
|
2020-06-16 01:59:47 -04:00
|
|
|
memset(sock, '\0', sizeof(*sock));
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
sock->status = PATTY_AX25_SOCK_CLOSED;
|
2020-06-16 01:59:47 -04:00
|
|
|
sock->mode = PATTY_AX25_SOCK_DM;
|
2020-06-16 18:48:29 -04:00
|
|
|
sock->type = type;
|
2020-06-16 01:59:47 -04:00
|
|
|
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; i<PATTY_AX25_CALLSIGN_LEN; i++) {
|
|
|
|
hash_byte(hash, addr->callsign[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);
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
static patty_ax25_sock *sock_by_fd(patty_dict *dict,
|
|
|
|
int fd) {
|
|
|
|
return patty_dict_get(dict,
|
|
|
|
NULL + fd,
|
|
|
|
sizeof(fd));
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
static patty_ax25_sock *sock_by_addr(patty_dict *dict,
|
|
|
|
patty_ax25_addr *addr) {
|
|
|
|
patty_dict_slot *slot;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
uint32_t hash;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
hash_init(&hash);
|
|
|
|
hash_addr(&hash, addr);
|
|
|
|
hash_end(&hash);
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) {
|
|
|
|
errno = EEXIST;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
goto error_dict_slot_find;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
return (patty_ax25_sock *)slot->value;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
error_dict_slot_find:
|
2020-06-16 01:59:47 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
static patty_ax25_sock *sock_by_addrpair(patty_dict *dict,
|
|
|
|
patty_ax25_addr *local,
|
|
|
|
patty_ax25_addr *remote) {
|
2020-06-16 01:59:47 -04:00
|
|
|
patty_dict_slot *slot;
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
hash_init(&hash);
|
|
|
|
hash_addr(&hash, local);
|
|
|
|
hash_addr(&hash, remote);
|
|
|
|
hash_end(&hash);
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) {
|
|
|
|
errno = EEXIST;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
|
|
|
goto error_dict_slot_find;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (patty_ax25_sock *)slot->value;
|
|
|
|
|
|
|
|
error_dict_slot_find:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) {
|
|
|
|
if (patty_dict_set(dict,
|
|
|
|
NULL + sock->fd,
|
|
|
|
sizeof(sock->fd),
|
|
|
|
sock) == NULL) {
|
|
|
|
goto error_dict_set;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sock->fd;
|
|
|
|
|
|
|
|
error_dict_set:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sock_save_by_addr(patty_dict *dict,
|
|
|
|
patty_ax25_sock *sock,
|
|
|
|
patty_ax25_addr *addr) {
|
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
hash_init(&hash);
|
|
|
|
hash_addr(&hash, addr);
|
|
|
|
hash_end(&hash);
|
|
|
|
|
|
|
|
if (patty_dict_set_with_hash(dict,
|
|
|
|
addr,
|
|
|
|
sizeof(*addr),
|
|
|
|
sock,
|
|
|
|
hash) == NULL) {
|
|
|
|
goto error_dict_set_with_hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_dict_set_with_hash:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sock_save_by_addrpair(patty_dict *dict,
|
|
|
|
patty_ax25_sock *sock,
|
|
|
|
patty_ax25_addr *local,
|
|
|
|
patty_ax25_addr *remote) {
|
2020-06-18 19:59:26 -04:00
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
hash_init(&hash);
|
|
|
|
hash_addr(&hash, local);
|
|
|
|
hash_addr(&hash, remote);
|
|
|
|
hash_end(&hash);
|
2020-06-18 18:25:11 -04:00
|
|
|
|
|
|
|
if (patty_dict_set_with_hash(dict,
|
|
|
|
sock,
|
|
|
|
sizeof(*sock),
|
|
|
|
sock,
|
|
|
|
hash) == NULL) {
|
|
|
|
goto error_dict_set_with_hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_dict_set_with_hash:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (patty_list_append(server->ifaces, iface) == NULL) {
|
|
|
|
goto error_list_append;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
return 0;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
error_list_append:
|
2020-06-16 01:59:47 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
int patty_ax25_server_delete_if(patty_ax25_server *server,
|
|
|
|
patty_ax25_if *iface) {
|
|
|
|
patty_list_item *item = server->ifaces->first;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
int fd, i = 0;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
while (item) {
|
|
|
|
if (item->value == iface) {
|
|
|
|
if (patty_list_splice(server->ifaces, i) == NULL) {
|
|
|
|
goto error_list_splice;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
item = item->next;
|
|
|
|
i++;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) {
|
|
|
|
FD_CLR(fd, &server->fds_watch);
|
|
|
|
|
|
|
|
if (server->fd_max == fd) {
|
|
|
|
server->fd_max--;
|
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
if (patty_dict_delete(server->socks_by_fd, NULL + fd, sizeof(fd)) < 0) {
|
2020-06-16 18:48:29 -04:00
|
|
|
goto error_dict_delete;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
return 0;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
error_dict_delete:
|
|
|
|
error_list_splice:
|
|
|
|
return -1;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
patty_ax25_if *patty_ax25_server_get_if(patty_ax25_server *server,
|
|
|
|
const char *name) {
|
|
|
|
patty_list_iterator *iter;
|
|
|
|
patty_ax25_if *iface;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
while ((iface = patty_list_next(iter)) != NULL) {
|
|
|
|
if (callback(iface, ctx) < 0) {
|
|
|
|
goto error_callback;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
patty_list_finish(iter);
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
return 0;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
error_callback:
|
|
|
|
patty_list_finish(iter);
|
|
|
|
|
|
|
|
error_list_start:
|
2020-06-16 01:59:47 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int server_socket(patty_ax25_server *server,
|
2020-06-16 18:48:29 -04:00
|
|
|
int client) {
|
|
|
|
patty_ax25_call_socket_request request;
|
|
|
|
patty_ax25_call_socket_response response;
|
|
|
|
|
2020-06-16 01:59:47 -04:00
|
|
|
patty_ax25_sock *sock;
|
|
|
|
|
|
|
|
if ((sock = malloc(sizeof(*sock))) == NULL) {
|
|
|
|
goto error_malloc_sock;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
sock_init(sock, request.type);
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if ((sock->fd = open("/dev/null", O_RDWR)) < 0) {
|
|
|
|
goto error_io;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (read(client, &request, sizeof(request)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
response.ret = sock->fd;
|
|
|
|
response.eno = 0;
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if (sock_save_by_fd(server->socks_by_fd, sock) < 0) {
|
2020-06-16 18:48:29 -04:00
|
|
|
response.ret = -1;
|
|
|
|
response.eno = errno;
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
goto error_sock_save_by_fd;
|
2020-06-16 18:48:29 -04:00
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
error_sock_save_by_fd:
|
2020-06-16 18:48:29 -04:00
|
|
|
if (write(client, &response, sizeof(response)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
2020-06-16 01:59:47 -04:00
|
|
|
free(sock);
|
|
|
|
|
|
|
|
error_malloc_sock:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int server_bind(patty_ax25_server *server,
|
2020-06-16 18:48:29 -04:00
|
|
|
int client) {
|
|
|
|
patty_ax25_call_bind_request request;
|
|
|
|
patty_ax25_call_bind_response response;
|
|
|
|
|
2020-06-16 01:59:47 -04:00
|
|
|
patty_ax25_sock *sock;
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (read(client, &request, sizeof(request)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((sock = sock_by_fd(server->socks_by_fd, request.socket)) == NULL) {
|
2020-06-16 18:48:29 -04:00
|
|
|
response.ret = -1;
|
|
|
|
response.eno = EBADF;
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
goto error_sock_by_fd;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
switch (sock->status) {
|
|
|
|
case PATTY_AX25_SOCK_LISTENING:
|
|
|
|
case PATTY_AX25_SOCK_ESTABLISHED:
|
|
|
|
response.ret = -1;
|
|
|
|
response.eno = EINVAL;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
goto error_invalid_status;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
default:
|
|
|
|
break;
|
2020-06-16 18:48:29 -04:00
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
memcpy(&sock->local, &request.peer, sizeof(request.peer));
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
response.ret = 0;
|
|
|
|
response.eno = 0;
|
2020-06-16 18:48:29 -04:00
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
error_invalid_status:
|
|
|
|
error_sock_by_fd:
|
2020-06-16 18:48:29 -04:00
|
|
|
if (write(client, &response, sizeof(response)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
2020-06-16 01:59:47 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int server_listen(patty_ax25_server *server,
|
2020-06-16 18:48:29 -04:00
|
|
|
int client) {
|
|
|
|
patty_ax25_call_listen_request request;
|
|
|
|
patty_ax25_call_listen_response response;
|
|
|
|
|
2020-06-16 01:59:47 -04:00
|
|
|
patty_ax25_sock *sock;
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (read(client, &request, sizeof(request)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((sock = sock_by_fd(server->socks_by_fd, request.socket)) == NULL) {
|
2020-06-16 18:48:29 -04:00
|
|
|
response.ret = -1;
|
|
|
|
response.eno = EBADF;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
goto error_sock_by_fd;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->local.callsign[0] == '\0') {
|
2020-06-16 18:48:29 -04:00
|
|
|
response.eno = EINVAL;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
|
|
|
goto error_invalid_fd;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
sock->status = PATTY_AX25_SOCK_LISTENING;
|
|
|
|
|
|
|
|
response.ret = 0;
|
|
|
|
response.eno = 0;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
|
|
|
error_invalid_fd:
|
2020-06-18 18:25:11 -04:00
|
|
|
error_sock_by_fd:
|
2020-06-16 18:48:29 -04:00
|
|
|
if (write(client, &response, sizeof(response)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
2020-06-16 01:59:47 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (grantpt(sock->fd) < 0) {
|
|
|
|
goto error_grantpt;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (unlockpt(sock->fd) < 0) {
|
|
|
|
goto error_unlockpt;
|
|
|
|
}
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
if (ptsname_r(sock->fd, response->path, PATTY_AX25_SOCK_PATH_SIZE) < 0) {
|
|
|
|
goto error_ptsname_r;
|
2020-06-16 01:59:47 -04:00
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
sock->type |= PATTY_AX25_SOCK_PTY;
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
response->ret = sock->fd;
|
|
|
|
response->eno = 0;
|
2020-06-16 01:59:47 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
error_ptsname_r:
|
|
|
|
error_unlockpt:
|
|
|
|
error_grantpt:
|
|
|
|
close(sock->fd);
|
|
|
|
|
|
|
|
error_open:
|
2020-06-16 01:59:47 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
static int server_accept_unix(patty_ax25_server *server,
|
|
|
|
patty_ax25_call_accept_response *response,
|
|
|
|
patty_ax25_sock *sock) {
|
|
|
|
struct sockaddr_un addr;
|
2020-06-25 01:04:04 -04:00
|
|
|
struct stat st;
|
2020-06-16 18:48:29 -04:00
|
|
|
|
|
|
|
if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
|
|
goto error_socket;
|
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
if (snprintf(response->path,
|
|
|
|
PATTY_AX25_SOCK_PATH_SIZE,
|
|
|
|
PATTY_AX25_SERVER_CLIENT_PATH_FORMAT,
|
|
|
|
sock->fd) < 0) {
|
2020-06-16 18:48:29 -04:00
|
|
|
goto error_snprintf;
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:04:04 -04:00
|
|
|
if (stat(response->path, &st) >= 0) {
|
|
|
|
unlink(response->path);
|
|
|
|
}
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
sock->type |= PATTY_AX25_SOCK_UNIX;
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
if ((local = sock_by_fd(server->socks_by_fd, request.socket)) == NULL) {
|
2020-06-16 18:48:29 -04:00
|
|
|
response.ret = -1;
|
|
|
|
response.eno = EBADF;
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
goto error_sock_by_fd;
|
2020-06-16 18:48:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((remote = malloc(sizeof(*remote))) == NULL) {
|
|
|
|
goto error_malloc_remote;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock_init(remote, local->type);
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
memcpy(&remote->local, &local->local, sizeof(remote->local));
|
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
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;
|
|
|
|
|
2020-06-18 18:25:11 -04:00
|
|
|
error_sock_by_fd:
|
2020-06-16 18:48:29 -04:00
|
|
|
if (write(client, &response, sizeof(response)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
error_save_by_fd:
|
|
|
|
error_save_by_addr:
|
2020-06-16 18:48:29 -04:00
|
|
|
error_server_accept_unix:
|
|
|
|
error_server_accept_pty:
|
|
|
|
free(remote);
|
2020-06-16 01:59:47 -04:00
|
|
|
|
2020-06-16 18:48:29 -04:00
|
|
|
error_malloc_remote:
|
|
|
|
error_io:
|
2020-06-16 01:59:47 -04:00
|
|
|
return -1;
|
|
|
|
}
|
2020-06-18 18:50:24 -04:00
|
|
|
|
|
|
|
static int server_connect(patty_ax25_server *server,
|
|
|
|
int client) {
|
|
|
|
patty_ax25_call_connect_request request;
|
|
|
|
patty_ax25_call_connect_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;
|
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
switch (sock->status) {
|
|
|
|
case PATTY_AX25_SOCK_LISTENING:
|
|
|
|
response.ret = -1;
|
|
|
|
response.eno = EINVAL;
|
|
|
|
|
|
|
|
goto error_invalid_status;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_ESTABLISHED:
|
|
|
|
response.ret = -1;
|
|
|
|
response.eno = EISCONN;
|
2020-06-18 18:50:24 -04:00
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
goto error_invalid_status;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2020-06-18 18:50:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&sock->remote, &request.peer, sizeof(request.peer));
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
if (sock_save_by_addrpair(server->socks_pending_connect,
|
2020-06-18 18:50:24 -04:00
|
|
|
sock,
|
|
|
|
&sock->local,
|
|
|
|
&sock->remote) < 0) {
|
|
|
|
goto error_sock_save_by_addrpair;
|
|
|
|
}
|
|
|
|
|
2020-06-20 03:01:52 -04:00
|
|
|
/*
|
|
|
|
* TODO: Send SABM(E) frame; set timer, and await response from peer.
|
|
|
|
* We will need to know what client to send a response to when either the
|
|
|
|
* timeout has been exceeded or the peer has sent a UA frame to
|
|
|
|
* acknowledge and establish the connection.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return 0;
|
2020-06-18 19:59:26 -04:00
|
|
|
|
|
|
|
error_invalid_status:
|
2020-06-18 18:50:24 -04:00
|
|
|
error_sock_by_fd:
|
|
|
|
if (write(client, &response, sizeof(response)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_sock_save_by_addrpair:
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
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;
|
|
|
|
}
|
2020-06-20 19:37:03 -04:00
|
|
|
|
|
|
|
static patty_ax25_server_call server_calls[PATTY_AX25_CALL_COUNT] = {
|
|
|
|
NULL,
|
|
|
|
server_socket,
|
|
|
|
server_bind,
|
|
|
|
server_listen,
|
|
|
|
server_accept,
|
|
|
|
server_connect,
|
|
|
|
server_close,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static int listen_unix(patty_ax25_server *server, const char *path) {
|
|
|
|
struct sockaddr_un addr;
|
2020-06-25 01:04:04 -04:00
|
|
|
struct stat st;
|
2020-06-20 19:37:03 -04:00
|
|
|
|
|
|
|
if (server->fd) {
|
|
|
|
errno = EBUSY;
|
|
|
|
|
|
|
|
goto error_listening;
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:04:04 -04:00
|
|
|
if (stat(path, &st) >= 0) {
|
|
|
|
unlink(path);
|
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
if ((server->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
|
|
goto error_socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&addr, '\0', sizeof(addr));
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
strncpy(addr.sun_path, path, sizeof(addr.sun_path));
|
|
|
|
|
|
|
|
if (bind(server->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
|
|
goto error_bind;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (listen(server->fd, 0) < 0) {
|
|
|
|
goto error_listen;
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:04:17 -04:00
|
|
|
FD_SET(server->fd, &server->fds_watch);
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_listen:
|
|
|
|
error_bind:
|
|
|
|
close(server->fd);
|
|
|
|
|
|
|
|
error_socket:
|
|
|
|
error_listening:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int accept_client(patty_ax25_server *server) {
|
|
|
|
int fd;
|
|
|
|
struct sockaddr addr;
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
|
|
if (!FD_ISSET(server->fd, &server->fds_r)) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = accept(server->fd, &addr, &addrlen)) < 0) {
|
|
|
|
goto error_accept;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (patty_dict_set(server->clients,
|
|
|
|
NULL + fd,
|
|
|
|
sizeof(fd),
|
|
|
|
NULL + fd) == NULL) {
|
|
|
|
goto error_dict_set;
|
|
|
|
}
|
|
|
|
|
|
|
|
FD_SET(fd, &server->fds_clients);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_dict_set:
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
error_accept:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_client(void *key,
|
|
|
|
size_t keysz,
|
|
|
|
void *value,
|
|
|
|
void *ctx) {
|
|
|
|
patty_ax25_server *server = ctx;
|
|
|
|
int client = (int)(key - NULL);
|
|
|
|
|
|
|
|
ssize_t readlen;
|
|
|
|
enum patty_ax25_call call;
|
|
|
|
|
|
|
|
if (!FD_ISSET(client, &server->fds_r)) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((readlen = read(server->fd, &call, sizeof(call))) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
} else if (readlen == 0) {
|
|
|
|
FD_CLR(client, &server->fds_watch);
|
|
|
|
FD_CLR(client, &server->fds_clients);
|
|
|
|
|
|
|
|
if (patty_dict_delete(server->clients,
|
|
|
|
key,
|
|
|
|
keysz) < 0) {
|
|
|
|
goto error_dict_delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(client) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call <= PATTY_AX25_CALL_NONE || call >= PATTY_AX25_CALL_COUNT) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return server_calls[call](server, client);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_dict_delete:
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_clients(patty_ax25_server *server) {
|
|
|
|
return patty_dict_each(server->clients, handle_client, server);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_packet_rx(patty_ax25_server *server,
|
|
|
|
patty_ax25_if *iface,
|
|
|
|
void *buf,
|
|
|
|
size_t len) {
|
|
|
|
patty_ax25_frame frame;
|
|
|
|
|
|
|
|
if (patty_ax25_frame_decode(&frame, buf, len) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: Handle inbound packet
|
|
|
|
*/
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((readlen = patty_ax25_if_recv(iface, &buf)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
} else if (readlen == 0) {
|
|
|
|
FD_CLR(fd, &server->fds_watch);
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle_packet_rx(server, iface, buf, readlen) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_ifaces(patty_ax25_server *server) {
|
|
|
|
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 (handle_iface(server, iface) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
patty_list_finish(iter);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
|
|
|
patty_list_finish(iter);
|
|
|
|
|
|
|
|
error_list_start:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_sock(void *key,
|
|
|
|
size_t keysz,
|
|
|
|
void *value,
|
|
|
|
void *ctx) {
|
|
|
|
patty_ax25_server *server = ctx;
|
2020-06-21 01:13:33 -04:00
|
|
|
patty_ax25_sock *sock = value;
|
2020-06-21 01:57:57 -04:00
|
|
|
patty_ax25_if *iface = sock->iface;
|
2020-06-20 19:37:03 -04:00
|
|
|
|
2020-06-21 01:13:33 -04:00
|
|
|
int fd = (int)(key - NULL),
|
|
|
|
fd_tnc = patty_kiss_tnc_fd(iface->tnc);
|
2020-06-20 19:37:03 -04:00
|
|
|
|
2020-06-21 01:13:33 -04:00
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
if (!FD_ISSET(fd, &server->fds_r) || !FD_ISSET(fd_tnc, &server->fds_w)) {
|
2020-06-20 19:37:03 -04:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2020-06-21 01:13:33 -04:00
|
|
|
if ((len = read(fd, iface->tx_buf, iface->tx_bufsz)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
} else if (len == 0) {
|
|
|
|
FD_CLR(fd, &server->fds_watch);
|
|
|
|
|
|
|
|
if (patty_dict_delete(server->socks_established,
|
|
|
|
NULL + fd,
|
|
|
|
sizeof(fd)) < 0) {
|
|
|
|
goto error_dict_delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((len = patty_ax25_if_send(iface, iface->tx_buf, len)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
/*
|
|
|
|
* TODO: Finish this
|
|
|
|
*/
|
|
|
|
|
|
|
|
done:
|
|
|
|
return 0;
|
2020-06-21 01:13:33 -04:00
|
|
|
|
|
|
|
error_dict_delete:
|
|
|
|
error_io:
|
|
|
|
return -1;
|
2020-06-20 19:37:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_socks(patty_ax25_server *server) {
|
2020-06-21 01:13:33 -04:00
|
|
|
return patty_dict_each(server->socks_established,
|
2020-06-20 19:37:03 -04:00
|
|
|
handle_sock,
|
|
|
|
server);
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_ax25_server_run(patty_ax25_server *server) {
|
|
|
|
if (listen_unix(server, PATTY_AX25_SERVER_PATH) < 0) {
|
|
|
|
goto error_listen_unix;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int nready;
|
|
|
|
|
2020-06-21 22:49:19 -04:00
|
|
|
memcpy(&server->fds_r, &server->fds_watch, sizeof(server->fds_r));
|
|
|
|
memcpy(&server->fds_w, &server->fds_watch, sizeof(server->fds_w));
|
2020-06-20 19:37:03 -04:00
|
|
|
|
|
|
|
if ((nready = select( server->fd_max,
|
|
|
|
&server->fds_r,
|
|
|
|
&server->fds_w,
|
|
|
|
NULL,
|
|
|
|
&server->timeout)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (accept_client(server) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle_clients(server) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle_ifaces(server) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle_socks(server) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(server->fd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_io:
|
|
|
|
close(server->fd);
|
|
|
|
|
|
|
|
error_listen_unix:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_by_fd);
|
|
|
|
|
|
|
|
patty_ax25_server_each_if(server, destroy_if, NULL);
|
|
|
|
patty_list_destroy(server->ifaces);
|
2020-06-24 23:56:31 -04:00
|
|
|
|
|
|
|
free(server);
|
2020-06-20 19:37:03 -04:00
|
|
|
}
|