Implement bin/pattyd.c
Changes: * Implement src/conf.c, patty_conf_read(), to read a configuration file to support a OpenBSD-style configuration file format * Implement bin/pattyd.c to use patty_conf_read() to read a configuration file and apply its settings to a patty_daemon object as it is read; also implement a --standalone|-s flag to allow the user to start a patty server without having to write a configuration file * Refactor patty_daemon_if_add() to accept a patty_ax25_if object; this is necessary as bin/pattyd.c needs to be able to validate the addresses given in a configuration file 'if' statement * Refactor patty_ax25_server_new() to no longer accept a client socket path; instead, patty_ax25_server_start() now accepts the client socket path * Remove the client socket 'path' member from patty_ax25_server in src/server.c * Refactor patty_kiss_tnc_new() to accept only one argument, a patty_kiss_tnc_info object containing flags and settings needed to open a device, use an existing file descriptor, or change termios settings as appropriate * Remove patty_kiss_tnc_new_fd(), as its functionality now exists in patty_kiss_tnc_new() itself * Add a 'flags' field to patty_kiss_tnc_info; use this bit field to determine whether a path or file descriptor is provided by the caller * Make patty_ax25_if_new() accept an interface name argument, as names are explicitly required when declaring new interfaces in configuration files * Make patty_kiss_tnc_new() able to accept /dev/ptmx as a device name, regardless of whether this character device exists on a given platform; when provided, a pseudo TTY pair is allocated with openpty() * Refactor examples/ax25dump.c to use the new patty_kiss_tnc_new() calling convention * Refactor examples/decode.c to use the new patty_kiss_tnc_new() calling convention * Remove examples/daemon.c in favor of bin/pattyd.c * Rename examples/patty.conf to examples/pattyd.conf; modify to provide values which would actually function
This commit is contained in:
parent
b0e9ae6e0d
commit
639ec8beb7
21 changed files with 1127 additions and 339 deletions
2
Makefile
2
Makefile
|
@ -1,5 +1,6 @@
|
||||||
all:
|
all:
|
||||||
$(MAKE) -C src all
|
$(MAKE) -C src all
|
||||||
|
$(MAKE) -C bin all
|
||||||
$(MAKE) -C examples all
|
$(MAKE) -C examples all
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
@ -7,4 +8,5 @@ install:
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C src clean
|
$(MAKE) -C src clean
|
||||||
|
$(MAKE) -C bin clean
|
||||||
$(MAKE) -C examples clean
|
$(MAKE) -C examples clean
|
||||||
|
|
23
bin/Makefile
Normal file
23
bin/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
include ../mk/build.mk
|
||||||
|
|
||||||
|
CC = $(CROSS)cc
|
||||||
|
|
||||||
|
INCLUDE_PATH = ../include
|
||||||
|
|
||||||
|
CFLAGS += -I$(INCLUDE_PATH)
|
||||||
|
LDFLAGS = -L../src -lpatty
|
||||||
|
|
||||||
|
PROGRAMS = pattyd
|
||||||
|
|
||||||
|
OBJS = pattyd.o
|
||||||
|
|
||||||
|
all: $(PROGRAMS)
|
||||||
|
|
||||||
|
pattyd: pattyd.o
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
$(OBJS): %.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(PROGRAMS)
|
567
bin/pattyd.c
Normal file
567
bin/pattyd.c
Normal file
|
@ -0,0 +1,567 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <patty/ax25.h>
|
||||||
|
#include <patty/daemon.h>
|
||||||
|
#include <patty/conf.h>
|
||||||
|
|
||||||
|
#define DEFAULT_CONFIG_FILE "/etc/patty/pattyd.conf"
|
||||||
|
#define DEFAULT_IFNAME "kiss0"
|
||||||
|
|
||||||
|
static int 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 [-f] [-c pattyd.conf]\n"
|
||||||
|
" %s [-f] -s patty.sock MYCALL /dev/ttyXYZ [tioflags ...]\n",
|
||||||
|
argv[0], argv[0]);
|
||||||
|
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_sock(patty_daemon *daemon,
|
||||||
|
int lineno,
|
||||||
|
int argc,
|
||||||
|
char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Invalid arguments for 'sock' on line %d\n", lineno);
|
||||||
|
|
||||||
|
goto error_invalid_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_set_sock_path(daemon, argv[1]) < 0) {
|
||||||
|
fprintf(stderr, "Line %d: unable to set socket path to %s: %s",
|
||||||
|
lineno, argv[1], strerror(errno));
|
||||||
|
|
||||||
|
goto error_set_sock_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_set_sock_path:
|
||||||
|
error_invalid_args:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_pid(patty_daemon *daemon,
|
||||||
|
int lineno,
|
||||||
|
int argc,
|
||||||
|
char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Invalid arguments for 'sock' on line %d\n", lineno);
|
||||||
|
|
||||||
|
goto error_invalid_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_set_pidfile(daemon, argv[1]) < 0) {
|
||||||
|
fprintf(stderr, "Line %d: Unable to set pidfile to %s: %s",
|
||||||
|
lineno, argv[1], strerror(errno));
|
||||||
|
|
||||||
|
goto error_set_pidfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_set_pidfile:
|
||||||
|
error_invalid_args:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct if_context {
|
||||||
|
patty_daemon *daemon;
|
||||||
|
patty_ax25_addr addr;
|
||||||
|
patty_kiss_tnc_info info;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int handle_if_ax25(struct if_context *ctx,
|
||||||
|
int lineno,
|
||||||
|
char *opt,
|
||||||
|
char *value) {
|
||||||
|
if (patty_ax25_pton(value, &ctx->addr) < 0) {
|
||||||
|
fprintf(stderr, "Line %d: Invalid interface address '%s'\n",
|
||||||
|
lineno, value);
|
||||||
|
|
||||||
|
goto error_pton;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_pton:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_if_kiss(struct if_context *ctx,
|
||||||
|
int lineno,
|
||||||
|
char *opt,
|
||||||
|
char *value) {
|
||||||
|
ctx->info.flags |= PATTY_KISS_TNC_DEVICE;
|
||||||
|
ctx->info.device = value;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_if_baud(struct if_context *ctx,
|
||||||
|
int lineno,
|
||||||
|
char *opt,
|
||||||
|
char *value) {
|
||||||
|
ctx->info.flags |= PATTY_KISS_TNC_BAUD;
|
||||||
|
ctx->info.baud = atoi(value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_if_flow(struct if_context *ctx,
|
||||||
|
int lineno,
|
||||||
|
char *opt,
|
||||||
|
char *value) {
|
||||||
|
if (strcmp(value, "xonxoff") == 0) {
|
||||||
|
ctx->info.flow = PATTY_KISS_TNC_FLOW_XONXOFF;
|
||||||
|
} else if (strcmp(value, "crtscts") == 0) {
|
||||||
|
ctx->info.flow = PATTY_KISS_TNC_FLOW_CRTSCTS;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Line %d: Invalid flow control '%s'\n",
|
||||||
|
lineno, value);
|
||||||
|
|
||||||
|
goto error_invalid_flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->info.flags |= PATTY_KISS_TNC_FLOW;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_invalid_flow:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct if_opt_handler {
|
||||||
|
char *name;
|
||||||
|
int (*func)(struct if_context *, int, char *, char *);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct if_opt_handler if_opt_handlers[] = {
|
||||||
|
{ "ax25", handle_if_ax25 },
|
||||||
|
{ "kiss", handle_if_kiss },
|
||||||
|
{ "baud", handle_if_baud },
|
||||||
|
{ "flow", handle_if_flow },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int handle_if_opt(struct if_context *ctx,
|
||||||
|
int lineno,
|
||||||
|
char *opt,
|
||||||
|
char *value) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; if_opt_handlers[i].name; i++) {
|
||||||
|
if (strcmp(opt, if_opt_handlers[i].name) == 0) {
|
||||||
|
return if_opt_handlers[i].func(ctx, lineno, opt, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Line %d: Invalid interface option '%s'\n",
|
||||||
|
lineno, opt);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_if(patty_daemon *daemon,
|
||||||
|
int lineno,
|
||||||
|
int argc,
|
||||||
|
char **argv) {
|
||||||
|
char *name;
|
||||||
|
struct if_context ctx;
|
||||||
|
patty_ax25_if *iface;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "Line %d: No interface name provided\n", lineno);
|
||||||
|
|
||||||
|
goto error_no_ifname;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Line %d: No interface options provided\n", lineno);
|
||||||
|
|
||||||
|
goto error_no_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc % 2 != 0) {
|
||||||
|
fprintf(stderr, "Line %d: Invalid number of values provided\n", lineno);
|
||||||
|
|
||||||
|
goto error_invalid_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ctx, '\0', sizeof(ctx));
|
||||||
|
ctx.daemon = daemon;
|
||||||
|
|
||||||
|
name = argv[1];
|
||||||
|
|
||||||
|
for (i=2; i<argc; i+=2) {
|
||||||
|
char *opt = argv[i],
|
||||||
|
*value = argv[i+1];
|
||||||
|
|
||||||
|
if (handle_if_opt(&ctx, lineno, opt, value) < 0) {
|
||||||
|
goto error_handle_if_opt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((iface = patty_ax25_if_new(PATTY_AX25_IF_KISS_TNC,
|
||||||
|
name,
|
||||||
|
&ctx.info,
|
||||||
|
&ctx.addr)) == NULL) {
|
||||||
|
goto error_if_new;
|
||||||
|
} else {
|
||||||
|
int fd = patty_kiss_tnc_fd(iface->tnc);
|
||||||
|
char *pty;
|
||||||
|
|
||||||
|
if (isatty(fd) && (pty = ptsname(fd)) != NULL) {
|
||||||
|
printf("if %s pty %s\n", name, pty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_if_add(daemon, iface) < 0) {
|
||||||
|
fprintf(stderr, "Line %d: Unable to create interface %s: %s\n",
|
||||||
|
lineno, name, strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_if_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_daemon_if_add:
|
||||||
|
patty_ax25_if_destroy(iface);
|
||||||
|
|
||||||
|
error_if_new:
|
||||||
|
error_handle_if_opt:
|
||||||
|
error_invalid_values:
|
||||||
|
error_no_options:
|
||||||
|
error_no_ifname:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_route(patty_daemon *daemon,
|
||||||
|
int lineno,
|
||||||
|
int argc,
|
||||||
|
char **argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "Line %d: Invalid route declaration\n", lineno);
|
||||||
|
|
||||||
|
goto error_invalid_route;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "default") == 0) {
|
||||||
|
if (argc != 4 || strcmp(argv[2], "if") != 0) {
|
||||||
|
fprintf(stderr, "Line %d: Invalid default route declaration\n",
|
||||||
|
lineno);
|
||||||
|
|
||||||
|
goto error_invalid_route;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_route_add_default(daemon, argv[3]) < 0) {
|
||||||
|
fprintf(stderr, "Line %d: Unable to add default route for interface %s: %s\n",
|
||||||
|
lineno, argv[3], strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_route_add;
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[1], "station") == 0) {
|
||||||
|
if (argc < 7 || strcmp(argv[3], "if") != 0 || strcmp(argv[5], "path") != 0) {
|
||||||
|
fprintf(stderr, "Line %d: Invalid station route declaration\n",
|
||||||
|
lineno);
|
||||||
|
|
||||||
|
goto error_invalid_route;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_route_add(daemon,
|
||||||
|
argv[4],
|
||||||
|
argv[2],
|
||||||
|
(const char **)&argv[6],
|
||||||
|
argc - 6) < 0) {
|
||||||
|
fprintf(stderr, "Line %d: Unable to add route for interface %s: %s\n",
|
||||||
|
lineno, argv[4], strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_route_add;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Line %d: Invalid route type '%s'\n",
|
||||||
|
lineno, argv[1]);
|
||||||
|
|
||||||
|
goto error_invalid_route;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_daemon_route_add:
|
||||||
|
error_invalid_route:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct config_handler {
|
||||||
|
const char *name;
|
||||||
|
int (*func)(patty_daemon *, int, int, char **);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_handler handlers[] = {
|
||||||
|
{ "sock", handle_sock },
|
||||||
|
{ "pid", handle_pid },
|
||||||
|
{ "if", handle_if },
|
||||||
|
{ "route", handle_route },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int handle_config_line(patty_conf_file *file,
|
||||||
|
patty_list *line,
|
||||||
|
void *ctx) {
|
||||||
|
patty_daemon *daemon = ctx;
|
||||||
|
patty_list_item *item = line->first;
|
||||||
|
|
||||||
|
int argc = (int)line->length,
|
||||||
|
i = 0,
|
||||||
|
ret = 0,
|
||||||
|
lineno = 0;
|
||||||
|
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((argv = malloc((argc + 1) * sizeof(char *))) == NULL) {
|
||||||
|
goto error_malloc_argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (item) {
|
||||||
|
patty_conf_token *token = item->value;
|
||||||
|
|
||||||
|
if (lineno == 0) {
|
||||||
|
lineno = token->lineno;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[i++] = token->text;
|
||||||
|
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[argc] = NULL;
|
||||||
|
|
||||||
|
for (i=0; handlers[i].name; i++) {
|
||||||
|
if (strcmp(argv[0], handlers[i].name) == 0) {
|
||||||
|
ret = handlers[i].func(daemon, lineno, argc, argv);
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Unknown configuration value '%s'\n", argv[0]);
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
error_malloc_argv:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_simple_config(patty_daemon *daemon,
|
||||||
|
int argc,
|
||||||
|
char *argv0,
|
||||||
|
char **argv) {
|
||||||
|
patty_ax25_if *iface;
|
||||||
|
patty_ax25_addr addr;
|
||||||
|
|
||||||
|
patty_kiss_tnc_info info = {
|
||||||
|
.flags = PATTY_KISS_TNC_DEVICE,
|
||||||
|
.device = argv[2]
|
||||||
|
};
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=3; i<argc; i++) {
|
||||||
|
if (strcmp(argv[i], "crtscts") == 0) {
|
||||||
|
info.flags |= PATTY_KISS_TNC_FLOW;
|
||||||
|
info.flow = PATTY_KISS_TNC_FLOW_CRTSCTS;
|
||||||
|
} else if (strcmp(argv[i], "xonxoff") == 0) {
|
||||||
|
info.flags |= PATTY_KISS_TNC_FLOW;
|
||||||
|
info.flow = PATTY_KISS_TNC_FLOW_XONXOFF;
|
||||||
|
} else if (argv[i][0] >= '0' && argv[i][0] <= '9') {
|
||||||
|
int baud = atoi(argv[i]);
|
||||||
|
|
||||||
|
info.flags |= PATTY_KISS_TNC_BAUD;
|
||||||
|
info.baud = baud;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: Invalid device setting '%s'\n",
|
||||||
|
argv0, argv[i]);
|
||||||
|
|
||||||
|
goto error_invalid_device_setting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_set_sock_path(daemon, argv[0]) < 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to set socket path to %s: %s\n",
|
||||||
|
argv0, argv[0], strerror(errno));
|
||||||
|
|
||||||
|
goto error_set_sock_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_ax25_pton(argv[1], &addr) < 0) {
|
||||||
|
fprintf(stderr, "%s: Invalid callsign '%s'\n",
|
||||||
|
argv0, argv[1]);
|
||||||
|
|
||||||
|
goto error_invalid_callsign;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((iface = patty_ax25_if_new(PATTY_AX25_IF_KISS_TNC,
|
||||||
|
DEFAULT_IFNAME,
|
||||||
|
&info,
|
||||||
|
&addr)) == NULL) {
|
||||||
|
fprintf(stderr, "%s: Unable to create network interface %s: %s\n",
|
||||||
|
argv0, DEFAULT_IFNAME, strerror(errno));
|
||||||
|
|
||||||
|
goto error_if_new;
|
||||||
|
} else {
|
||||||
|
int fd = patty_kiss_tnc_fd(iface->tnc);
|
||||||
|
char *pty;
|
||||||
|
|
||||||
|
if (isatty(fd) && (pty = ptsname(fd)) != NULL) {
|
||||||
|
printf("if %s pty %s\n", DEFAULT_IFNAME, pty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_if_add(daemon, iface) < 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to add interface %s: %s\n",
|
||||||
|
argv0, DEFAULT_IFNAME, strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_if_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_route_add_default(daemon, DEFAULT_IFNAME) < 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to add default route to %s: %s\n",
|
||||||
|
argv0, DEFAULT_IFNAME, strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_route_add_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_daemon_route_add_default:
|
||||||
|
error_daemon_if_add:
|
||||||
|
error_if_new:
|
||||||
|
error_invalid_callsign:
|
||||||
|
error_invalid_device_setting:
|
||||||
|
error_set_sock_path:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum flags {
|
||||||
|
FLAG_FG,
|
||||||
|
FLAG_STANDALONE,
|
||||||
|
FLAG_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int ret = 0,
|
||||||
|
index,
|
||||||
|
ch,
|
||||||
|
flags[FLAG_COUNT];
|
||||||
|
|
||||||
|
struct option opts[] = {
|
||||||
|
{ "fg", no_argument, &flags[FLAG_FG], 1 },
|
||||||
|
{ "config", required_argument, NULL, 'c' },
|
||||||
|
{ "standalone", no_argument, &flags[FLAG_STANDALONE], 1 },
|
||||||
|
{ NULL, no_argument, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
char *config_file = DEFAULT_CONFIG_FILE;
|
||||||
|
|
||||||
|
patty_daemon *daemon;
|
||||||
|
|
||||||
|
memset(flags, '\0', sizeof(flags));
|
||||||
|
|
||||||
|
if ((daemon = patty_daemon_new()) == NULL) {
|
||||||
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
|
argv[0], "patty_daemon_new()", strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = getopt_long(argc, argv, "fc:s", opts, &index)) >= 0) {
|
||||||
|
switch (ch) {
|
||||||
|
case '?':
|
||||||
|
ret = usage(argc, argv, NULL);
|
||||||
|
goto error_invalid_args;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
config_file = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
flags[FLAG_STANDALONE] = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags[FLAG_STANDALONE]) {
|
||||||
|
if (argc - optind < 1) {
|
||||||
|
ret = usage(argc, argv, "No socket path provided");
|
||||||
|
|
||||||
|
goto error_config;
|
||||||
|
} else if (argc - optind < 2) {
|
||||||
|
ret = usage(argc, argv, "No device path provided");
|
||||||
|
|
||||||
|
goto error_config;
|
||||||
|
} else if (argc - optind < 3) {
|
||||||
|
ret = usage(argc, argv, "No callsign provided");
|
||||||
|
|
||||||
|
goto error_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle_simple_config(daemon,
|
||||||
|
argc - optind,
|
||||||
|
argv[0],
|
||||||
|
argv + optind) < 0) {
|
||||||
|
goto error_config;
|
||||||
|
}
|
||||||
|
} else if (patty_conf_read(config_file, handle_config_line, daemon) < 0) {
|
||||||
|
if (errno) {
|
||||||
|
fprintf(stderr, "%s: %s: %s: %s\n",
|
||||||
|
argv[0], "patty_conf_read()", config_file, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
goto error_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patty_daemon_run(daemon) < 0) {
|
||||||
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
|
argv[0], "patty_daemon_run()", strerror(errno));
|
||||||
|
|
||||||
|
goto error_daemon_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
patty_daemon_destroy(daemon);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_daemon_run:
|
||||||
|
error_config:
|
||||||
|
error_invalid_args:
|
||||||
|
patty_daemon_destroy(daemon);
|
||||||
|
|
||||||
|
error_daemon_new:
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ INCLUDE_PATH = ../include
|
||||||
CFLAGS += -I$(INCLUDE_PATH)
|
CFLAGS += -I$(INCLUDE_PATH)
|
||||||
LDFLAGS = -L../src -lpatty -lutil
|
LDFLAGS = -L../src -lpatty -lutil
|
||||||
|
|
||||||
EXAMPLES = daemon connect listen login ax25dump decode
|
EXAMPLES = connect listen login ax25dump decode
|
||||||
|
|
||||||
all: $(EXAMPLES)
|
all: $(EXAMPLES)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,9 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
patty_kiss_tnc *raw;
|
patty_kiss_tnc *raw;
|
||||||
|
|
||||||
int fd;
|
patty_kiss_tnc_info info = {
|
||||||
|
.flags = PATTY_KISS_TNC_FD
|
||||||
|
};
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
usage(argc, argv, "No patty socket provided");
|
usage(argc, argv, "No patty socket provided");
|
||||||
|
@ -52,7 +54,7 @@ int main(int argc, char **argv) {
|
||||||
goto error_client_new;
|
goto error_client_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fd = patty_client_socket(client, PATTY_AX25_PROTO_NONE, PATTY_AX25_SOCK_RAW)) < 0) {
|
if ((info.fd = patty_client_socket(client, PATTY_AX25_PROTO_NONE, PATTY_AX25_SOCK_RAW)) < 0) {
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
argv[0], "patty_client_socket()", strerror(errno));
|
argv[0], "patty_client_socket()", strerror(errno));
|
||||||
|
|
||||||
|
@ -63,16 +65,16 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
ifreq.state = PATTY_AX25_SOCK_PROMISC;
|
ifreq.state = PATTY_AX25_SOCK_PROMISC;
|
||||||
|
|
||||||
if (patty_client_setsockopt(client, fd, PATTY_AX25_SOCK_IF, &ifreq, sizeof(ifreq)) < 0) {
|
if (patty_client_setsockopt(client, info.fd, PATTY_AX25_SOCK_IF, &ifreq, sizeof(ifreq)) < 0) {
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
fprintf(stderr, "%s: %s: %s\n",
|
||||||
argv[0], "patty_client_setsockopt()", strerror(errno));
|
argv[0], "patty_client_setsockopt()", strerror(errno));
|
||||||
|
|
||||||
goto error_client_setsockopt;
|
goto error_client_setsockopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((raw = patty_kiss_tnc_new_fd(fd, NULL)) == NULL) {
|
if ((raw = patty_kiss_tnc_new(&info)) == NULL) {
|
||||||
fprintf(stderr, "%s: fd %d: %s: %s\n",
|
fprintf(stderr, "%s: fd %d: %s: %s\n",
|
||||||
argv[0], fd, "patty_kiss_tnc_new_fd()", strerror(errno));
|
argv[0], info.fd, "patty_kiss_tnc_new_fd()", strerror(errno));
|
||||||
|
|
||||||
goto error_kiss_tnc_new_fd;
|
goto error_kiss_tnc_new_fd;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +139,7 @@ error_ax25_frame_decode_address:
|
||||||
|
|
||||||
patty_kiss_tnc_destroy(raw);
|
patty_kiss_tnc_destroy(raw);
|
||||||
|
|
||||||
patty_client_close(client, fd);
|
patty_client_close(client, info.fd);
|
||||||
|
|
||||||
patty_client_destroy(client);
|
patty_client_destroy(client);
|
||||||
|
|
||||||
|
@ -149,7 +151,7 @@ error_io:
|
||||||
error_kiss_tnc_new_fd:
|
error_kiss_tnc_new_fd:
|
||||||
error_client_setsockopt:
|
error_client_setsockopt:
|
||||||
error_client_socket:
|
error_client_socket:
|
||||||
(void)patty_client_close(client, fd);
|
(void)patty_client_close(client, info.fd);
|
||||||
|
|
||||||
error_client_new:
|
error_client_new:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <patty/ax25.h>
|
|
||||||
#include <patty/daemon.h>
|
|
||||||
|
|
||||||
#include "../src/config.h"
|
|
||||||
|
|
||||||
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 /dev/ttyXX|kiss.cap [path.sock] callsign\n", argv[0]);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
patty_daemon *daemon;
|
|
||||||
|
|
||||||
patty_ax25_if_kiss_tnc_info info = {
|
|
||||||
.type = PATTY_AX25_IF_KISS_TNC_INFO_FD,
|
|
||||||
|
|
||||||
.flags = PATTY_KISS_TNC_BAUD
|
|
||||||
| PATTY_KISS_TNC_FLOW,
|
|
||||||
|
|
||||||
.baud = B9600,
|
|
||||||
.flow = PATTY_KISS_TNC_FLOW_CRTSCTS
|
|
||||||
};
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
usage(argc, argv, "No TNC device or KISS dump file provided");
|
|
||||||
} else if (argc < 3) {
|
|
||||||
usage(argc, argv, "No socket path provided");
|
|
||||||
} else if (argc < 4) {
|
|
||||||
usage(argc, argv, "No station callsign provided");
|
|
||||||
} else if (argc > 4) {
|
|
||||||
usage(argc, argv, "Too many arguments provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(argv[1], "/dev/ptmx") == 0) {
|
|
||||||
int ptysub;
|
|
||||||
char ptyname[256];
|
|
||||||
|
|
||||||
if (openpty(&info.fd, &ptysub, ptyname, NULL, NULL) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0], "openpty()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_open;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grantpt(info.fd) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s: %s\n",
|
|
||||||
argv[0], ptyname, "grantpt()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_grantpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlockpt(info.fd) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s: %s\n",
|
|
||||||
argv[0], ptyname, "unlockpt()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_unlockpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "pts %s\n", ptyname);
|
|
||||||
} else {
|
|
||||||
if ((info.fd = open(argv[1], O_RDWR | O_NOCTTY)) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s: %s\n",
|
|
||||||
argv[0], "open()", argv[1], strerror(errno));
|
|
||||||
|
|
||||||
goto error_open;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
if ((daemon = patty_daemon_new()) == NULL) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0], "patty_daemon_new()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_daemon_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc >= 3) {
|
|
||||||
if (patty_daemon_set_sock_path(daemon, argv[2]) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0], "patty_daemon_set_sock_path()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_daemon_set_sock_path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patty_daemon_init(daemon) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0], "patty_daemon_init()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_daemon_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patty_daemon_if_add(daemon,
|
|
||||||
PATTY_AX25_IF_KISS_TNC,
|
|
||||||
(patty_ax25_if_info *)&info,
|
|
||||||
argv[3]) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0], "patty_daemon_if_add()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_daemon_if_add;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patty_daemon_route_add_default(daemon, "kiss0") < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s\n",
|
|
||||||
argv[0], "patty_daemon_route_add_default()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_daemon_route_add_default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patty_daemon_run(daemon) < 0) {
|
|
||||||
fprintf(stderr, "%s: %s: %s: %s\n",
|
|
||||||
argv[0], argv[1], "patty_daemon_run()", strerror(errno));
|
|
||||||
|
|
||||||
goto error_daemon_run;
|
|
||||||
}
|
|
||||||
|
|
||||||
patty_daemon_destroy(daemon);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error_daemon_run:
|
|
||||||
error_daemon_route_add_default:
|
|
||||||
error_daemon_if_add:
|
|
||||||
error_daemon_set_sock_path:
|
|
||||||
error_daemon_init:
|
|
||||||
patty_daemon_destroy(daemon);
|
|
||||||
|
|
||||||
error_daemon_new:
|
|
||||||
error_grantpt:
|
|
||||||
error_unlockpt:
|
|
||||||
close(info.fd);
|
|
||||||
|
|
||||||
error_open:
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -28,15 +28,21 @@ int main(int argc, char **argv) {
|
||||||
void *buf;
|
void *buf;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
|
patty_kiss_tnc_info info;
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
usage(argc, argv, NULL);
|
usage(argc, argv, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
tnc = (argc == 2)?
|
if (argc == 2) {
|
||||||
patty_kiss_tnc_new(argv[1], NULL):
|
info.flags |= PATTY_KISS_TNC_DEVICE;
|
||||||
patty_kiss_tnc_new_fd(0, NULL);
|
info.device = argv[1];
|
||||||
|
} else {
|
||||||
|
info.flags |= PATTY_KISS_TNC_FD;
|
||||||
|
info.fd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (tnc == NULL) {
|
if ((tnc = patty_kiss_tnc_new(&info)) == NULL) {
|
||||||
perror("Unable to open TNC");
|
perror("Unable to open TNC");
|
||||||
|
|
||||||
goto error_kiss_tnc_open;
|
goto error_kiss_tnc_open;
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
sock /var/run/patty.sock
|
|
||||||
pid /var/run/patty.pid
|
|
||||||
if tnc0 ax25 KZ3ROX kiss /dev/ttyUSB0 baud 9600
|
|
||||||
route default if tnc0
|
|
||||||
route station GB9BLM path KX5UXQ WX3RKR
|
|
||||||
listen tnc0 ssid 0 exec /usr/bin/login -l -h @peer
|
|
5
examples/pattyd.conf
Normal file
5
examples/pattyd.conf
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
sock /var/run/patty.sock
|
||||||
|
pid /var/run/patty.pid
|
||||||
|
if kiss0 ax25 N7MMX kiss /dev/ttyUSB0 baud 9600
|
||||||
|
route default if kiss0
|
||||||
|
route station GB9BLM if kiss0 path KX4EHF WX9KIP
|
|
@ -52,25 +52,10 @@ typedef struct _patty_ax25_if {
|
||||||
patty_dict *promisc_fds;
|
patty_dict *promisc_fds;
|
||||||
} patty_ax25_if;
|
} patty_ax25_if;
|
||||||
|
|
||||||
enum patty_ax25_if_kiss_tnc_info_type {
|
|
||||||
PATTY_AX25_IF_KISS_TNC_INFO_FD,
|
|
||||||
PATTY_AX25_IF_KISS_TNC_INFO_PATH
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _patty_ax25_if_kiss_tnc_info {
|
|
||||||
int flags;
|
|
||||||
speed_t baud;
|
|
||||||
enum patty_kiss_tnc_flow flow;
|
|
||||||
|
|
||||||
enum patty_ax25_if_kiss_tnc_info_type type;
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
char path[256];
|
|
||||||
} patty_ax25_if_kiss_tnc_info;
|
|
||||||
|
|
||||||
typedef void patty_ax25_if_info;
|
typedef void patty_ax25_if_info;
|
||||||
|
|
||||||
patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type,
|
patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type,
|
||||||
|
const char *name,
|
||||||
patty_ax25_if_info *info,
|
patty_ax25_if_info *info,
|
||||||
patty_ax25_addr *addr);
|
patty_ax25_addr *addr);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
typedef struct _patty_ax25_server patty_ax25_server;
|
typedef struct _patty_ax25_server patty_ax25_server;
|
||||||
|
|
||||||
patty_ax25_server *patty_ax25_server_new(const char *path);
|
patty_ax25_server *patty_ax25_server_new();
|
||||||
|
|
||||||
void patty_ax25_server_destroy(patty_ax25_server *server);
|
void patty_ax25_server_destroy(patty_ax25_server *server);
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ int patty_ax25_server_route_each(patty_ax25_server *server,
|
||||||
int (*callback)(patty_ax25_route *, void *),
|
int (*callback)(patty_ax25_route *, void *),
|
||||||
void *ctx);
|
void *ctx);
|
||||||
|
|
||||||
int patty_ax25_server_start(patty_ax25_server *server);
|
int patty_ax25_server_start(patty_ax25_server *server, const char *path);
|
||||||
|
|
||||||
int patty_ax25_server_stop(patty_ax25_server *server);
|
int patty_ax25_server_stop(patty_ax25_server *server);
|
||||||
|
|
||||||
|
|
22
include/patty/conf.h
Normal file
22
include/patty/conf.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef _PATTY_CONF_H
|
||||||
|
#define _PATTY_CONF_H
|
||||||
|
|
||||||
|
#include <patty/list.h>
|
||||||
|
|
||||||
|
typedef struct _patty_conf_file patty_conf_file;
|
||||||
|
|
||||||
|
typedef struct _patty_conf_token {
|
||||||
|
char *text;
|
||||||
|
|
||||||
|
size_t lineno,
|
||||||
|
column,
|
||||||
|
len;
|
||||||
|
} patty_conf_token;
|
||||||
|
|
||||||
|
typedef int (*patty_conf_handler)(patty_conf_file *, patty_list *, void *);
|
||||||
|
|
||||||
|
int patty_conf_read(const char *file,
|
||||||
|
patty_conf_handler handler,
|
||||||
|
void *ctx);
|
||||||
|
|
||||||
|
#endif /* _PATTY_CONF_H */
|
|
@ -10,8 +10,6 @@ patty_daemon *patty_daemon_new();
|
||||||
|
|
||||||
void patty_daemon_destroy(patty_daemon *daemon);
|
void patty_daemon_destroy(patty_daemon *daemon);
|
||||||
|
|
||||||
int patty_daemon_init(patty_daemon *daemon);
|
|
||||||
|
|
||||||
int patty_daemon_run(patty_daemon *daemon);
|
int patty_daemon_run(patty_daemon *daemon);
|
||||||
|
|
||||||
int patty_daemon_set_sock_path(patty_daemon *daemon, const char *path);
|
int patty_daemon_set_sock_path(patty_daemon *daemon, const char *path);
|
||||||
|
@ -19,9 +17,7 @@ int patty_daemon_set_sock_path(patty_daemon *daemon, const char *path);
|
||||||
int patty_daemon_set_pidfile(patty_daemon *daemon, const char *path);
|
int patty_daemon_set_pidfile(patty_daemon *daemon, const char *path);
|
||||||
|
|
||||||
int patty_daemon_if_add(patty_daemon *daemon,
|
int patty_daemon_if_add(patty_daemon *daemon,
|
||||||
enum patty_ax25_if_type type,
|
patty_ax25_if *iface);
|
||||||
patty_ax25_if_info *info,
|
|
||||||
const char *callsign);
|
|
||||||
|
|
||||||
int patty_daemon_route_add(patty_daemon *daemon,
|
int patty_daemon_route_add(patty_daemon *daemon,
|
||||||
const char *ifname,
|
const char *ifname,
|
||||||
|
|
|
@ -35,8 +35,10 @@ ssize_t patty_kiss_frame_send(int fd,
|
||||||
|
|
||||||
typedef struct _patty_kiss_tnc patty_kiss_tnc;
|
typedef struct _patty_kiss_tnc patty_kiss_tnc;
|
||||||
|
|
||||||
#define PATTY_KISS_TNC_BAUD (1 << 0)
|
#define PATTY_KISS_TNC_DEVICE (1 << 0)
|
||||||
#define PATTY_KISS_TNC_FLOW (1 << 1)
|
#define PATTY_KISS_TNC_FD (1 << 1)
|
||||||
|
#define PATTY_KISS_TNC_BAUD (1 << 2)
|
||||||
|
#define PATTY_KISS_TNC_FLOW (1 << 3)
|
||||||
|
|
||||||
enum patty_kiss_tnc_flow {
|
enum patty_kiss_tnc_flow {
|
||||||
PATTY_KISS_TNC_FLOW_NONE,
|
PATTY_KISS_TNC_FLOW_NONE,
|
||||||
|
@ -47,15 +49,13 @@ enum patty_kiss_tnc_flow {
|
||||||
typedef struct _patty_kiss_tnc_info {
|
typedef struct _patty_kiss_tnc_info {
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
const char *device;
|
||||||
|
int fd;
|
||||||
speed_t baud;
|
speed_t baud;
|
||||||
enum patty_kiss_tnc_flow flow;
|
enum patty_kiss_tnc_flow flow;
|
||||||
} patty_kiss_tnc_info;
|
} patty_kiss_tnc_info;
|
||||||
|
|
||||||
patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd,
|
patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info);
|
||||||
patty_kiss_tnc_info *info);
|
|
||||||
|
|
||||||
patty_kiss_tnc *patty_kiss_tnc_new(const char *device,
|
|
||||||
patty_kiss_tnc_info *info);
|
|
||||||
|
|
||||||
int patty_kiss_tnc_fd(patty_kiss_tnc *tnc);
|
int patty_kiss_tnc_fd(patty_kiss_tnc *tnc);
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,11 @@ LDFLAGS = -lutil
|
||||||
|
|
||||||
HEADERS = kiss.h ax25.h client.h ax25/if.h ax25/frame.h \
|
HEADERS = kiss.h ax25.h client.h ax25/if.h ax25/frame.h \
|
||||||
ax25/sock.h ax25/route.h ax25/server.h daemon.h list.h \
|
ax25/sock.h ax25/route.h ax25/server.h daemon.h list.h \
|
||||||
hash.h dict.h timer.h print.h
|
hash.h dict.h timer.h print.h conf.h
|
||||||
|
|
||||||
OBJS = kiss.o ax25.o client.o if.o frame.o \
|
OBJS = kiss.o ax25.o client.o if.o frame.o \
|
||||||
sock.o route.o server.o daemon.o list.o \
|
sock.o route.o server.o daemon.o list.o \
|
||||||
hash.o dict.o timer.o print.o
|
hash.o dict.o timer.o print.o conf.o
|
||||||
|
|
||||||
VERSION_MAJOR = 0
|
VERSION_MAJOR = 0
|
||||||
VERSION_MINOR = 0.1
|
VERSION_MINOR = 0.1
|
||||||
|
|
358
src/conf.c
Normal file
358
src/conf.c
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <patty/list.h>
|
||||||
|
#include <patty/conf.h>
|
||||||
|
|
||||||
|
enum state {
|
||||||
|
STRING,
|
||||||
|
STRING_SINGLE_QUOTE,
|
||||||
|
STRING_DOUBLE_QUOTE,
|
||||||
|
DELIM,
|
||||||
|
COMMENT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum escape {
|
||||||
|
ESCAPE_OFF,
|
||||||
|
ESCAPE_ON
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _patty_conf_file {
|
||||||
|
const char *path;
|
||||||
|
size_t size;
|
||||||
|
void *buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int file_read(patty_conf_file *file, const char *path) {
|
||||||
|
int fd;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
size_t offset,
|
||||||
|
left;
|
||||||
|
|
||||||
|
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||||
|
goto error_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
goto error_fstat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((file->buf = malloc(st.st_size)) == NULL) {
|
||||||
|
goto error_malloc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
left = st.st_size;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
if ((len = read(fd,
|
||||||
|
(uint8_t *)file->buf + offset,
|
||||||
|
left > st.st_blksize? st.st_blksize: left)) < 0) {
|
||||||
|
goto error_read;
|
||||||
|
} else if (len < st.st_blksize) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
offset += len;
|
||||||
|
left -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)close(fd);
|
||||||
|
|
||||||
|
file->size = st.st_size;
|
||||||
|
file->path = path;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_read:
|
||||||
|
free(file->buf);
|
||||||
|
|
||||||
|
error_malloc_buf:
|
||||||
|
error_fstat:
|
||||||
|
(void)close(fd);
|
||||||
|
|
||||||
|
error_open:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_free(patty_conf_file *file) {
|
||||||
|
free(file->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void token_start(patty_conf_token *token,
|
||||||
|
char *text,
|
||||||
|
size_t lineno,
|
||||||
|
size_t column) {
|
||||||
|
token->text = text;
|
||||||
|
token->lineno = lineno;
|
||||||
|
token->column = column;
|
||||||
|
token->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int token_save(patty_list *list, patty_conf_token *token) {
|
||||||
|
patty_conf_token *copy;
|
||||||
|
|
||||||
|
if ((copy = malloc(sizeof(*token))) == NULL) {
|
||||||
|
goto error_malloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(copy, token, sizeof(*copy));
|
||||||
|
|
||||||
|
memset(token, '\0', sizeof(*token));
|
||||||
|
|
||||||
|
if (patty_list_append(list, copy) == NULL) {
|
||||||
|
goto error_list_append;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_list_append:
|
||||||
|
free(copy);
|
||||||
|
|
||||||
|
error_malloc:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void line_destroy(patty_list *list) {
|
||||||
|
patty_list_item *item = list->first;
|
||||||
|
|
||||||
|
while (item) {
|
||||||
|
patty_list_item *next = item->next;
|
||||||
|
|
||||||
|
free(item->value);
|
||||||
|
free(item);
|
||||||
|
|
||||||
|
item = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int start_of_string(enum state old, enum state state) {
|
||||||
|
switch (state) {
|
||||||
|
case STRING:
|
||||||
|
case STRING_SINGLE_QUOTE:
|
||||||
|
case STRING_DOUBLE_QUOTE:
|
||||||
|
if (old == DELIM) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int end_of_string(enum state old, enum state state) {
|
||||||
|
switch (old) {
|
||||||
|
case STRING:
|
||||||
|
case STRING_SINGLE_QUOTE:
|
||||||
|
case STRING_DOUBLE_QUOTE:
|
||||||
|
if (state == DELIM || state == COMMENT) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int within_string(enum state old, enum state state) {
|
||||||
|
switch (state) {
|
||||||
|
case STRING:
|
||||||
|
if (old != STRING_SINGLE_QUOTE && old != STRING_DOUBLE_QUOTE) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING_SINGLE_QUOTE:
|
||||||
|
case STRING_DOUBLE_QUOTE:
|
||||||
|
if (old == state) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int char_delim(uint8_t c) {
|
||||||
|
return (c == ' ' || c == '\r' || c == '\n' || c == '\t')? 1: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int patty_conf_read(const char *path,
|
||||||
|
patty_conf_handler handler,
|
||||||
|
void *ctx) {
|
||||||
|
patty_conf_file file;
|
||||||
|
|
||||||
|
patty_list *line;
|
||||||
|
patty_conf_token token;
|
||||||
|
|
||||||
|
enum state state = STRING;
|
||||||
|
enum escape escape = ESCAPE_OFF;
|
||||||
|
|
||||||
|
size_t i,
|
||||||
|
o,
|
||||||
|
lineno = 1,
|
||||||
|
column = 0;
|
||||||
|
|
||||||
|
if (file_read(&file, path) < 0) {
|
||||||
|
goto error_file_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((line = patty_list_new()) == NULL) {
|
||||||
|
goto error_list_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
token_start(&token, file.buf, lineno, column);
|
||||||
|
|
||||||
|
for (i=0, o=0; i<file.size; i++) {
|
||||||
|
enum state old = state;
|
||||||
|
|
||||||
|
uint8_t c = ((uint8_t *)file.buf)[i];
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
lineno++;
|
||||||
|
column = 1;
|
||||||
|
} else {
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case STRING:
|
||||||
|
if (c == '\\' && escape == ESCAPE_OFF) {
|
||||||
|
escape = ESCAPE_ON;
|
||||||
|
} else if (char_delim(c)) {
|
||||||
|
state = DELIM;
|
||||||
|
} else if (c == '\'') {
|
||||||
|
state = STRING_SINGLE_QUOTE;
|
||||||
|
} else if (c == '"') {
|
||||||
|
state = STRING_DOUBLE_QUOTE;
|
||||||
|
} else if (c == '#') {
|
||||||
|
state = COMMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING_SINGLE_QUOTE:
|
||||||
|
if (c == '\'') {
|
||||||
|
state = STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING_DOUBLE_QUOTE:
|
||||||
|
if (c == '\\' && escape == ESCAPE_OFF) {
|
||||||
|
escape = ESCAPE_ON;
|
||||||
|
} else if (c == '"' && escape == ESCAPE_OFF) {
|
||||||
|
state = STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DELIM:
|
||||||
|
if (c == '\\' && escape == ESCAPE_OFF) {
|
||||||
|
escape = ESCAPE_ON;
|
||||||
|
} else if (c == '\'') {
|
||||||
|
state = STRING_SINGLE_QUOTE;
|
||||||
|
} else if (c == '"') {
|
||||||
|
state = STRING_DOUBLE_QUOTE;
|
||||||
|
} else if (c == '#') {
|
||||||
|
state = COMMENT;
|
||||||
|
} else if (!char_delim(c)) {
|
||||||
|
state = STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMMENT:
|
||||||
|
if (c == '\n') {
|
||||||
|
state = DELIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_of_string(old, state)) {
|
||||||
|
token_start(&token,
|
||||||
|
(char *)file.buf + o,
|
||||||
|
lineno,
|
||||||
|
column);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (within_string(old, state)) {
|
||||||
|
if (escape == ESCAPE_OFF) {
|
||||||
|
((char *)file.buf)[o++] = c;
|
||||||
|
|
||||||
|
token.len++;
|
||||||
|
}
|
||||||
|
} else if (end_of_string(old, state)) {
|
||||||
|
((char *)file.buf)[o++] = '\0';
|
||||||
|
|
||||||
|
if (token_save(line, &token) < 0) {
|
||||||
|
goto error_token_save;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n' && escape == ESCAPE_OFF) {
|
||||||
|
if (line->length > 0) {
|
||||||
|
if (handler(&file, line, ctx) < 0) {
|
||||||
|
goto error_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_destroy(line);
|
||||||
|
|
||||||
|
if ((line = patty_list_new()) == NULL) {
|
||||||
|
goto error_list_new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (escape == ESCAPE_ON) {
|
||||||
|
escape = ESCAPE_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.len) {
|
||||||
|
((char *)file.buf)[o++] = '\0';
|
||||||
|
|
||||||
|
if (token_save(line, &token) < 0) {
|
||||||
|
goto error_token_save;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line->length > 0) {
|
||||||
|
if (handler(&file, line, ctx) < 0) {
|
||||||
|
goto error_handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line_destroy(line);
|
||||||
|
|
||||||
|
file_free(&file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_handler:
|
||||||
|
error_token_save:
|
||||||
|
patty_list_destroy(line);
|
||||||
|
|
||||||
|
error_list_new:
|
||||||
|
file_free(&file);
|
||||||
|
|
||||||
|
error_file_read:
|
||||||
|
return -1;
|
||||||
|
}
|
50
src/daemon.c
50
src/daemon.c
|
@ -1,5 +1,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <patty/ax25.h>
|
#include <patty/ax25.h>
|
||||||
#include <patty/daemon.h>
|
#include <patty/daemon.h>
|
||||||
|
@ -28,8 +29,15 @@ patty_daemon *patty_daemon_new() {
|
||||||
goto error_set_pidfile;
|
goto error_set_pidfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((daemon->server = patty_ax25_server_new()) == NULL) {
|
||||||
|
goto error_server_new;
|
||||||
|
}
|
||||||
|
|
||||||
return daemon;
|
return daemon;
|
||||||
|
|
||||||
|
error_server_new:
|
||||||
|
free(daemon->pidfile);
|
||||||
|
|
||||||
error_set_pidfile:
|
error_set_pidfile:
|
||||||
free(daemon->sock_path);
|
free(daemon->sock_path);
|
||||||
|
|
||||||
|
@ -41,24 +49,23 @@ error_malloc:
|
||||||
}
|
}
|
||||||
|
|
||||||
void patty_daemon_destroy(patty_daemon *daemon) {
|
void patty_daemon_destroy(patty_daemon *daemon) {
|
||||||
|
if (daemon->server) {
|
||||||
patty_ax25_server_destroy(daemon->server);
|
patty_ax25_server_destroy(daemon->server);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon->sock_path) {
|
||||||
|
free(daemon->sock_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon->pidfile) {
|
||||||
|
free(daemon->pidfile);
|
||||||
|
}
|
||||||
|
|
||||||
free(daemon);
|
free(daemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
int patty_daemon_init(patty_daemon *daemon) {
|
|
||||||
if ((daemon->server = patty_ax25_server_new(daemon->sock_path)) == NULL) {
|
|
||||||
goto error_server_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error_server_new:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int patty_daemon_run(patty_daemon *daemon) {
|
int patty_daemon_run(patty_daemon *daemon) {
|
||||||
if (patty_ax25_server_start(daemon->server) < 0) {
|
if (patty_ax25_server_start(daemon->server, daemon->sock_path) < 0) {
|
||||||
goto error_server_start;
|
goto error_server_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,25 +117,8 @@ error_strdup:
|
||||||
}
|
}
|
||||||
|
|
||||||
int patty_daemon_if_add(patty_daemon *daemon,
|
int patty_daemon_if_add(patty_daemon *daemon,
|
||||||
enum patty_ax25_if_type type,
|
patty_ax25_if *iface) {
|
||||||
patty_ax25_if_info *info,
|
|
||||||
const char *callsign) {
|
|
||||||
patty_ax25_if *iface;
|
|
||||||
patty_ax25_addr addr;
|
|
||||||
|
|
||||||
if (patty_ax25_pton(callsign, &addr) < 0) {
|
|
||||||
goto error_pton;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((iface = patty_ax25_if_new(type, info, &addr)) == NULL) {
|
|
||||||
goto error_if_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
return patty_ax25_server_if_add(daemon->server, iface);
|
return patty_ax25_server_if_add(daemon->server, iface);
|
||||||
|
|
||||||
error_if_new:
|
|
||||||
error_pton:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int patty_daemon_route_add(patty_daemon *daemon,
|
int patty_daemon_route_add(patty_daemon *daemon,
|
||||||
|
|
19
src/if.c
19
src/if.c
|
@ -1,4 +1,3 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -7,22 +6,13 @@
|
||||||
|
|
||||||
#include <patty/ax25.h>
|
#include <patty/ax25.h>
|
||||||
|
|
||||||
static int init_tnc(patty_ax25_if *iface, patty_ax25_if_kiss_tnc_info *info) {
|
static int init_tnc(patty_ax25_if *iface, patty_kiss_tnc_info *info) {
|
||||||
static char *prefix = "kiss";
|
if ((iface->tnc = patty_kiss_tnc_new(info)) == NULL) {
|
||||||
static int number = 0;
|
|
||||||
|
|
||||||
iface->tnc = (info->type == PATTY_AX25_IF_KISS_TNC_INFO_FD)?
|
|
||||||
patty_kiss_tnc_new_fd(info->fd, (patty_kiss_tnc_info *)info):
|
|
||||||
patty_kiss_tnc_new(info->path, (patty_kiss_tnc_info *)info);
|
|
||||||
|
|
||||||
if (iface->tnc == NULL) {
|
|
||||||
goto error_kiss_tnc_new;
|
goto error_kiss_tnc_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
iface->type = PATTY_AX25_IF_KISS_TNC;
|
iface->type = PATTY_AX25_IF_KISS_TNC;
|
||||||
|
|
||||||
snprintf(iface->name, sizeof(iface->name), "%s%d", prefix, number++);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_kiss_tnc_new:
|
error_kiss_tnc_new:
|
||||||
|
@ -34,6 +24,7 @@ static void destroy_tnc(patty_ax25_if *iface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type,
|
patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type,
|
||||||
|
const char *name,
|
||||||
patty_ax25_if_info *info,
|
patty_ax25_if_info *info,
|
||||||
patty_ax25_addr *addr) {
|
patty_ax25_addr *addr) {
|
||||||
patty_ax25_if *iface;
|
patty_ax25_if *iface;
|
||||||
|
@ -44,6 +35,8 @@ patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type,
|
||||||
|
|
||||||
memset(iface, '\0', sizeof(*iface));
|
memset(iface, '\0', sizeof(*iface));
|
||||||
|
|
||||||
|
strncpy(iface->name, name, sizeof(iface->name));
|
||||||
|
|
||||||
if (addr->callsign[0] == '\0') {
|
if (addr->callsign[0] == '\0') {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
|
||||||
|
@ -78,7 +71,7 @@ patty_ax25_if *patty_ax25_if_new(enum patty_ax25_if_type type,
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PATTY_AX25_IF_KISS_TNC:
|
case PATTY_AX25_IF_KISS_TNC:
|
||||||
if (init_tnc(iface, (patty_ax25_if_kiss_tnc_info *)info) < 0) {
|
if (init_tnc(iface, info) < 0) {
|
||||||
goto error_init;
|
goto error_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
131
src/kiss.c
131
src/kiss.c
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <patty/kiss.h>
|
#include <patty/kiss.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
enum kiss_flags {
|
enum kiss_flags {
|
||||||
KISS_NONE = 0,
|
KISS_NONE = 0,
|
||||||
KISS_FRAME = 1 << 0,
|
KISS_FRAME = 1 << 0,
|
||||||
|
@ -120,8 +122,7 @@ error_io:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd,
|
patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) {
|
||||||
patty_kiss_tnc_info *info) {
|
|
||||||
patty_kiss_tnc *tnc;
|
patty_kiss_tnc *tnc;
|
||||||
|
|
||||||
if ((tnc = malloc(sizeof(*tnc))) == NULL) {
|
if ((tnc = malloc(sizeof(*tnc))) == NULL) {
|
||||||
|
@ -132,8 +133,54 @@ patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd,
|
||||||
goto error_malloc_buf;
|
goto error_malloc_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isatty(fd) && ptsname(fd) == NULL) {
|
if (info->flags & PATTY_KISS_TNC_DEVICE) {
|
||||||
if (tcgetattr(fd, &tnc->attrs) < 0) {
|
struct stat st;
|
||||||
|
|
||||||
|
if (strcmp(info->device, "/dev/ptmx") == 0) {
|
||||||
|
int ptysub;
|
||||||
|
|
||||||
|
if (openpty(&tnc->fd, &ptysub, NULL, NULL, NULL) < 0) {
|
||||||
|
goto error_open;
|
||||||
|
}
|
||||||
|
} else if (stat(info->device, &st) < 0) {
|
||||||
|
goto error_stat;
|
||||||
|
} else if ((st.st_mode & S_IFMT) == S_IFSOCK) {
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
|
||||||
|
if (strlen(info->device) > sizeof(addr.sun_path)) {
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
|
||||||
|
goto error_overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tnc->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, info->device, sizeof(addr.sun_path)-1);
|
||||||
|
|
||||||
|
if (connect(tnc->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
goto error_connect;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((tnc->fd = open(info->device, O_RDWR | O_NOCTTY)) < 0) {
|
||||||
|
goto error_open;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tnc->opts |= TNC_CLOSE_ON_DESTROY;
|
||||||
|
} else if (info->flags & PATTY_KISS_TNC_FD) {
|
||||||
|
tnc->fd = info->fd;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
|
goto error_no_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) {
|
||||||
|
if (tcgetattr(tnc->fd, &tnc->attrs) < 0) {
|
||||||
goto error_tcgetattr;
|
goto error_tcgetattr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +188,6 @@ patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd,
|
||||||
|
|
||||||
cfmakeraw(&tnc->attrs);
|
cfmakeraw(&tnc->attrs);
|
||||||
|
|
||||||
if (info) {
|
|
||||||
if (info->flags & PATTY_KISS_TNC_BAUD) {
|
if (info->flags & PATTY_KISS_TNC_BAUD) {
|
||||||
cfsetspeed(&tnc->attrs, info->baud);
|
cfsetspeed(&tnc->attrs, info->baud);
|
||||||
}
|
}
|
||||||
|
@ -162,20 +208,18 @@ patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tcflush(fd, TCIOFLUSH) < 0) {
|
if (tcflush(tnc->fd, TCIOFLUSH) < 0) {
|
||||||
goto error_tcflush;
|
goto error_tcflush;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcsetattr(fd, TCSANOW, &tnc->attrs) < 0) {
|
if (tcsetattr(tnc->fd, TCSANOW, &tnc->attrs) < 0) {
|
||||||
goto error_tcsetattr;
|
goto error_tcsetattr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tnc->fd = fd;
|
|
||||||
tnc->opts = TNC_NONE;
|
tnc->opts = TNC_NONE;
|
||||||
tnc->bufsz = PATTY_KISS_BUFSZ;
|
tnc->bufsz = PATTY_KISS_BUFSZ;
|
||||||
tnc->offset = 0;
|
tnc->offset = 0;
|
||||||
|
@ -187,6 +231,18 @@ patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd,
|
||||||
error_tcflush:
|
error_tcflush:
|
||||||
error_tcsetattr:
|
error_tcsetattr:
|
||||||
error_tcgetattr:
|
error_tcgetattr:
|
||||||
|
error_connect:
|
||||||
|
if (info->flags & PATTY_KISS_TNC_DEVICE) {
|
||||||
|
(void)close(tnc->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_open:
|
||||||
|
error_no_fd:
|
||||||
|
error_socket:
|
||||||
|
error_overflow:
|
||||||
|
error_stat:
|
||||||
|
free(tnc->buf);
|
||||||
|
|
||||||
error_malloc_buf:
|
error_malloc_buf:
|
||||||
free(tnc);
|
free(tnc);
|
||||||
|
|
||||||
|
@ -194,61 +250,6 @@ error_malloc_tnc:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
patty_kiss_tnc *patty_kiss_tnc_new(const char *device,
|
|
||||||
patty_kiss_tnc_info *info) {
|
|
||||||
patty_kiss_tnc *tnc;
|
|
||||||
int fd;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (stat(device, &st) < 0) {
|
|
||||||
goto error_stat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((st.st_mode & S_IFMT) == S_IFSOCK) {
|
|
||||||
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;
|
|
||||||
strncpy(addr.sun_path, device, sizeof(addr.sun_path)-1);
|
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
||||||
goto error_connect;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((fd = open(device, O_RDWR | O_NOCTTY)) < 0) {
|
|
||||||
goto error_open;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tnc = patty_kiss_tnc_new_fd(fd, info)) == NULL) {
|
|
||||||
goto error_tnc_new_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
tnc->opts |= TNC_CLOSE_ON_DESTROY;
|
|
||||||
|
|
||||||
return tnc;
|
|
||||||
|
|
||||||
error_tnc_new_fd:
|
|
||||||
error_connect:
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
error_socket:
|
|
||||||
error_overflow:
|
|
||||||
error_open:
|
|
||||||
error_stat:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) {
|
int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) {
|
||||||
return tnc->fd;
|
return tnc->fd;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +260,7 @@ void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tnc->opts & TNC_CLOSE_ON_DESTROY) {
|
if (tnc->opts & TNC_CLOSE_ON_DESTROY) {
|
||||||
close(tnc->fd);
|
(void)close(tnc->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(tnc->buf);
|
free(tnc->buf);
|
||||||
|
|
10
src/server.c
10
src/server.c
|
@ -16,8 +16,6 @@
|
||||||
typedef int (*patty_ax25_server_call)(patty_ax25_server *, int);
|
typedef int (*patty_ax25_server_call)(patty_ax25_server *, int);
|
||||||
|
|
||||||
struct _patty_ax25_server {
|
struct _patty_ax25_server {
|
||||||
char path[PATTY_AX25_SOCK_PATH_SIZE];
|
|
||||||
|
|
||||||
int fd, /* fd of UNIX domain socket */
|
int fd, /* fd of UNIX domain socket */
|
||||||
fd_max;
|
fd_max;
|
||||||
|
|
||||||
|
@ -38,7 +36,7 @@ struct _patty_ax25_server {
|
||||||
*clients_by_sock;
|
*clients_by_sock;
|
||||||
};
|
};
|
||||||
|
|
||||||
patty_ax25_server *patty_ax25_server_new(const char *path) {
|
patty_ax25_server *patty_ax25_server_new() {
|
||||||
patty_ax25_server *server;
|
patty_ax25_server *server;
|
||||||
|
|
||||||
if ((server = malloc(sizeof(*server))) == NULL) {
|
if ((server = malloc(sizeof(*server))) == NULL) {
|
||||||
|
@ -47,8 +45,6 @@ patty_ax25_server *patty_ax25_server_new(const char *path) {
|
||||||
|
|
||||||
memset(server, '\0', sizeof(*server));
|
memset(server, '\0', sizeof(*server));
|
||||||
|
|
||||||
strncpy(server->path, path, sizeof(server->path)-1);
|
|
||||||
|
|
||||||
if ((server->ifaces = patty_list_new()) == NULL) {
|
if ((server->ifaces = patty_list_new()) == NULL) {
|
||||||
goto error_list_new_ifaces;
|
goto error_list_new_ifaces;
|
||||||
}
|
}
|
||||||
|
@ -2296,8 +2292,8 @@ static int handle_socks(patty_ax25_server *server) {
|
||||||
return patty_dict_each(server->socks_by_fd, handle_sock, server);
|
return patty_dict_each(server->socks_by_fd, handle_sock, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
int patty_ax25_server_start(patty_ax25_server *server) {
|
int patty_ax25_server_start(patty_ax25_server *server, const char *path) {
|
||||||
return listen_unix(server, server->path);
|
return listen_unix(server, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int patty_ax25_server_stop(patty_ax25_server *server) {
|
int patty_ax25_server_stop(patty_ax25_server *server) {
|
||||||
|
|
11
src/sock.c
11
src/sock.c
|
@ -130,8 +130,13 @@ static patty_ax25_sock *init_dgram(patty_ax25_sock *sock,
|
||||||
}
|
}
|
||||||
|
|
||||||
static patty_ax25_sock *init_raw(patty_ax25_sock *sock) {
|
static patty_ax25_sock *init_raw(patty_ax25_sock *sock) {
|
||||||
if ((sock->raw = patty_kiss_tnc_new_fd(sock->fd, NULL)) == NULL) {
|
patty_kiss_tnc_info info = {
|
||||||
goto error_kiss_tnc_new_fd;
|
.flags = PATTY_KISS_TNC_FD,
|
||||||
|
.fd = sock->fd
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((sock->raw = patty_kiss_tnc_new(&info)) == NULL) {
|
||||||
|
goto error_kiss_tnc_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock->proto = PATTY_AX25_PROTO_NONE;
|
sock->proto = PATTY_AX25_PROTO_NONE;
|
||||||
|
@ -140,7 +145,7 @@ static patty_ax25_sock *init_raw(patty_ax25_sock *sock) {
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
|
|
||||||
error_kiss_tnc_new_fd:
|
error_kiss_tnc_new:
|
||||||
(void)close(sock->fd);
|
(void)close(sock->fd);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Add table
Reference in a new issue