diff --git a/include/patty/ax25/call.h b/include/patty/ax25/call.h index b9da27e..0ed11fb 100644 --- a/include/patty/ax25/call.h +++ b/include/patty/ax25/call.h @@ -18,16 +18,19 @@ enum patty_ax25_call { * socket() */ typedef struct _patty_ax25_call_socket_request { - int type; + int opts; } patty_ax25_call_socket_request; typedef struct _patty_ax25_response_socket { int ret; int eno; + char path[PATTY_AX25_SOCK_PATH_SIZE]; } patty_ax25_call_socket_response; int patty_ax25_call_socket(int server, - int type); + int opts, + char *path, + size_t len); /* * bind() @@ -71,14 +74,15 @@ typedef struct _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; + char path[PATTY_AX25_SOCK_PATH_SIZE]; } patty_ax25_call_accept_response; int patty_ax25_call_accept(int server, int socket, patty_ax25_addr *peer, - char *path); + char *path, + size_t len); /* * connect() @@ -91,13 +95,11 @@ typedef struct _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); + patty_ax25_addr *peer); /* * close() diff --git a/include/patty/ax25/macros.h b/include/patty/ax25/macros.h index 426afc7..e6e4ec0 100644 --- a/include/patty/ax25/macros.h +++ b/include/patty/ax25/macros.h @@ -56,7 +56,7 @@ (((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x0f)) #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) \ (((c & 0xe0) == 0x40) && ((c & 0x0f) == 0x07)) diff --git a/include/patty/ax25/sock.h b/include/patty/ax25/sock.h index 1022e9f..3fd39a3 100644 --- a/include/patty/ax25/sock.h +++ b/include/patty/ax25/sock.h @@ -1,12 +1,13 @@ #ifndef _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_UNIX = 1 << 0, - PATTY_AX25_SOCK_PTY = 1 << 1, - PATTY_AX25_SOCK_RAW = 1 << 2, - PATTY_AX25_SOCK_NONBLOCK = 1 << 3 + PATTY_AX25_SOCK_PTY = 1 << 0, + PATTY_AX25_SOCK_RAW = 1 << 1, + PATTY_AX25_SOCK_NONBLOCK = 1 << 2 }; enum patty_ax25_sock_status { @@ -24,7 +25,7 @@ enum patty_ax25_sock_mode { }; 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_mode mode; @@ -42,6 +43,9 @@ typedef struct _patty_ax25_sock { int fd; char path[PATTY_AX25_SOCK_PATH_SIZE]; + void *buf; + size_t bufsz; + patty_ax25_if *iface; patty_ax25_addr local, @@ -52,7 +56,7 @@ typedef struct _patty_ax25_sock { } patty_ax25_sock; #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) \ (((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_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); +char *patty_ax25_sock_pty(patty_ax25_sock *sock); + ssize_t patty_ax25_sock_send(patty_ax25_sock *sock, uint16_t control, 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_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, uint8_t proto, void *buf, diff --git a/src/Makefile b/src/Makefile index 2b529f7..d793e9a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 \ 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)) diff --git a/src/call.c b/src/call.c index 5cb7cf5..ef9c8c1 100644 --- a/src/call.c +++ b/src/call.c @@ -6,11 +6,13 @@ #include 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; patty_ax25_call_socket_request request = { - type + opts }; patty_ax25_call_socket_response response; @@ -27,6 +29,10 @@ int patty_ax25_call_socket(int server, goto error_io; } + if (path) { + strncpy(path, response.path, len); + } + errno = response.eno; return response.ret; @@ -101,7 +107,8 @@ error_io: int patty_ax25_call_accept(int server, int socket, patty_ax25_addr *peer, - char *path) { + char *path, + size_t len) { enum patty_ax25_call call = PATTY_AX25_CALL_ACCEPT; patty_ax25_call_accept_request request = { @@ -110,6 +117,8 @@ int patty_ax25_call_accept(int server, patty_ax25_call_accept_response response; + memset(&response, '\0', sizeof(response)); + if (write(server, &call, sizeof(call)) < 0) { goto error_io; } @@ -123,8 +132,11 @@ int patty_ax25_call_accept(int server, } if (response.ret >= 0) { - strncpy(path, response.path, PATTY_AX25_SOCK_PATH_SIZE); memcpy(peer, &response.peer, sizeof(*peer)); + + if (path) { + strncpy(path, response.path, len); + } } errno = response.eno; @@ -137,8 +149,7 @@ error_io: int patty_ax25_call_connect(int server, int socket, - patty_ax25_addr *peer, - char *path) { + patty_ax25_addr *peer) { enum patty_ax25_call call = PATTY_AX25_CALL_CONNECT; patty_ax25_call_connect_request request = { @@ -161,10 +172,6 @@ int patty_ax25_call_connect(int server, goto error_io; } - if (response.ret >= 0) { - strncpy(path, response.path, PATTY_AX25_SOCK_PATH_SIZE); - } - errno = response.eno; return response.ret; diff --git a/src/server.c b/src/server.c index f38e5d5..4a33011 100644 --- a/src/server.c +++ b/src/server.c @@ -23,8 +23,6 @@ struct _patty_ax25_server { 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 */ @@ -126,31 +124,18 @@ static patty_ax25_sock *sock_by_fd(patty_dict *dict, static patty_ax25_sock *sock_by_addr(patty_dict *dict, patty_ax25_addr *addr) { - patty_dict_slot *slot; - uint32_t hash; patty_hash_init(&hash); patty_ax25_addr_hash(&hash, addr); patty_hash_end(&hash); - if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { - errno = EEXIST; - - goto error_dict_slot_find; - } - - return (patty_ax25_sock *)slot->value; - -error_dict_slot_find: - return NULL; + return patty_dict_get_with_hash(dict, hash); } static patty_ax25_sock *sock_by_addrpair(patty_dict *dict, patty_ax25_addr *local, patty_ax25_addr *remote) { - patty_dict_slot *slot; - uint32_t 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_hash_end(&hash); - if ((slot = patty_dict_slot_find(dict, hash)) == NULL) { - errno = EEXIST; - - goto error_dict_slot_find; - } - - return (patty_ax25_sock *)slot->value; - -error_dict_slot_find: - return NULL; + return patty_dict_get_with_hash(dict, hash); } 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) { 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) { 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, @@ -469,17 +429,10 @@ static int server_socket(patty_ax25_server *server, 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; } - 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) { response.ret = -1; response.eno = errno; @@ -487,17 +440,28 @@ static int server_socket(patty_ax25_server *server, 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) { goto error_write; } return 0; +error_dict_set_with_hash: +error_sock_save_by_fd: error_write: - close(sock->fd); - -error_open: patty_ax25_sock_destroy(sock); error_sock_new: @@ -593,132 +557,30 @@ 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; - } - - 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, int client) { patty_ax25_call_accept_request request; patty_ax25_call_accept_response response; - patty_ax25_sock *local, - *remote; + patty_ax25_sock *sock; if (read(client, &request, sizeof(request)) < 0) { 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.eno = EBADF; 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, - remote, - &local->local) < 0) { + sock, + &sock->local) < 0) { goto error_save_by_addr; } - if (sock_save_by_fd(server->socks_by_fd, remote) < 0) { - goto error_save_by_fd; - } - return 0; error_sock_by_fd: @@ -728,13 +590,7 @@ error_sock_by_fd: return 0; -error_save_by_fd: error_save_by_addr: -error_server_accept_unix: -error_server_accept_pty: - patty_ax25_sock_destroy(remote); - -error_sock_new_remote: error_io: return -1; } @@ -828,6 +684,14 @@ static int server_connect(patty_ax25_server *server, 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. * 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; } - return 0; + return 0; error_sock_send_sabm: error_network_down: @@ -853,6 +717,7 @@ error_sock_by_fd: return 0; +error_dict_set_with_hash: error_sock_save_by_addrpair: error_io: return -1; @@ -984,7 +849,7 @@ static int accept_client(patty_ax25_server *server) { goto error_dict_set; } - watch_client(server, fd); + watch_fd(server, fd); done: return 0; @@ -1013,7 +878,7 @@ static int handle_client(void *key, if ((readlen = read(client, &call, sizeof(call))) < 0) { goto error_io; } else if (readlen == 0) { - clear_client(server, client); + clear_fd(server, client); if (patty_dict_delete_with_hash(server->clients, (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? 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; irepeaters[i], @@ -1112,40 +978,228 @@ static int reply_ua(patty_ax25_if *iface, .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); } static int handle_sabm(patty_ax25_server *server, patty_ax25_if *iface, 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, - &frame->dest)) == NULL) { + if ((local = sock_by_addr(server->socks_pending_accept, + &frame->dest)) == NULL) { 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->mode = PATTY_AX25_SOCK_SABM; - save_reply_addr(sock, frame); - if (sock_save_by_addrpair(server->socks_established, - sock, + sock, &sock->local, &sock->remote) < 0) { goto error_save_by_addrpair; } - if (sock_delete_by_addr(server->socks_pending_accept, - &frame->dest) < 0) { - goto error_delete_by_addr; + if (sock_delete_by_addrpair(server->socks_pending_connect, + &sock->local, + &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_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; } @@ -1166,6 +1220,12 @@ static int handle_frame(patty_ax25_server *server, if (PATTY_AX25_CONTROL_UNNUMBERED_SABM(frame.control)) { 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; @@ -1234,18 +1294,16 @@ static int handle_sock(void *key, void *ctx) { patty_ax25_server *server = ctx; patty_ax25_sock *sock = value; - patty_ax25_if *iface = sock->iface; - int fd = (int)(key - NULL), - fd_tnc = patty_kiss_tnc_fd(iface->tnc); + int fd = (int)(key - NULL); 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; } - if ((len = read(fd, iface->tx_buf, iface->tx_bufsz)) < 0) { + if ((len = read(sock->fd, sock->buf, sock->bufsz)) < 0) { goto error_io; } else if (len == 0) { clear_sock(server, sock); @@ -1259,26 +1317,21 @@ static int handle_sock(void *key, goto done; } - if ((len = patty_ax25_if_send(iface, iface->tx_buf, len)) < 0) { - goto error_io; + if (patty_ax25_sock_write(sock, PATTY_AX25_PROTO_NONE, sock->buf, len) < 0) { + goto error_sock_write; } - /* - * TODO: Finish this - */ - done: return 0; +error_sock_write: error_dict_delete: error_io: return -1; } static int handle_socks(patty_ax25_server *server) { - return patty_dict_each(server->socks_established, - handle_sock, - server); + return patty_dict_each(server->socks_by_fd, handle_sock, 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; } - if (accept_client(server) < 0) { - goto error_io; - } - if (handle_clients(server) < 0) { goto error_io; } @@ -1314,6 +1363,10 @@ int patty_ax25_server_run(patty_ax25_server *server) { if (handle_socks(server) < 0) { goto error_io; } + + if (accept_client(server) < 0) { + goto error_io; + } } close(server->fd); diff --git a/src/sock.c b/src/sock.c index 8d4d616..3886109 100644 --- a/src/sock.c +++ b/src/sock.c @@ -1,10 +1,72 @@ +#define _GNU_SOURCE #include #include #include +#include +#include +#include +#include +#include +#include +#include #include -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; 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)); + 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->mode = PATTY_AX25_SOCK_DM; - sock->type = type; + sock->opts = opts; sock->n_maxlen = PATTY_AX25_FRAME_DEFAULT_MAXLEN; sock->n_window = PATTY_AX25_FRAME_DEFAULT_WINDOW; return sock; +error_bind_pty: + free(sock->buf); + +error_malloc_buf: + free(sock); + error_malloc_sock: 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) { + if (sock->fd) { + close(sock->fd); + } + + free(sock->buf); free(sock); } @@ -75,7 +163,7 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock, uint8_t proto, void *info, size_t infolen) { - size_t offset = 0; + size_t offset; if (toobig(sock, control, infolen)) { goto error_toobig; @@ -86,8 +174,12 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock, 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 & 0x00ff; + + sock->seq_send = (sock->seq_send + 1) & 0x07; } else { ((uint8_t *)sock->iface->tx_buf)[offset++] = control; + + sock->seq_send = (sock->seq_send + 1) & 0x7f; } if (PATTY_AX25_CONTROL_INFO(control)) { @@ -97,7 +189,7 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock, offset += infolen; } - return offset; + return patty_ax25_if_send(sock->iface, sock->iface->tx_buf, offset); error_toobig: return -1; @@ -112,13 +204,46 @@ ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int poll) { 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, uint8_t proto, void *buf, size_t len) { - uint16_t control = sock->mode == PATTY_AX25_SOCK_SABME? - PATTY_AX25_SOCK_CONTROL_SABME(sock, 1): - PATTY_AX25_SOCK_CONTROL_SABM(sock, 1); + uint16_t control = 0x0000; + + 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) { goto error_send; @@ -127,5 +252,6 @@ ssize_t patty_ax25_sock_write(patty_ax25_sock *sock, return len; error_send: +error_invalid_mode: return -1; } diff --git a/src/testclient.c b/src/testclient-connect.c similarity index 65% rename from src/testclient.c rename to src/testclient-connect.c index 0167d44..c4fd485 100644 --- a/src/testclient.c +++ b/src/testclient-connect.c @@ -29,17 +29,22 @@ static void usage(int argc, char **argv, const char *message, ...) { int main(int argc, char **argv) { struct sockaddr_un addr; + int fd, - sock; + sock, + pty; patty_ax25_addr peer; - char path[256]; + char path[PATTY_AX25_SOCK_PATH_SIZE]; + + uint8_t buf[4096]; + ssize_t readlen; if (argc != 2) { 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) { fprintf(stderr, "%s: %s: %s: %s\n", @@ -56,27 +61,46 @@ int main(int argc, char **argv) { 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", argv[0], "patty_ax25_call_socket()", strerror(errno)); 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", 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); return 0; -error_call_close: +error_write: +error_open_pty: +error_call_connect: + patty_ax25_call_close(fd, sock); + error_call_socket: close(fd); diff --git a/src/testclient-listen.c b/src/testclient-listen.c new file mode 100644 index 0000000..577e173 --- /dev/null +++ b/src/testclient-listen.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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; +}