Implement new patty client code
Implement new patty client code, replacing src/call.c with src/client.c
providing clients with an interface dealing with file descriptors valid
in their process space; this also obviates the need to open a Unix
domain socket to a patty server explicitly, and helps keep track of
sockets opened on the server, locally
Changes:
* Implement patty_client_new() to handle opening the server Unix
domain socket, and to allocate a dict for mapping server-side
sockets with current process file descriptors
* Reimplement all server calls in src/call.c around the new
patty_client type; calls which result in the creation of a
Unix98 PTY by the patty server now handle opening the local PTY
and setting the file descriptor to raw mode. Furthermore, these
calls deal exclusively in terms of current process file
descriptors
* Refactor src/server.c to use the new patty_client type and calls
* Refactor examples/client.c, examples/server.c, examples/ax25dump.c
to use the new patty_client type and calls
* Fix a bug in src/server.c, respond_accept() wherein a 0, rather
than the file descriptor of the socket, is sent to the client as a
return value
2020-08-01 20:21:01 -04:00
|
|
|
#define _GNU_SOURCE
|
2015-07-14 22:27:42 -05:00
|
|
|
#include <stdlib.h>
|
2015-07-16 00:31:27 +00:00
|
|
|
#include <string.h>
|
2020-05-26 23:41:39 -04:00
|
|
|
#include <inttypes.h>
|
2015-07-14 22:27:42 -05:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2020-07-26 16:34:15 -04:00
|
|
|
#include <termios.h>
|
2015-07-14 16:45:03 +00:00
|
|
|
#include <sys/types.h>
|
2015-07-14 22:27:42 -05:00
|
|
|
#include <sys/stat.h>
|
2020-07-19 23:36:35 -04:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2015-07-14 16:45:03 +00:00
|
|
|
#include <errno.h>
|
|
|
|
|
2015-07-12 02:16:26 -05:00
|
|
|
#include <patty/kiss.h>
|
|
|
|
|
|
|
|
enum kiss_flags {
|
2020-05-27 18:17:00 -04:00
|
|
|
KISS_NONE = 0,
|
|
|
|
KISS_FRAME = 1 << 0,
|
|
|
|
KISS_COMMAND = 1 << 1,
|
|
|
|
KISS_ESCAPE = 1 << 2
|
2015-07-12 02:16:26 -05:00
|
|
|
};
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
enum tnc_opts {
|
|
|
|
TNC_NONE = 0,
|
|
|
|
TNC_CLOSE_ON_DESTROY = 1 << 0
|
|
|
|
};
|
|
|
|
|
2015-07-14 22:27:42 -05:00
|
|
|
struct _patty_kiss_tnc {
|
2020-07-26 16:34:15 -04:00
|
|
|
struct termios attrs,
|
|
|
|
attrs_old;
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
int fd,
|
|
|
|
opts;
|
2020-05-26 23:52:06 -04:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
void *buf,
|
|
|
|
*frame;
|
2020-05-26 23:52:06 -04:00
|
|
|
|
|
|
|
size_t bufsz,
|
2020-05-28 17:53:26 -04:00
|
|
|
offset,
|
2020-05-26 23:52:06 -04:00
|
|
|
dropped;
|
2020-05-28 17:53:26 -04:00
|
|
|
|
2020-05-29 00:11:54 -04:00
|
|
|
ssize_t readlen;
|
2015-07-14 22:27:42 -05:00
|
|
|
};
|
|
|
|
|
2020-08-05 00:48:58 -04:00
|
|
|
static inline ssize_t write_byte(int fd, uint8_t c) {
|
|
|
|
return write(fd, &c, sizeof(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline ssize_t write_start(int fd,
|
|
|
|
enum patty_kiss_command command,
|
|
|
|
int port) {
|
|
|
|
uint8_t start[2] = {
|
|
|
|
PATTY_KISS_FEND,
|
|
|
|
((port & 0x0f) << 4) | (command & 0x0f)
|
|
|
|
};
|
|
|
|
|
|
|
|
return write(fd, start, sizeof(start));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t escape_fend[2] = { PATTY_KISS_FESC, PATTY_KISS_TFEND };
|
|
|
|
static uint8_t escape_fesc[2] = { PATTY_KISS_FESC, PATTY_KISS_TFESC };
|
|
|
|
|
|
|
|
ssize_t patty_kiss_frame_send(int fd,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
|
|
|
int port) {
|
|
|
|
size_t i, start = 0, end = 0;
|
|
|
|
|
|
|
|
if (write_start(fd, PATTY_KISS_DATA, port) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
uint8_t c = ((uint8_t *)buf)[i];
|
|
|
|
uint8_t *escape = NULL;
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case PATTY_KISS_FEND:
|
|
|
|
escape = escape_fend;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PATTY_KISS_FESC:
|
|
|
|
escape = escape_fesc;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
end = i + 1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (escape) {
|
|
|
|
if (write(fd, ((uint8_t *)buf) + start, end - start) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write(fd, escape, 2) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
escape = NULL;
|
|
|
|
start = i + 1;
|
|
|
|
end = start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end - start) {
|
|
|
|
if (write(fd, ((uint8_t *)buf) + start, end - start) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write_byte(fd, PATTY_KISS_FEND) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd) {
|
2015-07-14 22:27:42 -05:00
|
|
|
patty_kiss_tnc *tnc;
|
|
|
|
|
|
|
|
if ((tnc = malloc(sizeof(*tnc))) == NULL) {
|
|
|
|
goto error_malloc_tnc;
|
|
|
|
}
|
|
|
|
|
2020-05-27 22:22:42 -04:00
|
|
|
if ((tnc->buf = malloc(PATTY_KISS_BUFSZ)) == NULL) {
|
2015-07-14 22:27:42 -05:00
|
|
|
goto error_malloc_buf;
|
|
|
|
}
|
|
|
|
|
2020-08-01 20:13:48 -04:00
|
|
|
if (isatty(fd) && ptsname(fd) == NULL) {
|
2020-07-30 01:34:43 -04:00
|
|
|
if (tcgetattr(fd, &tnc->attrs) < 0) {
|
|
|
|
goto error_tcgetattr;
|
|
|
|
}
|
2020-07-26 16:34:15 -04:00
|
|
|
|
2020-07-30 01:34:43 -04:00
|
|
|
memcpy(&tnc->attrs_old, &tnc->attrs, sizeof(tnc->attrs_old));
|
2020-07-26 16:34:15 -04:00
|
|
|
|
2020-07-30 01:34:43 -04:00
|
|
|
cfmakeraw(&tnc->attrs);
|
2020-07-26 16:34:15 -04:00
|
|
|
|
2020-07-30 01:34:43 -04:00
|
|
|
if (tcsetattr(fd, TCSANOW, &tnc->attrs) < 0) {
|
|
|
|
goto error_tcsetattr;
|
|
|
|
}
|
2020-07-26 16:34:15 -04:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:16:25 -04:00
|
|
|
tnc->fd = fd;
|
2020-06-26 22:44:19 -04:00
|
|
|
tnc->opts = TNC_NONE;
|
2020-05-29 00:11:54 -04:00
|
|
|
tnc->bufsz = PATTY_KISS_BUFSZ;
|
|
|
|
tnc->offset = 0;
|
|
|
|
tnc->dropped = 0;
|
|
|
|
tnc->readlen = -1;
|
2015-07-14 22:27:42 -05:00
|
|
|
|
|
|
|
return tnc;
|
|
|
|
|
2020-07-26 16:34:15 -04:00
|
|
|
error_tcsetattr:
|
|
|
|
error_tcgetattr:
|
2015-07-14 22:27:42 -05:00
|
|
|
error_malloc_buf:
|
|
|
|
free(tnc);
|
|
|
|
|
|
|
|
error_malloc_tnc:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
patty_kiss_tnc *patty_kiss_tnc_new(const char *device) {
|
2020-05-27 18:35:23 -04:00
|
|
|
patty_kiss_tnc *tnc;
|
|
|
|
int fd;
|
2020-07-19 23:36:35 -04:00
|
|
|
struct stat st;
|
2020-05-27 18:35:23 -04:00
|
|
|
|
2020-07-19 23:36:35 -04:00
|
|
|
if (stat(device, &st) < 0) {
|
|
|
|
goto error_stat;
|
|
|
|
}
|
|
|
|
|
2020-07-23 01:43:25 -04:00
|
|
|
if ((st.st_mode & S_IFMT) == S_IFSOCK) {
|
2020-07-19 23:36:35 -04:00
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
|
|
|
if (strlen(device) > sizeof(addr.sun_path)) {
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
|
|
|
goto error_overflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
|
|
goto error_socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&addr, '\0', sizeof(addr));
|
|
|
|
addr.sun_family = AF_UNIX;
|
2020-08-07 17:59:16 -04:00
|
|
|
strncpy(addr.sun_path, device, sizeof(addr.sun_path)-1);
|
2020-07-19 23:36:35 -04:00
|
|
|
|
|
|
|
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
|
|
goto error_connect;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((fd = open(device, O_RDWR)) < 0) {
|
|
|
|
goto error_open;
|
|
|
|
}
|
2020-05-27 18:35:23 -04:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
if ((tnc = patty_kiss_tnc_new_fd(fd)) == NULL) {
|
|
|
|
goto error_tnc_new_fd;
|
2020-05-27 18:35:23 -04:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
tnc->opts |= TNC_CLOSE_ON_DESTROY;
|
|
|
|
|
2020-05-27 18:35:23 -04:00
|
|
|
return tnc;
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
error_tnc_new_fd:
|
2020-07-19 23:36:35 -04:00
|
|
|
error_connect:
|
2020-05-27 18:35:23 -04:00
|
|
|
close(fd);
|
|
|
|
|
2020-07-19 23:36:35 -04:00
|
|
|
error_socket:
|
|
|
|
error_overflow:
|
2020-05-27 18:35:23 -04:00
|
|
|
error_open:
|
2020-07-19 23:36:35 -04:00
|
|
|
error_stat:
|
2020-05-27 18:35:23 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-28 17:57:07 -04:00
|
|
|
int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) {
|
2015-07-29 22:28:44 -05:00
|
|
|
return tnc->fd;
|
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc) {
|
2020-08-02 01:11:53 -04:00
|
|
|
if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) {
|
|
|
|
(void)tcsetattr(tnc->fd, TCSANOW, &tnc->attrs_old);
|
|
|
|
}
|
2020-07-26 16:34:15 -04:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
if (tnc->opts & TNC_CLOSE_ON_DESTROY) {
|
|
|
|
close(tnc->fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(tnc->buf);
|
|
|
|
free(tnc);
|
2015-07-14 22:27:42 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
static void tnc_drop(patty_kiss_tnc *tnc) {
|
2020-05-29 00:11:54 -04:00
|
|
|
tnc->offset = 0;
|
|
|
|
tnc->readlen = -1;
|
2020-05-27 18:17:00 -04:00
|
|
|
tnc->dropped++;
|
|
|
|
}
|
2015-07-17 00:45:14 +00:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) {
|
|
|
|
return tnc->dropped;
|
|
|
|
}
|
2020-05-27 00:22:50 -04:00
|
|
|
|
2020-07-12 22:14:58 -04:00
|
|
|
ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc) {
|
|
|
|
if (tnc->readlen < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tnc->offset == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tnc->readlen - tnc->offset;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc,
|
2020-05-27 19:11:25 -04:00
|
|
|
void *buf,
|
|
|
|
size_t len,
|
2020-05-27 18:17:00 -04:00
|
|
|
int *port) {
|
2020-05-28 17:53:26 -04:00
|
|
|
size_t r = 0, /* Number of bytes read */
|
|
|
|
w = 0; /* Number of bytes written to buf */
|
2015-07-16 00:31:27 +00:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
enum kiss_flags flags = KISS_NONE;
|
2015-07-12 02:16:26 -05:00
|
|
|
|
2020-05-29 00:11:54 -04:00
|
|
|
if (tnc->offset == tnc->readlen) {
|
2020-06-26 22:44:19 -04:00
|
|
|
errno = 0;
|
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
return 0;
|
2020-05-27 18:17:00 -04:00
|
|
|
}
|
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
while (1) {
|
|
|
|
uint8_t c;
|
|
|
|
|
|
|
|
r++;
|
|
|
|
|
|
|
|
if (w == len) {
|
|
|
|
tnc_drop(tnc);
|
|
|
|
|
|
|
|
flags &= ~KISS_FRAME;
|
|
|
|
w = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tnc->offset == 0) {
|
|
|
|
if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
} else if (tnc->readlen == 0) {
|
|
|
|
if (errno) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c = ((uint8_t *)tnc->buf)[tnc->offset++];
|
|
|
|
|
2020-06-03 00:26:58 -04:00
|
|
|
if (tnc->offset == tnc->readlen) {
|
2020-05-28 17:53:26 -04:00
|
|
|
tnc->offset = 0;
|
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
|
|
|
|
if (!(flags & KISS_FRAME)) {
|
2015-07-12 02:16:26 -05:00
|
|
|
if (c == PATTY_KISS_FEND) {
|
|
|
|
flags |= KISS_FRAME;
|
2015-07-16 00:31:27 +00:00
|
|
|
|
|
|
|
continue;
|
2020-05-27 18:17:00 -04:00
|
|
|
} else {
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
goto error_io;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
} else {
|
|
|
|
if (c == PATTY_KISS_FEND) {
|
2020-05-28 17:53:26 -04:00
|
|
|
if (w > 0) {
|
2020-05-27 18:17:00 -04:00
|
|
|
flags &= ~KISS_FRAME;
|
2015-07-12 02:16:26 -05:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
goto done;
|
|
|
|
}
|
2015-07-16 00:31:27 +00:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
continue;
|
|
|
|
}
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
if (!(flags & KISS_COMMAND)) {
|
|
|
|
if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) {
|
2015-07-12 12:00:35 -05:00
|
|
|
errno = EIO;
|
|
|
|
|
2015-07-12 02:18:08 -05:00
|
|
|
goto error_io;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
|
|
|
|
2020-07-08 18:29:27 -04:00
|
|
|
if (port) {
|
|
|
|
*port = PATTY_KISS_COMMAND_PORT(c);
|
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
|
|
|
|
flags |= KISS_COMMAND;
|
2015-07-12 02:16:26 -05:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
if (!(flags & KISS_ESCAPE)) {
|
2015-07-12 02:16:26 -05:00
|
|
|
if (c == PATTY_KISS_FESC) {
|
|
|
|
flags |= KISS_ESCAPE;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
} else {
|
|
|
|
switch (c) {
|
|
|
|
case PATTY_KISS_TFEND:
|
2020-05-28 17:53:26 -04:00
|
|
|
((uint8_t *)buf)[w++] = PATTY_KISS_FEND;
|
2020-05-27 18:17:00 -04:00
|
|
|
flags &= ~KISS_ESCAPE;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case PATTY_KISS_TFESC:
|
2020-05-28 17:53:26 -04:00
|
|
|
((uint8_t *)buf)[w++] = PATTY_KISS_FESC;
|
2020-05-27 18:17:00 -04:00
|
|
|
flags &= ~KISS_ESCAPE;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
default:
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
goto error_io;
|
|
|
|
}
|
2015-07-16 00:31:27 +00:00
|
|
|
}
|
2015-07-12 02:28:31 -05:00
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
((uint8_t *)buf)[w++] = c;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
done:
|
|
|
|
if (flags & KISS_FRAME) {
|
|
|
|
tnc_drop(tnc);
|
2020-05-28 17:53:26 -04:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
errno = 0;
|
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ssize_t)w;
|
2015-07-12 02:18:08 -05:00
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
2015-07-12 15:34:40 -05:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
|
|
|
int port) {
|
2020-08-05 00:48:58 -04:00
|
|
|
return patty_kiss_frame_send(tnc->fd, buf, len, port);
|
2015-07-12 15:34:40 -05:00
|
|
|
}
|