Commit 8d74c7ea authored by Dave Hibberd's avatar Dave Hibberd

New upstream version 2.9.0

parent 71f02d51
Makefile
aprx-complex.conf
aprx.conf
config.h
config.log
config.status
aprx
aprx-stat
aprx-stat.8
aprx.8
build-stamp
configure-stamp
debian/aprx.debhelper.log
debian/aprx.logrotate
debian/aprx.postinst.debhelper
debian/aprx.postrm.debhelper
debian/aprx.prerm.debhelper
debian/aprx.substvars
debian/changelog
debian/files
*.o
*.d
2014-08-29 Matti Aarnio - OH2MQK - KP20NG <oh2mqk@sral.fi>
* beacon.c:
Demote some nuisance logging to "-dd" level.
2014-03-31 Matti Aarnio - OH2MQK - KP20NG <oh2mqk@sral.fi>
* aprx.h, interface.c, igate.c, dprsgw.c:
Deliver all APRS-IS supplied tokens to the interface 3rd-party
receiver
* beacon.c:
Limit read amount of 256 bytes, excess is rejected and usually
also the beaconing is skipped.
* aprx.c, aprx.h, igate.c:
Moved rflog() from igate.c to aprx.c.
2014-03-24 Matti Aarnio - OH2MQK - KP20NG <oh2mqk@sral.fi>
* interface.c:
......
INSTALL of APRX 2.08
INSTALL of APRX 2
Pre-made binary package building system exists for Debian and
Redhat/Fedora systems. See details at the end of this file.
Instructions for how to build Debian apt packages are provided
at the end of this file
A rough-cut version of the installation instructions
......@@ -35,11 +35,11 @@ A rough-cut version of the installation instructions
5) Edit the configuration file to match your system:
# emacs /etc/aprx.conf
# $EDITOR /etc/aprx.conf
See the aprx(8) man-page for more info (man 8 aprx)
6) Program startup scripts ("init-scripts") exist for
6) Program startup scripts ("init-scripts") exist for a
couple system environments, others may need manual
adapting.
......@@ -48,13 +48,10 @@ A rough-cut version of the installation instructions
For Debian users wanting to compile themselves instead of using
precompiled binaries:
$ make make-deb
# aptitude install git build-essential debhelper libssl-dev
$ git clone https://github.com/PhirePhly/aprx.git
$ cd aprx
$ ./configure
$ make make-deb
# dpkg -i ../aprx_....deb
# dpkg -i aprx_2.07-....deb
For RedHat/Fedora users:
$ make make-rpm
# rpm -Uvh aprx-2.07.svn###-1.i386.rpm
#
# APRX -- 2nd generation receive-only APRS-i-gate with
# minimal requirement of esoteric facilities or
# libraries of any kind beyond UNIX system libc.
#
# Note: This makefile uses features from GNU make
# -------------------------------------------------------------------- #
# target paths
VARRUN= /var/run # directory for aprx.state and pid-file
VARLOG= /var/log/aprx # directory for direct logfiles
CFGFILE= /etc/aprx.conf # default configuration file
SBINDIR= /usr/sbin # installation path for programs
MANDIR= /usr/share/man # installation path for manual pages
# -------------------------------------------------------------------- #
srcdir = .
PROF= # used by 'make profile'
# Compiler and flags
CC= gcc
CFLAGS= -Wall -g -O2 -pthread
# Linker and flags
LD= gcc
LDFLAGS= -Wall -g -O2 -z noexecstack $(PROF)
datarootdir= ${prefix}/share
INSTALL= $(srcdir)/install-sh
INSTALL_PROGRAM=$(INSTALL) -m 755
INSTALL_DATA= $(INSTALL) -m 644
# -------------------------------------------------------------------- #
# no user serviceable parts below
# -------------------------------------------------------------------- #
# strip extra whitespace from paths
VARRUN:=$(strip $(VARRUN))
VARLOG:=$(strip $(VARLOG))
CFGFILE:=$(strip $(CFGFILE))
SBINDIR:=$(strip $(SBINDIR))
MANDIR:=$(strip $(MANDIR))
# generate version strings
VERSION = 2.08
SVNVERSION = $(shell cat SVNVERSION)
versionupdate := $(shell if [ "$(PKG_REV)-$(PKG_RELEASE)" != "-" ]; then echo "$(PKG_REV)-$(PKG_RELEASE)" > SVNVERSION; fi)
# VERSION:=$(shell cat VERSION)
# SVNVERSION_CMD:=$(shell which svnversion)
# SVNVERSION:=$(shell if ${SVNVERSION_CMD} > /dev/null 2>&1 \&\& test -x ${SVNVERSION_CMD} -a \( -d .svn -o -d ../.svn -o -d ../../.svn \) ; then ${SVNVERSION_CMD} | tee SVNVERSION ; else cat SVNVERSION; fi)
DATE:=$(shell date +"%Y %B %d")
RFCDATE:=$(shell date +"%a, %d %b %Y %H:%M:%S %z")
DEFS= -DAPRXVERSION="\"2.08r$(SVNVERSION)\"" \
-DVARRUN="\"$(VARRUN)\"" -DVARLOG="\"$(VARLOG)\"" \
-DCFGFILE="\"$(CFGFILE)\""
# program names
PROGAPRX= aprx
PROGSTAT= $(PROGAPRX)-stat
LIBS= -lrt -lutil -lm -pthread -lrt
OBJSAPRX= aprx.o ttyreader.o ax25.o aprsis.o beacon.o config.o \
netax25.o erlang.o aprxpolls.o telemetry.o igate.o \
cellmalloc.o historydb.o keyhash.o parse_aprs.o \
dupecheck.o kiss.o interface.o pbuf.o digipeater.o \
valgrind.o filter.o dprsgw.o crc.o agwpesocket.o \
netresolver.o timercmp.o #ssl.o
OBJSSTAT= erlang.o aprx-stat.o aprxpolls.o valgrind.o timercmp.o
# man page sources, will be installed as $(PROGAPRX).8 / $(PROGSTAT).8
MANAPRX := aprx.8
MANSTAT := aprx-stat.8
OBJS= $(OBJSAPRX) $(OBJSSTAT)
MAN= $(MANAPRX) $(MANSTAT)
# -------------------------------------------------------------------- #
.PHONY: all
all: $(PROGAPRX) $(PROGSTAT) man aprx.conf aprx-complex.conf
valgrind:
@echo "Did you do 'make clean' before 'make valgrind' ?"
make all CFLAGS="${CFLAGS} -D_FOR_VALGRIND_"
profile:
@echo "Did you do 'make clean' before 'make profile' ?"
make all PROF="-pg"
$(PROGAPRX): $(OBJSAPRX) VERSION Makefile
$(LD) $(LDFLAGS) -o $@ $(OBJSAPRX) $(LIBS)
$(PROGSTAT): $(OBJSSTAT) VERSION Makefile
$(LD) $(LDFLAGS) -o $@ $(OBJSSTAT) $(LIBS)
.PHONY: man
man: $(MAN)
.PHONY: doc html pdf
doc: html pdf
pdf: $(MAN:=.pdf)
html: $(MAN:=.html)
# -------------------------------------------------------------------- #
.PHONY: install install-deb
install: all
$(INSTALL_PROGRAM) $(PROGAPRX) $(DESTDIR)$(SBINDIR)/$(PROGAPRX)
$(INSTALL_PROGRAM) $(PROGSTAT) $(DESTDIR)$(SBINDIR)/$(PROGSTAT)
$(INSTALL_DATA) $(MANAPRX) $(DESTDIR)$(MANDIR)/man8/$(PROGAPRX).8
$(INSTALL_DATA) $(MANSTAT) $(DESTDIR)$(MANDIR)/man8/$(PROGSTAT).8
if [ ! -f $(DESTDIR)$(CFGFILE) ] ; then \
$(INSTALL_DATA) aprx.conf $(DESTDIR)$(CFGFILE) ; \
else true ; fi
.PHONY: clean
clean:
rm -f $(PROGAPRX) $(PROGSTAT)
rm -f $(MAN) $(MAN:=.html) $(MAN:=.ps) $(MAN:=.pdf) \
rm -f aprx.conf logrotate.aprx
rm -f *~ *.o *.d
.PHONY: distclean
distclean: clean
rm -f config.log config.status config.h
rm -rf autom4te.cache *.log* doc/.~*#
# -------------------------------------------------------------------- #
%.o: %.c VERSION Makefile
$(CC) $(CFLAGS) $(PROF) $(DEFS) -c $<
@$(CC) -MM $(CFLAGS) $(PROF) $(DEFS) $< > $(@:.o=.d)
$(MAN:=.html): %.html : %
sh man-to-html.sh $< > $@
$(MAN:=.ps): %.ps : %
groff -man $< > $@
$(MAN:=.pdf): %.pdf : %.ps
ps2pdf $<
logrotate.aprx $(MAN) aprx-complex.conf aprx.conf: % : %.in VERSION Makefile
perl -ne "s{\@DATEVERSION\@}{$(VERSION) - $(DATE)}g; \
s{\@VARRUN\@}{$(VARRUN)}g; \
s{\@VARLOG\@}{$(VARLOG)}g; \
s{\@CFGFILE\@}{$(CFGFILE)}g; \
print;" \
< $< > $@
# -------------------------------------------------------------------- #
#
# Following is for the original author only...
#
DISTVERSION:=aprx-$(VERSION).svn$(SVNVERSION)
DISTTARGET:=../$(DISTVERSION)
RPMVERSION:=$(shell echo "${DISTVERSION}" | sed -e 's/aprx-//')
.PHONY: dist svnversion-test
svnversion-test:
# Special for the source maintainer only..
@sh svnversion-test.sh $(SVNVERSION)
dist: svnversion-test
if [ ! -d $(DISTTARGET) ] ; then \
mkdir $(DISTTARGET) ; \
fi
tar cf - --exclude-backups --exclude-vcs --exclude=windows --exclude=*.log* --exclude=*.conf . | (cd $(DISTTARGET) ; tar xf -)
echo "$(DISTVERSION)" > $(DISTTARGET)/VERSION
perl -ne "\$$ver = '$(DISTVERSION)'; \
\$$ver =~ tr/0-9.//cd; \
\$$ver .= '-1'; \
s{\@VERSION\@}{\$$ver}g; \
s{\@RFCDATE\@}{$(RFCDATE)}g; \
print;" \
< $(DISTTARGET)/debian/changelog.release \
> $(DISTTARGET)/debian/changelog
rm -f $(DISTTARGET)/debian/changelog.release
rm -f $(DISTTARGET)/aprx.spec
perl -ne "s{\@VERSION\@}{$(RPMVERSION)}g; \
s{\@DATE0\@}{$(DATE0)}g; \
print;" \
< $(DISTTARGET)/rpm/aprx.spec.in \
> $(DISTTARGET)/aprx.spec
rm -f $(DISTTARGET)/rpm/aprx.spec.in
make -C $(DISTTARGET) distclean
cd .. && \
tar czvf $(DISTVERSION).tar.gz $(DISTVERSION)
# -------------------------------------------------------------------- #
.PHONY: make-deb make-rpm
make-deb:
if [ -f debian/changelog.release ] ; then \
perl -ne "\$$ver = '$(DISTVERSION)'; \
\$$ver =~ tr/0-9.//cd; \
\$$ver .= '-1'; \
s{\@VERSION\@}{\$$ver}g; \
s{\@RFCDATE\@}{$(RFCDATE)}g; \
print;" \
< debian/changelog.release \
> debian/changelog ; \
fi
dpkg-buildpackage -b -us -uc -rfakeroot
make-rpm: # actually just a reminder of how to do it..
rpmbuild --target i386 -ta ../$(DISTVERSION).tar.gz
# -------------------------------------------------------------------- #
# include object depencies if available
-include $(OBJS:.o=.d)
......@@ -48,18 +48,12 @@ MANDIR:=$(strip $(MANDIR))
# generate version strings
VERSION = @VERSION_STRING@
SVNVERSION = $(shell cat SVNVERSION)
versionupdate := $(shell if [ "$(PKG_REV)-$(PKG_RELEASE)" != "-" ]; then echo "$(PKG_REV)-$(PKG_RELEASE)" > SVNVERSION; fi)
# VERSION:=$(shell cat VERSION)
# SVNVERSION_CMD:=$(shell which svnversion)
# SVNVERSION:=$(shell if ${SVNVERSION_CMD} > /dev/null 2>&1 \&\& test -x ${SVNVERSION_CMD} -a \( -d .svn -o -d ../.svn -o -d ../../.svn \) ; then ${SVNVERSION_CMD} | tee SVNVERSION ; else cat SVNVERSION; fi)
VERSION = $(shell echo @VERSION_STRING@ | cut -b 2-)
DATE:=$(shell date +"%Y %B %d")
RFCDATE:=$(shell date +"%a, %d %b %Y %H:%M:%S %z")
DEFS= -DAPRXVERSION="\"@VERSION_STRING@r$(SVNVERSION)\"" \
DEFS= -DAPRXVERSION="\"$(VERSION)\"" \
-DVARRUN="\"$(VARRUN)\"" -DVARLOG="\"$(VARLOG)\"" \
-DCFGFILE="\"$(CFGFILE)\""
......@@ -165,16 +159,12 @@ logrotate.aprx $(MAN) aprx-complex.conf aprx.conf: % : %.in VERSION Makefile
# Following is for the original author only...
#
DISTVERSION:=aprx-$(VERSION).svn$(SVNVERSION)
DISTVERSION:=aprx-$(VERSION)
DISTTARGET:=../$(DISTVERSION)
RPMVERSION:=$(shell echo "${DISTVERSION}" | sed -e 's/aprx-//')
.PHONY: dist svnversion-test
svnversion-test:
# Special for the source maintainer only..
@sh svnversion-test.sh $(SVNVERSION)
.PHONY: dist
dist: svnversion-test
dist:
if [ ! -d $(DISTTARGET) ] ; then \
mkdir $(DISTTARGET) ; \
fi
......@@ -206,9 +196,7 @@ dist: svnversion-test
make-deb:
if [ -f debian/changelog.release ] ; then \
perl -ne "\$$ver = '$(DISTVERSION)'; \
\$$ver =~ tr/0-9.//cd; \
\$$ver .= '-1'; \
perl -ne "\$$ver = '$(VERSION)'; \
s{\@VERSION\@}{\$$ver}g; \
s{\@RFCDATE\@}{$(RFCDATE)}g; \
print;" \
......
APRX v2.08
APRX v2.9
A multitalented APRS / DPRS / APRSIS "i-gate" with following properties:
......
Aprx Roadmap and Future Directions
APRX ROADMAP
Version 1
- APRS Rx-only iGate - Complete, working
- channel activity monitoring and telemetry - Complete, working
v2.9.x - Stable release with only bug-fixes
Pretty much everyone should be using this version
Version 2
- Digipeater - Working
- Analyze and detect station distance - Working
- Radio beacons - Working
- Bidirection (Rx/Tx) APRS iGate - Working
- DPRS->APRS GW - Working
v2.10.x - Development branch for new feature experimentation
Version for developers who'd like to help test new features for Aprx
Version 2+
- Port to ucLinux - Planned (pthread OK)
- Port to Windows
- Automated coverage statistics analyzer, and
reporting it via digi node identity beacons.
"ALOHA circles"
- Automated coverage plotting
APRX 2.08
APRX 2.09
TODO / Wishlist
BUGS / TODO / Wishlist
- "[Aprx] Re: WIDE2-2/NOGATE - trace not working?"
- Digipeater working wrong:
oz1ekd> oh2mqk - it seems like KG4PID is right, aprx does not digipeat as it should, mine set to "non viscous" and "not direct-only" live log at: http://stave.dk/aprx
From: kg4pid@yahoo.com
Subject: Re: RF beacons vs TCPIP* (was: 2.08 r593 Not digipeating correctly)
As far as I know all the digi's in this area insert their calsign in the
packet. I do see some beacons being digied and igated by other stations
just not as many as I think I should. You maybe right about receiving my
own beacon after a digipeat as I have seen that happen before. It would be
nice if it was marked somehow and what digi heard me. They look just like
the telemetry packets that I know are sent direct. Max
20140417070330,KG4PID-14>APRX28,TCPIP*,qAC,FIRENET1:T#014,23.6,4.3,101.0,0.0,17.0,00000000
20140417070351,KG4PID-14>APRX28,TCPIP*,qAC,FIRENET1:>Digi/Igate kg4pid at yahoo dot com
20140417071955,KG4PID-14>APRX28,WIDE2-2,qAR,N4XWC:!3417.45N/08742.32W#PHG7250 Bear Creek, Al
- Add to RF-log all packets dropped due to bad bits; use HEX dump,
and type tag 'D'. Use type tag 'd' with text dump when APRS-IS
dropped the frame for one reason or other (network timeouts mostly)
- "[Aprx] Re: Bi-Directional Cross-band Digipeater"
Probably heard sources accounting bucket initializing as zero,
which was fixed recently.
which was fixed recently. (2.07ish)
- SSL mode to talk to APRS-IS. (Aprsc speaks SSL very efficiently.)
......
aprx-2.08.svn593
v2.9.0
/* **************************************************************** *
* *
* APRX -- 2nd generation receive-only APRS-i-gate with *
* APRX -- 2nd generation APRS iGate and digi with *
* minimal requirement of esoteric facilities or *
* libraries of any kind beyond UNIX system libc. *
* *
......
......@@ -18,6 +18,7 @@
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#ifdef HAVE_NETINET_SCTP_H
#include <netinet/sctp.h>
......@@ -254,8 +255,8 @@ static int aprsis_queue_(struct aprsis *A, const char * const addr, const char q
// APRS-IS communicator
static void aprsis_reconnect(struct aprsis *A)
{
struct addrinfo req, *ai, *a, *ap[21];
int i, n;
struct addrinfo req, *ai, *a;
int i;
char *s;
char aprsislogincmd[3000];
const char *errstr;
......@@ -265,8 +266,8 @@ static void aprsis_reconnect(struct aprsis *A)
aprsis_close(A, "reconnect");
if (!A->H) {
A->H = AISh[0];
if (A->H == NULL) {
A->H = AISh[AIShindex=0];
} else {
++AIShindex;
if (AIShindex >= AIShcount)
......@@ -286,11 +287,7 @@ static void aprsis_reconnect(struct aprsis *A)
req.ai_socktype = SOCK_STREAM;
req.ai_protocol = IPPROTO_TCP;
req.ai_flags = 0;
#if 1
req.ai_family = AF_UNSPEC; /* IPv4 and IPv6 are both OK */
#else
req.ai_family = AF_INET; /* IPv4 only */
#endif
req.ai_family = AF_UNSPEC;
ai = NULL;
......@@ -313,27 +310,7 @@ static void aprsis_reconnect(struct aprsis *A)
return;
}
/* Count the addresses */
memset(ap, 0, sizeof(ap));
for (n = 0, a = ai; a; a = a->ai_next, ++n) {
if (n < 20)
ap[n] = a;
else
break;
}
ap[n] = NULL;
if (n > 1) { /* more than one ? choose one at random as the first address,
then go through the address list in new sequence. */
n = rand() % n;
if (n > 0) {
a = ap[n];
ap[n] = ap[0];
ap[0] = a;
}
}
for (n = 0; (a = ap[n]) && A->server_socket < 0; ++n) {
for (a = ai; (a != NULL) && (A->server_socket < 0); a = a->ai_next) {
errstr = "socket formation failed";
......@@ -342,14 +319,34 @@ static void aprsis_reconnect(struct aprsis *A)
a->ai_protocol);
errcode = errno;
if (A->server_socket < 0)
if (A->server_socket < 0) {
if (debug) printf("aprsis failed to open socket.\n");
continue;
}
if(debug) {
char addrstr[INET6_ADDRSTRLEN];
void *sin_ptr = NULL;
switch (a->ai_family) {
case AF_INET:
sin_ptr = &((struct sockaddr_in *) a->ai_addr)->sin_addr;
break;
case AF_INET6:
sin_ptr = &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr;
break;
}
inet_ntop (a->ai_family, sin_ptr, addrstr, INET6_ADDRSTRLEN);
printf("aprsis connection attempt IPv%d address: %s\n",
(a->ai_family == PF_INET6) ? 6 : 4, addrstr);
}
errstr = "connection failed";
i = connect(A->server_socket, a->ai_addr, a->ai_addrlen);
errcode = errno;
if (i < 0) {
if (debug) printf("aprsis connection failed.\n");
/* If connection fails, try next possible address */
close(A->server_socket);
A->server_socket = -1;
......@@ -509,17 +506,18 @@ static void aprsis_readup(void)
buf[i] = 0; /* String Termination NUL byte */
memcpy(&head, buf, sizeof(head));
if (head.then + 10 < tick.tv_sec)
return; /* Too old, discard */
addr = buf + sizeof(head);
gwcall = addr + head.addrlen + 1;
text = gwcall + head.gwlen + 1;
textlen = head.textlen;
if (textlen <= 2)
if (head.then + 10 < tick.tv_sec) {
return; /* Too old, discard */
// rflog();
}
if (textlen <= 2) {
return; // BAD!
}
if ((text + textlen) > (buf + i)) {
return; // BAD!
}
......@@ -758,7 +756,6 @@ static void aprsis_main(void)
/* The main loop */
while (!die_now) {
struct pollfd *pfd;
int i;
timetick();
......@@ -768,6 +765,7 @@ static void aprsis_main(void)
#if !(defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD))
// Parent-pid makes no sense in threaded setup
int i;
i = getppid();
if (i != ppid)
break; /* die now, my parent is gone.. */
......@@ -786,7 +784,7 @@ static void aprsis_main(void)
pfd->revents = 0;
}
i = aprsis_prepoll_(&app);
aprsis_prepoll_(&app);
// Prepolls are done
time_reset = 0;
......@@ -795,7 +793,7 @@ static void aprsis_main(void)
tv_timeradd_seconds( &app.next_timeout, &tick, 1 ); // Just to be on safe side..
}
i = poll(app.polls, app.pollcount, aprxpolls_millis(&app));
poll(app.polls, app.pollcount, aprxpolls_millis(&app));
timetick();
......@@ -806,7 +804,7 @@ static void aprsis_main(void)
the channel reports EOF, we exit there and then. */
aprsis_readup();
}
i = aprsis_postpoll_(&app);
aprsis_postpoll_(&app);
}
aprxpolls_free(&app); // valgrind..
/* Got "DIE NOW" signal... */
......@@ -1271,7 +1269,7 @@ int aprsis_config(struct configfile *cf)
}
AISh = realloc(AISh, sizeof(AISh[0]) * (AIShcount + 1));
AISh[AIShcount] = AIH;
AISh[AIShcount++] = AIH;
}
return has_fault;
}
......
/* **************************************************************** *
* *
* APRX -- 2nd generation receive-only APRS-i-gate with *
* APRX -- 2nd generation APRS iGate and digi with *
* minimal requirement of esoteric facilities or *
* libraries of any kind beyond UNIX system libc. *
* *
......
/* **************************************************************** *
* *
* APRX -- 2nd generation receive-only APRS-i-gate with *
* APRX -- 2nd generation APRS iGate and digi with *
* minimal requirement of esoteric facilities or *
* libraries of any kind beyond UNIX system libc. *
* *
......@@ -34,8 +34,7 @@ float myloc_lon;
const char *myloc_latstr;
const char *myloc_lonstr;
const char *tocall = "APRX28";
const uint8_t tocall25[7] = {'A'<<1,'P'<<1,'R'<<1,'X'<<1,'2'<<1,'8'<<1,0x60};
const char *tocall = "APRX29";
#ifndef CFGFILE
#define CFGFILE "/etc/aprx.conf"
......@@ -54,6 +53,7 @@ static void sig_handler(int sig)
{
die_now = 1;
signal(sig, sig_handler);
aprxlog("aprx ending (SIG %d) - %s",sig,swversion);
if (debug) {
// Avoid stdio FILE* interlocks within signal handler
char buf[64];
......@@ -374,7 +374,7 @@ int main(int argc, char *const argv[])
igate_start();
#endif
aprxlog("APRX start");
aprxlog("aprx start - %s",swversion);
// The main loop
......@@ -633,3 +633,56 @@ va_dcl
}
}
/* ---------------------------------------------------------- */
void rfloghex(const char *portname, char direction, int discard, const uint8_t *buf, int buflen)
{
}
void rflog(const char *portname, char direction, int discard, const char *tnc2buf, int tnc2len)
{
if (rflogfile) {
#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
#endif
FILE *fp = NULL;
const char *p;
if (strcmp("-",rflogfile)==0) {
if (debug < 2) return;
fp = stdout;
} else {
fp = fopen(rflogfile, "a");
}
if (fp) {
char timebuf[60];
printtime(timebuf, sizeof(timebuf));
(void)fprintf(fp, "%s %-9s ", timebuf, portname);
(void)fprintf(fp, "%c ", direction);
if (discard < 0) {
fprintf(fp, "*");
}
if (discard > 0) {
fprintf(fp, "#");
}
//replace non printing TNC2 characters in log print
for(p=tnc2buf;p<tnc2buf+tnc2len;p++){
if(*p<0x20 || *p>0x7e)
fprintf(fp,"<0x%02x>",*p);
else