SO BLOODY CLOSE

This commit is contained in:
XANTRONIX Development 2020-06-30 23:20:12 -04:00 committed by XANTRONIX Industrial
parent 94f073c38d
commit 22bf692a61
9 changed files with 594 additions and 241 deletions

View file

@ -18,16 +18,19 @@ enum patty_ax25_call {
* socket() * socket()
*/ */
typedef struct _patty_ax25_call_socket_request { typedef struct _patty_ax25_call_socket_request {
int type; int opts;
} patty_ax25_call_socket_request; } patty_ax25_call_socket_request;
typedef struct _patty_ax25_response_socket { typedef struct _patty_ax25_response_socket {
int ret; int ret;
int eno; int eno;
char path[PATTY_AX25_SOCK_PATH_SIZE];
} patty_ax25_call_socket_response; } patty_ax25_call_socket_response;
int patty_ax25_call_socket(int server, int patty_ax25_call_socket(int server,
int type); int opts,
char *path,
size_t len);
/* /*
* bind() * bind()
@ -71,14 +74,15 @@ typedef struct _patty_ax25_call_accept_request {
typedef struct _patty_ax25_call_accept_response { typedef struct _patty_ax25_call_accept_response {
int ret; int ret;
int eno; int eno;
char path[PATTY_AX25_SOCK_PATH_SIZE];
patty_ax25_addr peer; patty_ax25_addr peer;
char path[PATTY_AX25_SOCK_PATH_SIZE];
} patty_ax25_call_accept_response; } patty_ax25_call_accept_response;
int patty_ax25_call_accept(int server, int patty_ax25_call_accept(int server,
int socket, int socket,
patty_ax25_addr *peer, patty_ax25_addr *peer,
char *path); char *path,
size_t len);
/* /*
* connect() * connect()
@ -91,13 +95,11 @@ typedef struct _patty_ax25_call_connect_request {
typedef struct _patty_ax25_call_connect_response { typedef struct _patty_ax25_call_connect_response {
int ret; int ret;
int eno; int eno;
char path[PATTY_AX25_SOCK_PATH_SIZE];
} patty_ax25_call_connect_response; } patty_ax25_call_connect_response;
int patty_ax25_call_connect(int server, int patty_ax25_call_connect(int server,
int socket, int socket,
patty_ax25_addr *peer, patty_ax25_addr *peer);
char *path);
/* /*
* close() * close()

View file

@ -56,7 +56,7 @@
(((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x0f)) (((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x0f))
#define PATTY_AX25_CONTROL_UNNUMBERED_UA(c) \ #define PATTY_AX25_CONTROL_UNNUMBERED_UA(c) \
(((c & 0xe0) == 0x30) && ((c & 0x0f) == 0x03)) (((c & 0xe0) == 0x60) && ((c & 0x0f) == 0x03))
#define PATTY_AX25_CONTROL_UNNUMBERED_FRMR(c) \ #define PATTY_AX25_CONTROL_UNNUMBERED_FRMR(c) \
(((c & 0xe0) == 0x40) && ((c & 0x0f) == 0x07)) (((c & 0xe0) == 0x40) && ((c & 0x0f) == 0x07))

View file

@ -1,12 +1,13 @@
#ifndef _PATTY_AX25_SOCK_H #ifndef _PATTY_AX25_SOCK_H
#define _PATTY_AX25_SOCK_H #define _PATTY_AX25_SOCK_H
enum patty_ax25_sock_type { #define PATTY_AX25_SOCK_BUFSZ 4096
enum patty_ax25_sock_opts {
PATTY_AX25_SOCK_NONE, PATTY_AX25_SOCK_NONE,
PATTY_AX25_SOCK_UNIX = 1 << 0, PATTY_AX25_SOCK_PTY = 1 << 0,
PATTY_AX25_SOCK_PTY = 1 << 1, PATTY_AX25_SOCK_RAW = 1 << 1,
PATTY_AX25_SOCK_RAW = 1 << 2, PATTY_AX25_SOCK_NONBLOCK = 1 << 2
PATTY_AX25_SOCK_NONBLOCK = 1 << 3
}; };
enum patty_ax25_sock_status { enum patty_ax25_sock_status {
@ -24,7 +25,7 @@ enum patty_ax25_sock_mode {
}; };
typedef struct _patty_ax25_sock { typedef struct _patty_ax25_sock {
enum patty_ax25_sock_type type; enum patty_ax25_sock_opts opts;
enum patty_ax25_sock_status status; enum patty_ax25_sock_status status;
enum patty_ax25_sock_mode mode; enum patty_ax25_sock_mode mode;
@ -42,6 +43,9 @@ typedef struct _patty_ax25_sock {
int fd; int fd;
char path[PATTY_AX25_SOCK_PATH_SIZE]; char path[PATTY_AX25_SOCK_PATH_SIZE];
void *buf;
size_t bufsz;
patty_ax25_if *iface; patty_ax25_if *iface;
patty_ax25_addr local, patty_ax25_addr local,
@ -52,7 +56,7 @@ typedef struct _patty_ax25_sock {
} patty_ax25_sock; } patty_ax25_sock;
#define PATTY_AX25_SOCK_CONTROL_SABM(sock, flag) \ #define PATTY_AX25_SOCK_CONTROL_SABM(sock, flag) \
(((sock->seq_recv & 07) << 7) | (flag << 4) | (sock->seq_send & 07)) (((sock->seq_recv & 0x07) << 7) | (flag << 4) | (sock->seq_send & 0x07))
#define PATTY_AX25_SOCK_CONTROL_SABME(sock, flag) \ #define PATTY_AX25_SOCK_CONTROL_SABME(sock, flag) \
(((sock->seq_recv & 0x7f) << 15) | (flag << 7) | (sock->seq_send & 0x7f)) (((sock->seq_recv & 0x7f) << 15) | (flag << 7) | (sock->seq_send & 0x7f))
@ -62,10 +66,14 @@ typedef struct _patty_ax25_sock {
PATTY_AX25_SOCK_CONTROL_SABME(sock, flag): \ PATTY_AX25_SOCK_CONTROL_SABME(sock, flag): \
PATTY_AX25_SOCK_CONTROL_SABM(sock, flag)) PATTY_AX25_SOCK_CONTROL_SABM(sock, flag))
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_sock_type type); patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_sock_opts opts);
void patty_ax25_sock_reset(patty_ax25_sock *sock);
void patty_ax25_sock_destroy(patty_ax25_sock *sock); void patty_ax25_sock_destroy(patty_ax25_sock *sock);
char *patty_ax25_sock_pty(patty_ax25_sock *sock);
ssize_t patty_ax25_sock_send(patty_ax25_sock *sock, ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
uint16_t control, uint16_t control,
uint8_t proto, uint8_t proto,
@ -74,6 +82,10 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int poll); ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int poll);
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int poll);
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int poll);
ssize_t patty_ax25_sock_write(patty_ax25_sock *sock, ssize_t patty_ax25_sock_write(patty_ax25_sock *sock,
uint8_t proto, uint8_t proto,
void *buf, void *buf,

View file

@ -14,7 +14,7 @@ HEADERS = kiss.h ax25.h ax25/if.h ax25/macros.h ax25/proto.h \
OBJS = kiss.o ax25.o if.o call.o frame.o sock.o route.o server.o \ OBJS = kiss.o ax25.o if.o call.o frame.o sock.o route.o server.o \
list.o hash.o dict.o list.o hash.o dict.o
EXAMPLES = decode ptmx testclient testserver EXAMPLES = decode ptmx testclient-connect testclient-listen testserver
HEADERS_BUILD = $(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/, $(HEADERS)) HEADERS_BUILD = $(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/, $(HEADERS))

View file

@ -6,11 +6,13 @@
#include <patty/ax25.h> #include <patty/ax25.h>
int patty_ax25_call_socket(int server, int patty_ax25_call_socket(int server,
int type) { int opts,
char *path,
size_t len) {
enum patty_ax25_call call = PATTY_AX25_CALL_SOCKET; enum patty_ax25_call call = PATTY_AX25_CALL_SOCKET;
patty_ax25_call_socket_request request = { patty_ax25_call_socket_request request = {
type opts
}; };
patty_ax25_call_socket_response response; patty_ax25_call_socket_response response;
@ -27,6 +29,10 @@ int patty_ax25_call_socket(int server,
goto error_io; goto error_io;
} }
if (path) {
strncpy(path, response.path, len);
}
errno = response.eno; errno = response.eno;
return response.ret; return response.ret;
@ -101,7 +107,8 @@ error_io:
int patty_ax25_call_accept(int server, int patty_ax25_call_accept(int server,
int socket, int socket,
patty_ax25_addr *peer, patty_ax25_addr *peer,
char *path) { char *path,
size_t len) {
enum patty_ax25_call call = PATTY_AX25_CALL_ACCEPT; enum patty_ax25_call call = PATTY_AX25_CALL_ACCEPT;
patty_ax25_call_accept_request request = { patty_ax25_call_accept_request request = {
@ -110,6 +117,8 @@ int patty_ax25_call_accept(int server,
patty_ax25_call_accept_response response; patty_ax25_call_accept_response response;
memset(&response, '\0', sizeof(response));
if (write(server, &call, sizeof(call)) < 0) { if (write(server, &call, sizeof(call)) < 0) {
goto error_io; goto error_io;
} }
@ -123,8 +132,11 @@ int patty_ax25_call_accept(int server,
} }
if (response.ret >= 0) { if (response.ret >= 0) {
strncpy(path, response.path, PATTY_AX25_SOCK_PATH_SIZE);
memcpy(peer, &response.peer, sizeof(*peer)); memcpy(peer, &response.peer, sizeof(*peer));
if (path) {
strncpy(path, response.path, len);
}
} }
errno = response.eno; errno = response.eno;
@ -137,8 +149,7 @@ error_io:
int patty_ax25_call_connect(int server, int patty_ax25_call_connect(int server,
int socket, int socket,
patty_ax25_addr *peer, patty_ax25_addr *peer) {
char *path) {
enum patty_ax25_call call = PATTY_AX25_CALL_CONNECT; enum patty_ax25_call call = PATTY_AX25_CALL_CONNECT;
patty_ax25_call_connect_request request = { patty_ax25_call_connect_request request = {
@ -161,10 +172,6 @@ int patty_ax25_call_connect(int server,
goto error_io; goto error_io;
} }
if (response.ret >= 0) {
strncpy(path, response.path, PATTY_AX25_SOCK_PATH_SIZE);
}
errno = response.eno; errno = response.eno;
return response.ret; return response.ret;

View file

@ -23,8 +23,6 @@ struct _patty_ax25_server {
struct timeval timeout; struct timeval timeout;
fd_set fds_watch, /* fds to monitor with select() */ 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_r, /* fds select()ed for reading */
fds_w; /* fds select()ed for writing */ fds_w; /* fds select()ed for writing */
@ -126,31 +124,18 @@ static patty_ax25_sock *sock_by_fd(patty_dict *dict,
static patty_ax25_sock *sock_by_addr(patty_dict *dict, static patty_ax25_sock *sock_by_addr(patty_dict *dict,
patty_ax25_addr *addr) { patty_ax25_addr *addr) {
patty_dict_slot *slot;
uint32_t hash; uint32_t hash;
patty_hash_init(&hash); patty_hash_init(&hash);
patty_ax25_addr_hash(&hash, addr); patty_ax25_addr_hash(&hash, addr);
patty_hash_end(&hash); patty_hash_end(&hash);
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { return patty_dict_get_with_hash(dict, hash);
errno = EEXIST;
goto error_dict_slot_find;
}
return (patty_ax25_sock *)slot->value;
error_dict_slot_find:
return NULL;
} }
static patty_ax25_sock *sock_by_addrpair(patty_dict *dict, static patty_ax25_sock *sock_by_addrpair(patty_dict *dict,
patty_ax25_addr *local, patty_ax25_addr *local,
patty_ax25_addr *remote) { patty_ax25_addr *remote) {
patty_dict_slot *slot;
uint32_t hash; uint32_t hash;
patty_hash_init(&hash); patty_hash_init(&hash);
@ -158,16 +143,7 @@ static patty_ax25_sock *sock_by_addrpair(patty_dict *dict,
patty_ax25_addr_hash(&hash, remote); patty_ax25_addr_hash(&hash, remote);
patty_hash_end(&hash); patty_hash_end(&hash);
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { return patty_dict_get_with_hash(dict, hash);
errno = EEXIST;
goto error_dict_slot_find;
}
return (patty_ax25_sock *)slot->value;
error_dict_slot_find:
return NULL;
} }
static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) { static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) {
@ -329,26 +305,10 @@ static inline void clear_fd(patty_ax25_server *server, int fd) {
static inline void watch_sock(patty_ax25_server *server, patty_ax25_sock *sock) { static inline void watch_sock(patty_ax25_server *server, patty_ax25_sock *sock) {
watch_fd(server, sock->fd); watch_fd(server, sock->fd);
FD_SET(sock->fd, &server->fds_socks);
} }
static inline void clear_sock(patty_ax25_server *server, patty_ax25_sock *sock) { static inline void clear_sock(patty_ax25_server *server, patty_ax25_sock *sock) {
clear_fd(server, sock->fd); clear_fd(server, sock->fd);
FD_CLR(sock->fd, &server->fds_socks);
}
static inline void watch_client(patty_ax25_server *server, int fd) {
watch_fd(server, fd);
FD_SET(fd, &server->fds_clients);
}
static inline void clear_client(patty_ax25_server *server, int fd) {
clear_fd(server, fd);
FD_CLR(fd, &server->fds_clients);
} }
int patty_ax25_server_add_if(patty_ax25_server *server, int patty_ax25_server_add_if(patty_ax25_server *server,
@ -469,17 +429,10 @@ static int server_socket(patty_ax25_server *server,
goto error_read; goto error_read;
} }
if ((sock = patty_ax25_sock_new(request.type)) == NULL) { if ((sock = patty_ax25_sock_new(request.opts)) == NULL) {
goto error_sock_new; goto error_sock_new;
} }
if ((sock->fd = open("/dev/null", O_RDWR)) < 0) {
goto error_open;
}
response.ret = sock->fd;
response.eno = 0;
if (sock_save_by_fd(server->socks_by_fd, sock) < 0) { if (sock_save_by_fd(server->socks_by_fd, sock) < 0) {
response.ret = -1; response.ret = -1;
response.eno = errno; response.eno = errno;
@ -487,17 +440,28 @@ static int server_socket(patty_ax25_server *server,
goto error_sock_save_by_fd; goto error_sock_save_by_fd;
} }
error_sock_save_by_fd: if (patty_dict_set_with_hash(server->clients_by_sock,
NULL + sock->fd,
sizeof(sock->fd),
NULL + client,
(uint32_t)sock->fd) < 0) {
goto error_dict_set_with_hash;
}
response.ret = sock->fd;
response.eno = 0;
memcpy(response.path, sock->path, sizeof(response.path));
if (write(client, &response, sizeof(response)) < 0) { if (write(client, &response, sizeof(response)) < 0) {
goto error_write; goto error_write;
} }
return 0; return 0;
error_dict_set_with_hash:
error_sock_save_by_fd:
error_write: error_write:
close(sock->fd);
error_open:
patty_ax25_sock_destroy(sock); patty_ax25_sock_destroy(sock);
error_sock_new: error_sock_new:
@ -593,132 +557,30 @@ error_io:
return -1; 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;
}
sock->type |= PATTY_AX25_SOCK_PTY;
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;
struct stat st;
if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
goto error_socket;
}
if (snprintf(response->path,
PATTY_AX25_SOCK_PATH_SIZE,
PATTY_AX25_SERVER_CLIENT_PATH_FORMAT,
sock->fd) < 0) {
goto error_snprintf;
}
if (stat(response->path, &st) >= 0) {
unlink(response->path);
}
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;
}
sock->type |= PATTY_AX25_SOCK_UNIX;
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, static int server_accept(patty_ax25_server *server,
int client) { int client) {
patty_ax25_call_accept_request request; patty_ax25_call_accept_request request;
patty_ax25_call_accept_response response; patty_ax25_call_accept_response response;
patty_ax25_sock *local, patty_ax25_sock *sock;
*remote;
if (read(client, &request, sizeof(request)) < 0) { if (read(client, &request, sizeof(request)) < 0) {
goto error_io; goto error_io;
} }
if ((local = sock_by_fd(server->socks_by_fd, request.socket)) == NULL) { if ((sock = sock_by_fd(server->socks_by_fd, request.socket)) == NULL) {
response.ret = -1; response.ret = -1;
response.eno = EBADF; response.eno = EBADF;
goto error_sock_by_fd; goto error_sock_by_fd;
} }
if ((remote = patty_ax25_sock_new(local->type)) == NULL) {
goto error_sock_new_remote;
}
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;
}
} else {
if (server_accept_unix(server, &response, remote) < 0) {
goto error_server_accept_unix;
}
}
remote->status = PATTY_AX25_SOCK_PENDING_ACCEPT;
if (sock_save_by_addr(server->socks_pending_accept, if (sock_save_by_addr(server->socks_pending_accept,
remote, sock,
&local->local) < 0) { &sock->local) < 0) {
goto error_save_by_addr; goto error_save_by_addr;
} }
if (sock_save_by_fd(server->socks_by_fd, remote) < 0) {
goto error_save_by_fd;
}
return 0; return 0;
error_sock_by_fd: error_sock_by_fd:
@ -728,13 +590,7 @@ error_sock_by_fd:
return 0; return 0;
error_save_by_fd:
error_save_by_addr: error_save_by_addr:
error_server_accept_unix:
error_server_accept_pty:
patty_ax25_sock_destroy(remote);
error_sock_new_remote:
error_io: error_io:
return -1; return -1;
} }
@ -828,6 +684,14 @@ static int server_connect(patty_ax25_server *server,
goto error_sock_save_by_addrpair; goto error_sock_save_by_addrpair;
} }
if (patty_dict_set_with_hash(server->clients_by_sock,
NULL + sock->fd,
sizeof(sock->fd),
NULL + client,
(uint32_t)client) < 0) {
goto error_dict_set_with_hash;
}
/* /*
* TODO: Send SABM(E) frame; set timer, and await response from peer. * 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 * We will need to know what client to send a response to when either the
@ -841,7 +705,7 @@ static int server_connect(patty_ax25_server *server,
goto error_sock_send_sabm; goto error_sock_send_sabm;
} }
return 0; return 0;
error_sock_send_sabm: error_sock_send_sabm:
error_network_down: error_network_down:
@ -853,6 +717,7 @@ error_sock_by_fd:
return 0; return 0;
error_dict_set_with_hash:
error_sock_save_by_addrpair: error_sock_save_by_addrpair:
error_io: error_io:
return -1; return -1;
@ -984,7 +849,7 @@ static int accept_client(patty_ax25_server *server) {
goto error_dict_set; goto error_dict_set;
} }
watch_client(server, fd); watch_fd(server, fd);
done: done:
return 0; return 0;
@ -1013,7 +878,7 @@ static int handle_client(void *key,
if ((readlen = read(client, &call, sizeof(call))) < 0) { if ((readlen = read(client, &call, sizeof(call))) < 0) {
goto error_io; goto error_io;
} else if (readlen == 0) { } else if (readlen == 0) {
clear_client(server, client); clear_fd(server, client);
if (patty_dict_delete_with_hash(server->clients, if (patty_dict_delete_with_hash(server->clients,
(uint32_t)(key - NULL)) < 0) { (uint32_t)(key - NULL)) < 0) {
@ -1058,7 +923,8 @@ static void save_reply_addr(patty_ax25_sock *sock,
hops = frame->hops > PATTY_AX25_MAX_HOPS? hops = frame->hops > PATTY_AX25_MAX_HOPS?
PATTY_AX25_MAX_HOPS: sock->hops; PATTY_AX25_MAX_HOPS: sock->hops;
memcpy(&sock->remote, &frame->src, sizeof(patty_ax25_addr)); memcpy(&sock->remote, &frame->src, sizeof(patty_ax25_addr));
memcpy(&sock->local, &frame->dest, sizeof(patty_ax25_addr));
for (i=0; i<hops; i++) { for (i=0; i<hops; i++) {
memcpy(&sock->repeaters[i], memcpy(&sock->repeaters[i],
@ -1112,40 +978,228 @@ static int reply_ua(patty_ax25_if *iface,
.infolen = 0 .infolen = 0
}; };
char callsign[7];
uint8_t ssid;
patty_ax25_ntop(&frame->dest, callsign, &ssid, sizeof(callsign));
return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL);
}
static int reply_frmr(patty_ax25_if *iface,
patty_ax25_frame *frame,
enum patty_ax25_frame_u_flags flags) {
patty_ax25_frame reply = {
.control = PATTY_AX25_FRAME_U_FRMR | flags,
.proto = PATTY_AX25_PROTO_NONE,
.info = NULL,
.infolen = 0
};
return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL); return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL);
} }
static int handle_sabm(patty_ax25_server *server, static int handle_sabm(patty_ax25_server *server,
patty_ax25_if *iface, patty_ax25_if *iface,
patty_ax25_frame *frame) { patty_ax25_frame *frame) {
patty_ax25_sock *sock; int client;
patty_ax25_sock *local, *remote;
patty_ax25_call_accept_response response;
if ((sock = sock_by_addr(server->socks_pending_accept, if ((local = sock_by_addr(server->socks_pending_accept,
&frame->dest)) == NULL) { &frame->dest)) == NULL) {
return reply_dm(iface, frame, PATTY_AX25_FRAME_U_FINAL); return reply_dm(iface, frame, PATTY_AX25_FRAME_U_FINAL);
} }
if ((client = (int)patty_dict_get_with_hash(server->clients_by_sock,
(uint32_t)local->fd)) == 0) {
goto error_lookup_client;
}
if ((remote = patty_ax25_sock_new(local->opts)) == NULL) {
goto error_sock_new;
}
remote->status = PATTY_AX25_SOCK_ESTABLISHED;
remote->mode = PATTY_AX25_SOCK_SABM;
remote->iface = iface;
save_reply_addr(remote, frame);
if (sock_save_by_fd(server->socks_by_fd, remote) < 0) {
goto error_sock_save_by_fd;
}
if (sock_save_by_addrpair(server->socks_established,
remote,
&remote->local,
&remote->remote) < 0) {
goto error_sock_save_by_addrpair;
}
if (sock_delete_by_addr(server->socks_pending_accept,
&local->local) < 0) {
goto error_sock_delete_by_addr;
}
if (reply_ua(iface, frame, PATTY_AX25_FRAME_U_FINAL) < 0) {
goto error_reply_ua;
}
memset(&response, '\0', sizeof(response));
response.ret = 0;
response.eno = 0;
memcpy(&response.peer, &frame->src, sizeof(patty_ax25_addr));
memcpy(&response.path, &remote->path, sizeof(response.path));
if (write(client, &response, sizeof(response)) < 0) {
goto error_write;
}
watch_sock(server, remote);
return 0;
error_write:
error_reply_ua:
error_sock_delete_by_addr:
error_sock_save_by_addrpair:
error_sock_save_by_fd:
patty_ax25_sock_destroy(remote);
error_sock_new:
error_lookup_client:
return -1;
}
static int handle_ua(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
int client;
patty_ax25_sock *sock;
patty_ax25_call_connect_response response;
if ((sock = sock_by_addrpair(server->socks_pending_connect,
&frame->dest,
&frame->src)) == NULL) {
return reply_frmr(iface, frame, PATTY_AX25_FRAME_U_FINAL);
}
if ((client = (int)patty_dict_get_with_hash(server->clients_by_sock,
(uint32_t)sock->fd)) == 0) {
goto error_lookup_client;
}
sock->status = PATTY_AX25_SOCK_ESTABLISHED; sock->status = PATTY_AX25_SOCK_ESTABLISHED;
sock->mode = PATTY_AX25_SOCK_SABM; sock->mode = PATTY_AX25_SOCK_SABM;
save_reply_addr(sock, frame);
if (sock_save_by_addrpair(server->socks_established, if (sock_save_by_addrpair(server->socks_established,
sock, sock,
&sock->local, &sock->local,
&sock->remote) < 0) { &sock->remote) < 0) {
goto error_save_by_addrpair; goto error_save_by_addrpair;
} }
if (sock_delete_by_addr(server->socks_pending_accept, if (sock_delete_by_addrpair(server->socks_pending_connect,
&frame->dest) < 0) { &sock->local,
goto error_delete_by_addr; &sock->remote) < 0) {
goto error_delete_by_addrpair;
} }
return reply_ua(iface, frame, PATTY_AX25_FRAME_U_FINAL); response.ret = 0;
response.eno = 0;
error_delete_by_addr: if (write(client, &response, sizeof(response)) < 0) {
goto error_write;
}
watch_sock(server, sock);
return 0;
error_write:
patty_ax25_sock_destroy(sock);
error_delete_by_addrpair:
error_save_by_addrpair: error_save_by_addrpair:
error_lookup_client:
return -1;
}
static int handle_dm(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
int client;
patty_ax25_sock *sock;
patty_ax25_call_connect_response response;
if ((sock = sock_by_addrpair(server->socks_pending_connect,
&frame->dest,
&frame->src)) == NULL) {
return 0;
}
if ((client = (int)patty_dict_get_with_hash(server->clients_by_sock,
(uint32_t)sock->fd)) == 0) {
goto error_lookup_client;
}
if (sock_delete_by_addrpair(server->socks_pending_connect,
&frame->dest,
&frame->src) < 0) {
goto error_delete_by_addrpair;
}
response.ret = -1;
response.eno = ECONNREFUSED;
patty_ax25_sock_reset(sock);
if (write(client, &response, sizeof(response)) < 0) {
goto error_write;
}
return 0;
error_write:
error_delete_by_addrpair:
error_lookup_client:
return -1;
}
static int handle_info(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
patty_ax25_sock *sock;
if ((sock = sock_by_addrpair(server->socks_established,
&frame->dest,
&frame->src)) == NULL) {
/*
* TODO: Figure out how to respond to a packet sent outside of an
* active session
*/
goto done;
}
if (sock->status != PATTY_AX25_SOCK_ESTABLISHED) {
/*
* TODO: Figure out how to respond to a packet sent to a socket not
* in an established state
*/
goto done;
}
if (write(sock->fd, frame->info, frame->infolen) < 0) {
goto error_write;
}
done:
return 0;
error_write:
return -1; return -1;
} }
@ -1166,6 +1220,12 @@ static int handle_frame(patty_ax25_server *server,
if (PATTY_AX25_CONTROL_UNNUMBERED_SABM(frame.control)) { if (PATTY_AX25_CONTROL_UNNUMBERED_SABM(frame.control)) {
return handle_sabm(server, iface, &frame); return handle_sabm(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_UNNUMBERED_UA(frame.control)) {
return handle_ua(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_UNNUMBERED_DM(frame.control)) {
return handle_dm(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_INFO(frame.control)) {
return handle_info(server, iface, &frame);
} }
return 0; return 0;
@ -1234,18 +1294,16 @@ static int handle_sock(void *key,
void *ctx) { void *ctx) {
patty_ax25_server *server = ctx; patty_ax25_server *server = ctx;
patty_ax25_sock *sock = value; patty_ax25_sock *sock = value;
patty_ax25_if *iface = sock->iface;
int fd = (int)(key - NULL), int fd = (int)(key - NULL);
fd_tnc = patty_kiss_tnc_fd(iface->tnc);
ssize_t len; ssize_t len;
if (!FD_ISSET(fd, &server->fds_r) || !FD_ISSET(fd_tnc, &server->fds_w)) { if (!FD_ISSET(fd, &server->fds_r)) {
goto done; goto done;
} }
if ((len = read(fd, iface->tx_buf, iface->tx_bufsz)) < 0) { if ((len = read(sock->fd, sock->buf, sock->bufsz)) < 0) {
goto error_io; goto error_io;
} else if (len == 0) { } else if (len == 0) {
clear_sock(server, sock); clear_sock(server, sock);
@ -1259,26 +1317,21 @@ static int handle_sock(void *key,
goto done; goto done;
} }
if ((len = patty_ax25_if_send(iface, iface->tx_buf, len)) < 0) { if (patty_ax25_sock_write(sock, PATTY_AX25_PROTO_NONE, sock->buf, len) < 0) {
goto error_io; goto error_sock_write;
} }
/*
* TODO: Finish this
*/
done: done:
return 0; return 0;
error_sock_write:
error_dict_delete: error_dict_delete:
error_io: error_io:
return -1; return -1;
} }
static int handle_socks(patty_ax25_server *server) { static int handle_socks(patty_ax25_server *server) {
return patty_dict_each(server->socks_established, return patty_dict_each(server->socks_by_fd, handle_sock, server);
handle_sock,
server);
} }
int patty_ax25_server_run(patty_ax25_server *server) { int patty_ax25_server_run(patty_ax25_server *server) {
@ -1299,10 +1352,6 @@ int patty_ax25_server_run(patty_ax25_server *server) {
goto error_io; goto error_io;
} }
if (accept_client(server) < 0) {
goto error_io;
}
if (handle_clients(server) < 0) { if (handle_clients(server) < 0) {
goto error_io; goto error_io;
} }
@ -1314,6 +1363,10 @@ int patty_ax25_server_run(patty_ax25_server *server) {
if (handle_socks(server) < 0) { if (handle_socks(server) < 0) {
goto error_io; goto error_io;
} }
if (accept_client(server) < 0) {
goto error_io;
}
} }
close(server->fd); close(server->fd);

View file

@ -1,10 +1,72 @@
#define _GNU_SOURCE
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <errno.h>
#include <patty/ax25.h> #include <patty/ax25.h>
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_sock_type type) { static int bind_pty(patty_ax25_sock *sock) {
struct termios t;
int pty;
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, sock->path, sizeof(sock->path)) < 0) {
goto error_ptsname_r;
}
/*if ((pty = open(sock->path, O_RDWR)) < 0) {
goto error_open_pty;
}*/
if (tcgetattr(sock->fd, &t) < 0) {
goto error_tcgetattr;
}
cfmakeraw(&t);
if (tcsetattr(sock->fd, TCSANOW, &t) < 0) {
goto error_tcsetattr;
}
//close(pty);
sock->opts |= PATTY_AX25_SOCK_PTY;
return 0;
error_tcsetattr:
error_tcgetattr:
//close(pty);
error_open_pty:
error_ptsname_r:
error_unlockpt:
error_grantpt:
close(sock->fd);
error_open:
return -1;
}
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_sock_opts opts) {
patty_ax25_sock *sock; patty_ax25_sock *sock;
if ((sock = malloc(sizeof(*sock))) == NULL) { if ((sock = malloc(sizeof(*sock))) == NULL) {
@ -13,19 +75,45 @@ patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_sock_type type) {
memset(sock, '\0', sizeof(*sock)); memset(sock, '\0', sizeof(*sock));
if ((sock->buf = malloc(PATTY_AX25_SOCK_BUFSZ)) == NULL) {
goto error_malloc_buf;
}
if (bind_pty(sock) < 0) {
goto error_bind_pty;
}
sock->bufsz = PATTY_AX25_SOCK_BUFSZ;
sock->status = PATTY_AX25_SOCK_CLOSED; sock->status = PATTY_AX25_SOCK_CLOSED;
sock->mode = PATTY_AX25_SOCK_DM; sock->mode = PATTY_AX25_SOCK_DM;
sock->type = type; sock->opts = opts;
sock->n_maxlen = PATTY_AX25_FRAME_DEFAULT_MAXLEN; sock->n_maxlen = PATTY_AX25_FRAME_DEFAULT_MAXLEN;
sock->n_window = PATTY_AX25_FRAME_DEFAULT_WINDOW; sock->n_window = PATTY_AX25_FRAME_DEFAULT_WINDOW;
return sock; return sock;
error_bind_pty:
free(sock->buf);
error_malloc_buf:
free(sock);
error_malloc_sock: error_malloc_sock:
return NULL; return NULL;
} }
void patty_ax25_sock_reset(patty_ax25_sock *sock) {
sock->opts &= ~PATTY_AX25_SOCK_PTY;
sock->status = PATTY_AX25_SOCK_CLOSED;
sock->mode = PATTY_AX25_SOCK_DM;
}
void patty_ax25_sock_destroy(patty_ax25_sock *sock) { void patty_ax25_sock_destroy(patty_ax25_sock *sock) {
if (sock->fd) {
close(sock->fd);
}
free(sock->buf);
free(sock); free(sock);
} }
@ -75,7 +163,7 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
uint8_t proto, uint8_t proto,
void *info, void *info,
size_t infolen) { size_t infolen) {
size_t offset = 0; size_t offset;
if (toobig(sock, control, infolen)) { if (toobig(sock, control, infolen)) {
goto error_toobig; goto error_toobig;
@ -86,8 +174,12 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
if (sock->mode == PATTY_AX25_SOCK_SABME) { if (sock->mode == PATTY_AX25_SOCK_SABME) {
((uint8_t *)sock->iface->tx_buf)[offset++] = (control & 0xff00) >> 8; ((uint8_t *)sock->iface->tx_buf)[offset++] = (control & 0xff00) >> 8;
((uint8_t *)sock->iface->tx_buf)[offset++] = control & 0x00ff; ((uint8_t *)sock->iface->tx_buf)[offset++] = control & 0x00ff;
sock->seq_send = (sock->seq_send + 1) & 0x07;
} else { } else {
((uint8_t *)sock->iface->tx_buf)[offset++] = control; ((uint8_t *)sock->iface->tx_buf)[offset++] = control;
sock->seq_send = (sock->seq_send + 1) & 0x7f;
} }
if (PATTY_AX25_CONTROL_INFO(control)) { if (PATTY_AX25_CONTROL_INFO(control)) {
@ -97,7 +189,7 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
offset += infolen; offset += infolen;
} }
return offset; return patty_ax25_if_send(sock->iface, sock->iface->tx_buf, offset);
error_toobig: error_toobig:
return -1; return -1;
@ -112,13 +204,46 @@ ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int poll) {
0); 0);
} }
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int poll) {
return patty_ax25_sock_send(sock,
PATTY_AX25_FRAME_U_SABME
| PATTY_AX25_FRAME_U_POLL,
PATTY_AX25_PROTO_NONE,
NULL,
0);
}
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int poll) {
return patty_ax25_sock_send(sock,
PATTY_AX25_FRAME_U_DISC
| PATTY_AX25_FRAME_U_POLL,
PATTY_AX25_PROTO_NONE,
NULL,
0);
}
ssize_t patty_ax25_sock_write(patty_ax25_sock *sock, ssize_t patty_ax25_sock_write(patty_ax25_sock *sock,
uint8_t proto, uint8_t proto,
void *buf, void *buf,
size_t len) { size_t len) {
uint16_t control = sock->mode == PATTY_AX25_SOCK_SABME? uint16_t control = 0x0000;
PATTY_AX25_SOCK_CONTROL_SABME(sock, 1):
PATTY_AX25_SOCK_CONTROL_SABM(sock, 1); switch (sock->mode) {
case PATTY_AX25_SOCK_DM:
errno = EBADF;
goto error_invalid_mode;
case PATTY_AX25_SOCK_SABM:
control = PATTY_AX25_SOCK_CONTROL_SABM(sock, 1);
break;
case PATTY_AX25_SOCK_SABME:
control = PATTY_AX25_SOCK_CONTROL_SABME(sock, 1);
break;
}
if (patty_ax25_sock_send(sock, control, proto, buf, len) < 0) { if (patty_ax25_sock_send(sock, control, proto, buf, len) < 0) {
goto error_send; goto error_send;
@ -127,5 +252,6 @@ ssize_t patty_ax25_sock_write(patty_ax25_sock *sock,
return len; return len;
error_send: error_send:
error_invalid_mode:
return -1; return -1;
} }

View file

@ -29,17 +29,22 @@ static void usage(int argc, char **argv, const char *message, ...) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct sockaddr_un addr; struct sockaddr_un addr;
int fd, int fd,
sock; sock,
pty;
patty_ax25_addr peer; patty_ax25_addr peer;
char path[256]; char path[PATTY_AX25_SOCK_PATH_SIZE];
uint8_t buf[4096];
ssize_t readlen;
if (argc != 2) { if (argc != 2) {
usage(argc, argv, "No patty socket provided"); usage(argc, argv, "No patty socket provided");
} }
patty_ax25_pton("GB9BLM", 0, &peer); patty_ax25_pton("KZ3ROX", 0, &peer);
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n", fprintf(stderr, "%s: %s: %s: %s\n",
@ -56,27 +61,46 @@ int main(int argc, char **argv) {
goto error_connect; goto error_connect;
} }
if ((sock = patty_ax25_call_socket(fd, PATTY_AX25_SOCK_PTY)) < 0) { if ((sock = patty_ax25_call_socket(fd, PATTY_AX25_SOCK_NONE, path, PATTY_AX25_SOCK_PATH_SIZE)) < 0) {
fprintf(stderr, "%s: %s: %s\n", fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_call_socket()", strerror(errno)); argv[0], "patty_ax25_call_socket()", strerror(errno));
goto error_call_socket; goto error_call_socket;
} }
if (patty_ax25_call_connect(fd, sock, &peer, path) < 0) { if (patty_ax25_call_connect(fd, sock, &peer) < 0) {
fprintf(stderr, "%s: %s: %s\n", fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_call_connect()", strerror(errno)); argv[0], "patty_ax25_call_connect()", strerror(errno));
goto error_call_close; goto error_call_connect;
} }
fprintf(stderr, "connected sock %d\n", sock); if ((pty = open(path, O_RDWR)) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], path, "open()", strerror(errno));
goto error_open_pty;
}
while ((readlen = read(pty, buf, sizeof(buf))) > 0) {
if (write(1, buf, readlen) < 0) {
goto error_write;
}
}
close(pty);
patty_ax25_call_close(fd, sock);
close(fd); close(fd);
return 0; return 0;
error_call_close: error_write:
error_open_pty:
error_call_connect:
patty_ax25_call_close(fd, sock);
error_call_socket: error_call_socket:
close(fd); close(fd);

129
src/testclient-listen.c Normal file
View file

@ -0,0 +1,129 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <fcntl.h>
#include <errno.h>
#include <patty/ax25.h>
extern char **environ;
static void usage(int argc, char **argv, const char *message, ...) {
if (message != NULL) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
fprintf(stderr, "\n");
va_end(args);
}
fprintf(stderr, "usage: %s /var/run/patty/patty.sock\n", argv[0]);
exit(1);
}
int main(int argc, char **argv) {
struct sockaddr_un unix_addr;
int fd,
local,
remote,
pty;
patty_ax25_addr addr,
peer;
char path[PATTY_AX25_SOCK_PATH_SIZE];
if (argc != 2) {
usage(argc, argv, "No patty socket provided");
}
patty_ax25_pton("KZ3ROX", 0, &addr);
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "socket()", argv[1], strerror(errno));
goto error_socket;
}
memset(&unix_addr, '\0', sizeof(unix_addr));
unix_addr.sun_family = AF_UNIX;
strncpy(unix_addr.sun_path, argv[1], sizeof(unix_addr.sun_path));
if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {
goto error_connect;
}
if ((local = patty_ax25_call_socket(fd, PATTY_AX25_SOCK_NONE, NULL, 0)) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_call_socket()", strerror(errno));
goto error_call_socket;
}
if (patty_ax25_call_bind(fd, local, &addr) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_call_connect()", strerror(errno));
goto error_call_bind;
}
if (patty_ax25_call_listen(fd, local) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_call_listen()", strerror(errno));
goto error_call_listen;
}
if ((remote = patty_ax25_call_accept(fd, local, &peer, path, sizeof(path))) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_call_accept()", strerror(errno));
goto error_call_accept;
}
if ((pty = open(path, O_RDWR)) < 0) {
goto error_open_pty;
}
if (write(pty, "hello world\n", 12) < 0) {
goto error_write;
}
close(pty);
patty_ax25_call_close(fd, remote);
patty_ax25_call_close(fd, local);
close(fd);
return 0;
error_write:
close(pty);
error_open_pty:
patty_ax25_call_close(fd, remote);
error_call_accept:
error_call_listen:
error_call_bind:
patty_ax25_call_close(fd, local);
error_call_socket:
error_connect:
close(fd);
error_socket:
return 1;
}