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