linbpq/bpqaxip.c

3333 lines
73 KiB
C

/*
Copyright 2001-2022 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
//
// DLL to provide AXIP support for G8BPQ switch in a
// 32bit environment,
//
// Uses BPQ EXTERNAL interface
//
// Version 1.1 August 2001
//
// Send to all matching entries in map table
// (Mainly for NODES braodcasts to multiple stations)
//
// Version 1.2 September 2001
//
// Support UDP as well as raw IP
// Version 1.3 October 2001
//
// Allow host names as well as numeric IP addresses
//
// Version 1.4 November 2002
//
// Implement keepalive for NAT routers
//
// Version 1.5 December 2004
//
// Implement a "MHEARD" facility
//
// Version 1.6 August 2005
//
// Treat NULL string in Registry as use current directory
// Version 1.7 December 2005
//
// Create a separate thread to open sockets to avoid hang on XP SP2
// Version 1.8 January 2006
//
// Get config file location from Node (will check bpq directory)
// Version 1.9 March 2006
//
// Allow multiple listening UDP ports
// Kick off resolver on EXTRESTART
// Remove redundant DYNAMIC processing
// Version 1.10 October 2006
//
// Add "Minimize to Tray" option
// Write diagnostics to BPQ console window instead of STDOUT
// Version 1.11 October 2007
//
// Sort MHeard and discard last entry if full
// Add Commands to re-read config file and manually add an ARP entry
// Version 1.12 February 2008
//
// Check received length
// Changes for unload of bpq32.dll
// Add Close Driver function
// Dynamic Load of bpq32.dll
// Version 1.13 October 2008
//
// Add Linux-style config of broadcast addressess
// Version 1.13.2 January 2009
//
// Add Start Minimized Option
// Version 1.13.3 February 2009
//
// Save Window positions
// Version 1.13.4 March 2009
//
// Fix loop on config file error
// Version 1.14.1 April 2009
//
// Add option to reject messages if sender is not in ARP Table
// Add option to add received calls to ARP Table
// Version 1.15.1 May 2009
//
// Add IP/TCP option
// Version 1.15.2 August 2009
//
// Extra Debug Output in TCP Mode
// Fix problem if TCP entry was first in table
// Include TCP sessions in MHEARD
// Add T flag to Resolver window fot TCP Sessions
// Set SO_KEEPALIVE and SO_CONDITIONAL_ACCEPT socket options
// Version 1.15.4 August 2009
// Recycle Listening Socket if no connect for 60 mins
// Clear data connections if no data for 60 mins
// Repaint MH Window after clear.
// Version 1.15.5 Spetmber 2010
// Add option to get config from bpq32.dll
// Moved to BPQ32.dll - no separate version number onw.
// October 2010
// Allow multiple axip ports.
// June 2011
// Add IPv6 support
#define _CRT_SECURE_NO_DEPRECATE
#include "CHeaders.h"
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "bpq32.h"
#ifndef LINBPQ
#include "kernelresource.h"
#include <process.h>
#endif
#include <time.h>
#define WSA_ACCEPT WM_USER + 1
#define WSA_DATA WM_USER + 2
#define WSA_CONNECT WM_USER + 3
// Cater for only systems without IPV6_V6ONLY
#ifndef IPV6_V6ONLY
#define IPV6_V6ONLY 0x27
#endif
#ifndef MAXGETHOSTSTRUCT
#define MAXGETHOSTSTRUCT 1024
#endif
#define FEND 0xC0 // KISS CONTROL CODES
#define FESC 0xDB
#define TFEND 0xDC
#define TFESC 0xDD
int ResolveDelay = 0;
extern BOOL StartMinimized;
VOID * zalloc(int len);
int ResetExtDriver(int num);
BOOL ProcessConfig();
VOID FreeConfig();
extern UCHAR BPQDirectory[];
extern int OffsetH, OffsetW;
static void ResolveNames(struct AXIPPORTINFO * PORT);
void OpenSockets(struct AXIPPORTINFO * PORT);
void CloseSockets(struct AXIPPORTINFO * PORT);
static int CONVFROMAX25(char * incall, char * outcall);
void CreateMHWindow(struct AXIPPORTINFO * PORT);
int Update_MH_List(struct AXIPPORTINFO * PORT, UCHAR * ipad, char * call, char proto, short port, BOOL IPv6);
int Update_MH_KeepAlive(struct AXIPPORTINFO * PORT, struct in_addr ipad, char proto, short port);
unsigned short int compute_crc(unsigned char *buf,int l);
unsigned int find_arp(unsigned char * call);
BOOL add_arp_entry(struct AXIPPORTINFO * PORT, unsigned char * call, UCHAR * ip, int len, int port,unsigned char * name,
int keepalive, BOOL BCFlag, BOOL AutoAdded, int TCPMode, int SourcePort, BOOL IPv6, int noUpdate);
BOOL add_bc_entry(struct AXIPPORTINFO * PORT, unsigned char * call, int len);
BOOL convtoax25(unsigned char * callsign, unsigned char * ax25call, int * calllen);
static BOOL ReadConfigFile(int Port);
static int ProcessLine(char * buf, struct AXIPPORTINFO * PORT);
int CheckKeepalives(struct AXIPPORTINFO * PORT);
BOOL CopyScreentoBuffer(char * buff, struct AXIPPORTINFO * PORT);
int DumpFrameInHex(unsigned char * msg, int len);
VOID SendFrame(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp_table, UCHAR * buff, int txlen);
BOOL CheckSourceisResolvable(struct AXIPPORTINFO * PORT, char * call, int Port, VOID * rxaddr);
int DataSocket_Read(struct arp_table_entry * sockptr, SOCKET sock);
int GetMessageFromBuffer(struct AXIPPORTINFO * PORT, char * Buffer);
int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
int KissDecode(UCHAR * inbuff, int len);
int Socket_Accept(int SocketId);
int Socket_Connect(int SocketId, int Error);
int Socket_Data(int sock, int error, int eventcode);
VOID TCPConnectThread(struct arp_table_entry * arp);
VOID __cdecl Debugprintf(const char * format, ...);
VOID __cdecl Consoleprintf(const char * format, ...);
BOOL OpenListeningSocket(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp);
VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6);
static void CreateResolverWindow(struct AXIPPORTINFO * PORT);
VOID SaveMDIWindowPos(HWND hWnd, char * RegKey, char * Value, BOOL Minimized);
VOID SaveAXIPCache(struct AXIPPORTINFO * PORT);
VOID GetAXIPCache(struct AXIPPORTINFO * PORT);
union
{
struct sockaddr_in sinx;
struct sockaddr_in6 sinx6;
} sinx;
/*
union
{
struct sockaddr_in destaddr;
struct sockaddr_in6 destaddr6;
} destaddr;
*/
#define IP_AXIP 93 // IP Protocol for AXIP
#pragma pack(1)
struct iphdr {
// unsigned int version:4; // Version of IP
// unsigned int h_len:4; // length of the header
unsigned char h_lenvers; // Version + length of the header
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum
unsigned int sourceIP;
unsigned int destIP;
};
#pragma pack()
#define TCPMaster 1
#define TCPSlave 2
#define TCPListening 1
#define TCPConnecting 2
#define TCPConnected 4
#ifndef LINBPQ
LOGFONT LFTTYFONT ;
extern HFONT hFont ;
RECT ResRect;
RECT MHRect;
extern HKEY REGTREE;
extern HWND ClientWnd, FrameWnd;
extern HMENU hMainFrameMenu, hBaseMenu, hWndMenu;
extern HBRUSH bgBrush;
#endif
//struct tagMSG Msg;
//char buf[MAXGETHOSTSTRUCT];
int addrlen6 = sizeof(struct sockaddr_in6);
int addrlen = sizeof(struct sockaddr_in);
extern unsigned short CRCTAB[];
unsigned int AXIPInst = 0;
char CantReplyList[512] = ""; // To suppress duplicate "Can't Reply" messages
DWORD n;
struct AXIPPORTINFO * Portlist[MaxBPQPortNo + 1];
int InitAXIP(int Port);
int CurrentResEntries;
static char ConfigClassName[]="CONFIG";
HANDLE hInstance;
VOID SaveAXIPWindowPos(int port)
{
#ifndef LINBPQ
struct AXIPPORTINFO * PORT;
char Key[80];
PORT = Portlist[port];
if (PORT == NULL)
return;
sprintf(Key, "PACTOR\\PORT%d", port);
SaveMDIWindowPos(PORT->hMHWnd, Key, "MHSize", PORT->MHMinimized);
SaveMDIWindowPos(PORT->hResWnd, Key, "ResSize", PORT->ResMinimized);
#endif
return;
}
static size_t ExtProc(int fn, int port, PMESSAGE buff)
{
struct iphdr * iphdrptr;
int len,txlen=0,err,index,digiptr,i;
unsigned short int crc;
char rxbuff[5000];
char axcall[7];
char errmsg[100];
union
{
struct sockaddr_in rxaddr;
struct sockaddr_in6 rxaddr6;
} RXaddr;
struct AXIPPORTINFO * PORT = Portlist[port];
switch (fn)
{
case 1: // poll
//
// Check Keepalive timers
//
time(&PORT->ltime);
if (PORT->ltime-PORT->lasttime >9 )
{
PORT->lasttime=PORT->ltime;
CheckKeepalives(PORT);
}
if (PORT->needip)
{
char call[7];
len = recvfrom(PORT->sock,rxbuff,500,0,(struct sockaddr *)&RXaddr.rxaddr,&addrlen);
if (len == -1)
{
err = WSAGetLastError();
}
else
{
iphdrptr=(struct iphdr *)&rxbuff;
if (len == ntohs(iphdrptr->total_len))
{
len-=20; // IP HEADER
if (memcmp(&rxbuff[20], "Keepalive", 9) == 0 )
{
if (PORT->MHEnabled)
Update_MH_KeepAlive(PORT, RXaddr.rxaddr.sin_addr,'I',93);
return 0;
}
crc = compute_crc(&rxbuff[20], len);
if (crc == 0xf0b8) // Good CRC
{
len-=2; // Remove CRC
if (len > MAXDATA)
{
sprintf(errmsg,"BPQAXIP Invalid Msg Len=%d Source=%s",len,inet_ntoa(RXaddr.rxaddr.sin_addr));
OutputDebugString(errmsg);
DumpFrameInHex(&rxbuff[20], len);
return 0;
}
memcpy(&buff->DEST, &rxbuff[20],len);
len += (3 + sizeof(void *));
PutLengthinBuffer((PDATAMESSAGE)buff, len); // Needed for arm5 portability
memcpy(call, &buff->ORIGIN, 7);
call[6] &= 0x7e; // Mask End of Address bit
//
// Do MH Proccessing if enabled
//
if (PORT->MHEnabled)
Update_MH_List(PORT, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, &buff->ORIGIN[0], 'I', 93, 0);
// Check Exclude
if (CheckExcludeList(call) == 0)
return 0;
if (PORT->Checkifcanreply)
{
if (CheckSourceisResolvable(PORT, call, 0, &RXaddr))
return 1;
else
// Can't reply. If AutoConfig is set, add to table and accept, else reject
if (PORT->AutoAddARP)
return add_arp_entry(PORT, call, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, 7, 0, inet_ntoa(RXaddr.rxaddr.sin_addr), 0, PORT->AutoAddBC, TRUE, 0, 0, FALSE, 0);
else
{
char From[11] = "|";
From[ConvFromAX25(call, &From[1]) + 1] = 0;
if (strstr(CantReplyList, From) == 0)
{
if (strlen(CantReplyList) < 500);
strcat(CantReplyList, From);
Debugprintf("AXIP Packet from %s dropped - can't reply", &From[1]);
}
return 0;
}
}
else
return(1);
}
//
// CRC Error
//
sprintf(errmsg,"BPQAXIP Invalid CRC=%d Source=%s",crc,inet_ntoa(RXaddr.rxaddr.sin_addr));
OutputDebugString(errmsg);
return (0);
}
//
// Bad Length
//
return (0);
}
}
for (i=0;i<PORT->NumberofUDPPorts;i++)
{
char call[7];
if (PORT->IPv6[i])
len = recvfrom(PORT->udpsock[i],rxbuff,500,0,(struct sockaddr *)&RXaddr.rxaddr, &addrlen6);
else
len = recvfrom(PORT->udpsock[i],rxbuff,500,0,(struct sockaddr *)&RXaddr.rxaddr, &addrlen);
if (len == -1)
{
err = WSAGetLastError();
}
else
{
if (memcmp(rxbuff, "Keepalive", 9) == 0 )
{
if (PORT->MHEnabled)
Update_MH_KeepAlive(PORT, RXaddr.rxaddr.sin_addr, 'U', PORT->udpport[i]);
continue;
}
crc = compute_crc(&rxbuff[0], len);
if (crc == 0xf0b8) // Good CRC
{
len-=2; // Remove CRC
if (len > MAXDATA)
{
sprintf(errmsg,"BPQAXIP Invalid Msg Len=%d Source=%s Port %d",len,inet_ntoa(RXaddr.rxaddr.sin_addr),PORT->udpport[i]);
OutputDebugString(errmsg);
DumpFrameInHex(&rxbuff[0], len);
return 0;
}
memcpy(&buff->DEST, &rxbuff[0], len);
len += (3 + sizeof(void *));
PutLengthinBuffer((PDATAMESSAGE)buff, len);
memcpy(call, &buff->ORIGIN, 7);
call[6] &= 0x7e; // Mask End of Address bit
//
// Do MH Proccessing if enabled
//
if (PORT->MHEnabled)
if (PORT->IPv6[i])
Update_MH_List(PORT, (UCHAR *)&RXaddr.rxaddr6.sin6_addr, &buff->ORIGIN[0], 'U', PORT->udpport[i], TRUE);
else
Update_MH_List(PORT, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, &buff->ORIGIN[0], 'U', PORT->udpport[i], FALSE);
// Check Exclude
if (CheckExcludeList(call) == 0)
return 0;
if (PORT->Checkifcanreply)
{
if (CheckSourceisResolvable(PORT, call, htons(RXaddr.rxaddr.sin_port), &RXaddr))
return 1;
else
{
// Can't reply. If AutoConfig is set, add to table and accept, else reject
if (PORT->AutoAddARP)
if (PORT->IPv6[i])
{
char Addr[80];
Format_Addr((UCHAR *)&RXaddr.rxaddr6.sin6_addr, Addr, TRUE);
return add_arp_entry(PORT, call, (UCHAR *)&RXaddr.rxaddr6.sin6_addr, 7, htons(RXaddr.rxaddr6.sin6_port), Addr, 0, PORT->AutoAddBC, TRUE, 0, PORT->udpport[i], TRUE, 0);
}
else
return add_arp_entry(PORT, call, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, 7, htons(RXaddr.rxaddr.sin_port), inet_ntoa(RXaddr.rxaddr.sin_addr), 0, PORT->AutoAddBC, TRUE, 0, PORT->udpport[i], FALSE, 0);
else
{
char From[11] = "|";
From[ConvFromAX25(call, &From[1]) + 1] = 0;
if (strstr(CantReplyList, From) == 0)
{
if (strlen(CantReplyList) < 500);
strcat(CantReplyList, From);
Debugprintf("AXIP Packet from %s dropped - can't reply", &From[1]);
}
return 0;
}
}
}
else
return(1);
}
//
// CRC Error
//
sprintf(errmsg,"BPQAXIP Invalid CRC=%d Source=%s Port %d",crc,inet_ntoa(RXaddr.rxaddr.sin_addr),PORT->udpport[i]);
Debugprintf(errmsg);
rxbuff[len] = 0;
Debugprintf(rxbuff);
return (0);
}
}
if (PORT->NeedTCP)
{
len = GetMessageFromBuffer(PORT, rxbuff);
if (len)
{
len = KissDecode(rxbuff, len-1); // Len includes FEND
len -= 2; // Ignore Checksum
if (len < MAXDATA)
{
memcpy(&buff->DEST, &rxbuff[0], len);
len += (3 + sizeof(void *));
PutLengthinBuffer((PDATAMESSAGE)buff, len); // fix big endian issue
return 1;
}
else
{
Debugprintf("Oversized AX/TCP frame %d", len);
return 0;
}
}
}
return (0);
case 2: // send
// txlen=(buff[6]<<8) + buff[5] - 5; // Len includes buffer header (7) but we add crc
txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - (MSGHDDRLEN - 2); // 2 for CRC
crc=compute_crc(&buff->DEST[0], txlen - 2);
crc ^= 0xffff;
buff->DEST[txlen - 2] = (crc & 0xff);
buff->DEST[txlen - 1] = (crc >> 8);
memcpy(axcall, &buff->DEST, 7); // Set to send to dest addr
// if digis are present, scan down list for first non-used call
if (buff->ORIGIN[6] == 0)
{
// end of addr bit not set, so scan digis
digiptr = 13; // start of first digi
while (((buff->ORIGIN[digiptr] & 0x80) == 0x80) && ((buff->ORIGIN[digiptr] & 0x1) == 0))
{
// This digi has been used, and it is not the last
digiptr+=7;
}
// if this has not been used, use it
if ((buff->ORIGIN[digiptr] & 0x80) == 0)
memcpy(axcall,&buff->ORIGIN[digiptr - 6], 7); // get next call
}
axcall[6] &= 0x7e;
// If addresses to a broadcast address, send to all entries
for (i=0; i< PORT->NumberofBroadcastAddreses; i++)
{
if (memcmp(axcall, PORT->BroadcastAddresses[i].callsign, 7) == 0)
{
for (index = 0; index < PORT->arp_table_len; index++)
{
if (PORT->arp_table[index].BCFlag)
SendFrame(PORT, &PORT->arp_table[index], &buff->DEST[0], txlen);
}
return 0;
}
}
// Send to all matching calls in arp table
index = 0;
while (index < PORT->arp_table_len)
{
if (memcmp(PORT->arp_table[index].callsign,axcall,PORT->arp_table[index].len) == 0)
{
SendFrame(PORT, &PORT->arp_table[index],&buff->DEST[0], txlen);
}
index++;
}
return (0);
case 3: // CHECK IF OK TO SEND
return (0); // OK
case 4: // reinit
CloseSockets(PORT);
if (ProcessConfig())
{
FreeConfig();
ReadConfigFile(port);
}
else
Consoleprintf("Failed to reread config file - leaving config unchanged");
_beginthread(OpenSockets, 0, PORT );
GetAXIPCache(PORT);
ResolveDelay = 2;
#ifndef LINBPQ
InvalidateRect(PORT->hResWnd,NULL,TRUE);
#endif
break;
case 5: // Terminate
CloseSockets(PORT);
#ifndef LINBPQ
SendMessage(PORT->hMHWnd, WM_CLOSE, 0, 0);
SendMessage(PORT->hResWnd, WM_CLOSE, 0, 0);
#endif
break;
}
return (0);
}
VOID SendFrame(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp_table, UCHAR * buff, int txlen)
{
int i;
SOCKET txsock, SourceSocket;
if (arp_table->TCPMode)
{
if (arp_table->TCPState == TCPConnected)
{
char outbuff[1000];
int newlen;
newlen = KissEncode(buff, outbuff, txlen);
send(arp_table->TCPSock, outbuff, newlen, 0);
}
return;
}
// Seelcte source port by choosing right socket
// First Set Default for Protocol
for (i = 0; i < PORT->NumberofUDPPorts; i++)
{
if (PORT->IPv6[i] == arp_table->IPv6)
{
SourceSocket = PORT->udpsock[i]; // Use as source socket, therefore source port
break;
}
}
for (i = 0; i < PORT->NumberofUDPPorts; i++)
{
if (PORT->udpport[i] == arp_table->SourcePort && PORT->IPv6[i] == arp_table->IPv6)
{
SourceSocket = PORT->udpsock[i]; // Use as source socket, therefore source port
break;
}
}
if (arp_table->error == 0)
{
int sent = 0;
if (arp_table->port == 0) txsock = PORT->sock; else txsock = SourceSocket;
if (arp_table->IPv6)
sent = sendto(txsock, buff, txlen, 0, (struct sockaddr *)&arp_table->destaddr6, sizeof(arp_table->destaddr6));
else
if (arp_table->destaddr.sin_addr.s_addr)
sent = sendto(txsock, buff, txlen, 0, (struct sockaddr *)&arp_table->destaddr, sizeof(arp_table->destaddr));
if (sent != txlen)
{
int i = GetLastError();
// perror("Sendto");
}
// reset Keepalive Timer
arp_table->keepalive=arp_table->keepaliveinit;
}
}
unsigned short int compute_crc_ccitt(unsigned char *buf, int len);
unsigned short CCCITTChecksum(unsigned char* data, unsigned int length);
VOID * AXIPExtInit(struct PORTCONTROL * PortEntry)
{
// char Msg[10] = {0xD0, 01, 00, 0x11, 00, 0x0B};
// unsigned short crc;
// crc = CCCITTChecksum(Msg, 4);
// crc = CalcCRC(Msg, 4);
WritetoConsole("AXIP ");
InitAXIP(PortEntry->PORTNUMBER);
WritetoConsole("\n");
return ExtProc;
}
int InitAXIP(int Port)
{
struct AXIPPORTINFO * PORT;
//
// Read config first, to get UDP info if needed
//
if (!ReadConfigFile(Port))
return (FALSE);
PORT = Portlist[Port];
if (PORT == NULL)
return FALSE;
PORT->Port = Port;
GetAXIPCache(PORT); // Prime resolver from cache
//
// Start Resolver Thread if needed
//
if (PORT->NeedResolver)
{
CreateResolverWindow(PORT);
_beginthread(ResolveNames, 0, PORT );
}
time(&PORT->lasttime); // Get initial time value
_beginthread(OpenSockets, 0, PORT );
// Start TCP outward connect threads
//
// Open MH window if needed
if (PORT->MHEnabled)
CreateMHWindow(PORT);
return (TRUE);
}
void OpenSockets(struct AXIPPORTINFO * PORT)
{
char Msg[255];
int err;
u_long param=1;
BOOL bcopt=TRUE;
int i;
int index = 0;
struct arp_table_entry * arp;
// Moved from InitAXIP, to avoid hang if started too early on XP SP2
// Create and bind socket
if (PORT->needip)
{
PORT->sock=socket(AF_INET,SOCK_RAW,IP_AXIP);
if (PORT->sock == INVALID_SOCKET)
{
err = WSAGetLastError();
sprintf(Msg, "AXIP Failed to create RAW socket - Error %d\n", err);
WritetoConsole(Msg);
}
else
{
ioctl (PORT->sock,FIONBIO,&param);
setsockopt (PORT->sock,SOL_SOCKET,SO_BROADCAST,(const char FAR *)&bcopt,4);
sinx.sinx.sin_family = AF_INET;
sinx.sinx.sin_addr.s_addr = INADDR_ANY;
sinx.sinx.sin_port = 0;
if (bind(PORT->sock, (struct sockaddr *) &sinx, sizeof(sinx)) != 0 )
{
//
// Bind Failed
//
err = WSAGetLastError();
sprintf(Msg, "Bind Failed for RAW socket - error code = %d", err);
WritetoConsole(Msg);
return;
}
}
}
for (i=0;i<PORT->NumberofUDPPorts;i++)
{
int ret;
if (PORT->IPv6[i])
PORT->udpsock[i]=socket(AF_INET6,SOCK_DGRAM,0);
else
PORT->udpsock[i]=socket(AF_INET,SOCK_DGRAM,0);
if (PORT->udpsock[i] == INVALID_SOCKET)
{
WritetoConsole("Failed to create UDP socket");
err = WSAGetLastError();
continue;
}
ioctl (PORT->udpsock[i],FIONBIO,&param);
setsockopt (PORT->udpsock[i],SOL_SOCKET,SO_BROADCAST,(const char FAR *)&bcopt,4);
#ifndef WIN32
if (PORT->IPv6[i])
if (setsockopt(PORT->udpsock[i], IPPROTO_IPV6, IPV6_V6ONLY, &param, sizeof(param)) < 0)
perror("setting option IPV6_V6ONLY");
#endif
if (PORT->IPv6[i])
{
sinx.sinx.sin_family = AF_INET6;
memset (&sinx.sinx6.sin6_addr, 0, 16);
}
else
{
sinx.sinx.sin_family = AF_INET;
sinx.sinx.sin_addr.s_addr = INADDR_ANY;
}
sinx.sinx.sin_port = htons(PORT->udpport[i]);
if (PORT->IPv6[i])
ret = bind(PORT->udpsock[i], (struct sockaddr *) &sinx.sinx, sizeof(sinx.sinx6));
else
ret = bind(PORT->udpsock[i], (struct sockaddr *) &sinx.sinx, sizeof(sinx.sinx));
if (ret != 0)
{
// Bind Failed
err = WSAGetLastError();
sprintf(Msg, "Bind Failed for UDP socket %d - error code = %d", PORT->udpport[i], err);
WritetoConsole(Msg);
continue;
}
}
// Open any TCP sockets
while (index < PORT->arp_table_len)
{
arp = &PORT->arp_table[index++];
if (arp->TCPMode == TCPMaster)
{
arp->TCPBuffer=malloc(4000);
arp->TCPState = 0;
if (arp->TCPThreadID == 0)
{
arp->TCPThreadID = _beginthread(TCPConnectThread, 0, arp);
Debugprintf("TCP Connect thread created for %s Handle %x", arp->hostname, arp->TCPThreadID);
}
continue;
}
if (arp->TCPMode == TCPSlave)
{
OpenListeningSocket(PORT, arp);
}
}
}
int OpenListeningSocket(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp)
{
char Msg[255];
struct sockaddr_in * psin;
BOOL bOptVal = TRUE;
struct sockaddr_in local_sin; /* Local socket - internet style */
u_long param = 1;
arp->TCPBuffer = malloc(4000);
arp->TCPState = 0;
arp->TCPListenSock = socket(AF_INET, SOCK_STREAM, 0);
ioctl (arp->TCPListenSock, FIONBIO, &param);
if (arp->TCPListenSock == INVALID_SOCKET)
{
sprintf(Msg, "socket() failed error %d", WSAGetLastError());
WritetoConsole(Msg);
return FALSE;
}
// Debugprintf("TCP Listening Socket Created - socket %d port %d ", arp->TCPListenSock, arp->port);
setsockopt (arp->TCPListenSock, SOL_SOCKET, SO_REUSEADDR, (char *)&param,4);
psin=&local_sin;
psin->sin_family = AF_INET;
psin->sin_addr.s_addr = htonl(INADDR_ANY); // Local Host Only
psin->sin_port = htons(arp->port); /* Convert to network ordering */
if (bind(arp->TCPListenSock , (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
{
sprintf(Msg, "bind(sock) failed Port %d Error %d\n", arp->port, WSAGetLastError());
Debugprintf(Msg);
closesocket(arp->TCPListenSock);
return FALSE;
}
if (listen(arp->TCPListenSock, 1) < 0)
{
sprintf(Msg, "listen(sock) failed Error %d", WSAGetLastError());
Debugprintf(Msg);
closesocket(arp->TCPListenSock);
return FALSE;
}
arp->TCPState = TCPListening;
return TRUE;
}
void CloseSockets(struct AXIPPORTINFO * PORT)
{
int i;
int index = 0;
struct arp_table_entry * arp;
if (PORT->needip)
closesocket(PORT->sock);
for (i=0;i<PORT->NumberofUDPPorts;i++)
{
closesocket(PORT->udpsock[i]);
}
// Close any open or listening TCP sockets
while (index < PORT->arp_table_len)
{
arp = &PORT->arp_table[index++];
if (arp->TCPMode == TCPMaster)
{
if (arp->TCPState)
{
closesocket(arp->TCPSock);
arp->TCPSock = 0;
}
continue;
}
if (arp->TCPMode == TCPSlave)
{
if (arp->TCPState)
{
closesocket(arp->TCPSock);
arp->TCPSock = 0;
}
closesocket(arp->TCPListenSock);
continue;
}
}
return ;
}
#ifndef LINBPQ
static LRESULT CALLBACK AXResWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HFONT hOldFont ;
char line[100];
char outcall[10];
int index,displayline;
struct AXIPPORTINFO * PORT;
MINMAXINFO * mmi;
int nScrollCode,nPos;
int i, Port;
char Flags[10];
struct arp_table_entry * arp;
// Find our PORT Entry
for (Port = 1; Port < 33; Port++)
{
PORT = Portlist[Port];
if (PORT == NULL)
continue;
if (PORT->hResWnd == hWnd)
break;
}
if (PORT == NULL)
return DefMDIChildProc(hWnd, message, wParam, lParam);
i=1;
switch (message)
{
case WM_GETMINMAXINFO:
mmi = (MINMAXINFO *)lParam;
mmi->ptMaxSize.x = 600;
mmi->ptMaxSize.y = PORT->MaxResWindowlength;
mmi->ptMaxTrackSize.x = 55600;
mmi->ptMaxTrackSize.y = PORT->MaxResWindowlength;
break;
case WM_MDIACTIVATE:
{
// Set the system info menu when getting activated
if (lParam == (LPARAM) hWnd)
{
// Activate
RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT_PTR)PORT->hResMenu, "Actions");
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM)hBaseMenu, (LPARAM)hWndMenu);
}
else
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
DrawMenuBar(FrameWnd);
return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
}
case WM_CHAR:
if (PORT->MHEnabled == FALSE && PORT->MHAvailable)
{
PORT->MHEnabled=TRUE;
CreateMHWindow(PORT);
ShowWindow(PORT->hMHWnd, SW_RESTORE); // In case Start Minimized set
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
if (wmId == BPQREREAD)
{
CloseSockets(PORT);
if (ProcessConfig())
{
FreeConfig();
ReadConfigFile(Port);
}
else
Consoleprintf("Failed to reread config file - leaving config unchanged");
_beginthread(OpenSockets, 0, PORT);
ResolveDelay = 2;
InvalidateRect(hWnd,NULL,TRUE);
return 0;
}
if (wmId == BPQADDARP)
{
if (PORT->ConfigWnd == 0)
{
PORT->ConfigWnd=CreateDialog(hInstance, ConfigClassName, 0, NULL);
if (!PORT->ConfigWnd)
{
return (FALSE);
}
ShowWindow(PORT->ConfigWnd, SW_SHOW);
UpdateWindow(PORT->ConfigWnd);
}
SetForegroundWindow(PORT->ConfigWnd);
return(0);
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
case WM_SYSCOMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
switch (wmId)
{
case SC_RESTORE:
PORT->ResMinimized = FALSE;
SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
break;
case SC_MINIMIZE:
PORT->ResMinimized = TRUE;
break;
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
case WM_VSCROLL:
nScrollCode = (int) LOWORD(wParam); // scroll bar value
nPos = (short int) HIWORD(wParam); // scroll box position
//hwndScrollBar = (HWND) lParam; // handle of scroll bar
if (nScrollCode == SB_LINEUP || nScrollCode == SB_PAGEUP)
{
PORT->baseline--;
if (PORT->baseline <0)
PORT->baseline=0;
}
if (nScrollCode == SB_LINEDOWN || nScrollCode == SB_PAGEDOWN)
{
PORT->baseline++;
if (PORT->baseline > PORT->arp_table_len)
PORT->baseline = PORT->arp_table_len;
}
if (nScrollCode == SB_THUMBTRACK)
{
PORT->baseline=nPos;
}
SetScrollPos(hWnd,SB_VERT,PORT->baseline,TRUE);
InvalidateRect(hWnd,NULL,TRUE);
break;
case WM_PAINT:
hdc = BeginPaint (hWnd, &ps);
hOldFont = SelectObject( hdc, hFont) ;
index = PORT->baseline;
displayline=0;
while (index < PORT->arp_table_len)
{
arp = &PORT->arp_table[index];
Flags[0] = 0;
if (arp->BCFlag)
strcat(Flags, "B ");
if (arp->TCPState == TCPConnected)
strcat(Flags, "C ");
if (arp->AutoAdded)
strcat(Flags, "A");
if (arp->ResolveFlag && arp->error != 0)
{
// resolver error - Display Error Code
sprintf(PORT->hostaddr,"Error %d",arp->error);
}
else
{
if (arp->IPv6)
Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, PORT->hostaddr, TRUE);
else
Format_Addr((unsigned char *)&arp->destaddr.sin_addr, PORT->hostaddr, FALSE);
}
CONVFROMAX25(arp->callsign,outcall);
if (arp->port == arp->SourcePort)
i=sprintf(line,"%.10s = %.64s %d = %-.30s %s ",
outcall,
arp->hostname,
arp->port,
PORT->hostaddr,
Flags);
else
i=sprintf(line,"%.10s = %.64s %d<%d = %-.30s %s ",
outcall,
arp->hostname,
arp->port,
arp->SourcePort,
PORT->hostaddr,
Flags);
TextOut(hdc, 0, (displayline++)*14+2, line, i);
index++;
}
SelectObject( hdc, hOldFont ) ;
EndPaint (hWnd, &ps);
break;
case WM_DESTROY:
// PostQuitMessage(0);
break;
default:
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
LRESULT FAR PASCAL ConfigWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
int cmd,id,i;
HWND hwndChild;
BOOL OK1,OK2,OK3;
char call[10], host[65];
int Interval;
int calllen;
int port;
char axcall[7];
BOOL UDPFlag, BCFlag;
struct AXIPPORTINFO * PORT;
for (i=1; i <= MAXBPQPORTS; i++)
{
PORT = Portlist[i];
if (PORT == NULL)
continue;
if (PORT->ConfigWnd == hWnd)
break;
}
switch (message)
{
case WM_CTLCOLORDLG:
return (LRESULT)bgBrush;
case WM_COMMAND:
id = LOWORD(wParam);
hwndChild = (HWND)(UINT)lParam;
cmd = HIWORD(wParam);
switch (id)
{
case ID_SAVE:
OK1=GetDlgItemText(PORT->ConfigWnd,1001,(LPSTR)call,10);
OK2=GetDlgItemText(PORT->ConfigWnd,1002,(LPSTR)host,64);
OK3=1;
for (i=0;i<7;i++)
call[i] = toupper(call[i]);
UDPFlag=IsDlgButtonChecked(PORT->ConfigWnd,1004);
BCFlag=IsDlgButtonChecked(PORT->ConfigWnd,1005);
if (UDPFlag)
port=GetDlgItemInt(PORT->ConfigWnd,1003,&OK3,FALSE);
else
port=0;
Interval=0;
if (OK1 && OK2 && OK3==1)
{
if (convtoax25(call,axcall,&calllen))
{
add_arp_entry(PORT, axcall,0,calllen,port,host,Interval, BCFlag, FALSE, 0, port, FALSE, 0);
ResolveDelay = 2;
return(DestroyWindow(hWnd));
}
}
// Validation failed
if (!OK1) SetDlgItemText(PORT->ConfigWnd,1001,"????");
if (!OK2) SetDlgItemText(PORT->ConfigWnd,1002,"????");
if (!OK3) SetDlgItemText(PORT->ConfigWnd,1003,"????");
break;
case ID_CANCEL:
return(DestroyWindow(hWnd));
}
break;
// case WM_CLOSE:
// return(DestroyWindow(hWnd));
case WM_DESTROY:
PORT->ConfigWnd=0;
return(0);
}
return (DefWindowProc(hWnd, message, wParam, lParam));
}
#endif
static void CreateResolverWindow(struct AXIPPORTINFO * PORT)
{
#ifndef LINBPQ
int WindowParam;
WNDCLASS wc;
char WindowTitle[100];
int retCode, Type, Vallen;
HKEY hKey=0;
char Size[80];
HWND hResWnd;
char Key[80];
RECT Rect = {0, 0, 300, 300};
int Top, Left, Width, Height;
sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\PACTOR\\PORT%d", PORT->Port);
retCode = RegOpenKeyEx (REGTREE, Key, 0, KEY_QUERY_VALUE, &hKey);
if (retCode == ERROR_SUCCESS)
{
Vallen=80;
retCode = RegQueryValueEx(hKey,"ResSize",0,
(ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
if (retCode == ERROR_SUCCESS)
sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &PORT->ResMinimized);
if (Rect.top < - 500 || Rect.left < - 500)
{
Rect.left = 0;
Rect.top = 0;
Rect.right = 600;
Rect.bottom = 400;
}
if (Rect.top < OffsetH) // Make sure not off top of MDI frame
{
int Error = OffsetH - Rect.top;
Rect.top += Error;
Rect.bottom += Error;
}
RegCloseKey(hKey);
}
Top = Rect.top;
Left = Rect.left;
Width = Rect.right - Left;
Height = Rect.bottom - Top;
// Register the window classes
wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
wc.lpfnWndProc = (WNDPROC)AXResWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL ;
wc.lpszClassName = "AXAppName";
RegisterClass(&wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = ConfigWndProc;
wc.lpszClassName = ConfigClassName;
RegisterClass(&wc);
WindowParam = WS_OVERLAPPEDWINDOW | WS_VSCROLL;
sprintf(WindowTitle,"AXIP Port %d Resolver", PORT->Port);
PORT->hResWnd = hResWnd = CreateMDIWindow("AXAppName", WindowTitle, WindowParam,
Left - (OffsetW /2), Top - OffsetH + 4, Width, Height, ClientWnd, hInstance, 1234);
PORT->hResMenu = CreatePopupMenu();
AppendMenu(PORT->hResMenu, MF_STRING, BPQREREAD, "ReRead Config");
AppendMenu(PORT->hResMenu, MF_STRING, BPQADDARP, "Add Entry");
SetScrollRange(hResWnd,SB_VERT, 0, PORT->arp_table_len, TRUE);
if (PORT->ResMinimized)
ShowWindow(hResWnd, SW_SHOWMINIMIZED);
else
ShowWindow(hResWnd, SW_RESTORE);
#endif
}
extern HWND hWndPopup;
static void ResolveNames(struct AXIPPORTINFO * PORT)
{
int count = 0;
PORT->ResolveNamesThreadId = GetCurrentThreadId(); // Detect if another started
while(TRUE)
{
count++; // So we can trap first few loops
ResolveDelay = 15 * 60;
for (PORT->ResolveIndex=0; PORT->ResolveIndex < PORT->arp_table_len; PORT->ResolveIndex++)
{
struct arp_table_entry * arp = &PORT->arp_table[PORT->ResolveIndex];
if (arp->ResolveFlag)
{
struct addrinfo hints, *res = 0;
int n;
BOOL UseV6 = FALSE;
BOOL ForceV4 = FALSE;
if (_memicmp(arp->hostname, "ipv6:", 5) == 0)
UseV6 = TRUE;
else if (_memicmp(arp->hostname, "ipv4:", 5) == 0)
ForceV4 = TRUE;
memset(&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_DGRAM;
if (UseV6)
{
hints.ai_family = AF_INET6; // use IPv6
n = getaddrinfo(&arp->hostname[5], NULL, &hints, &res);
}
else if (ForceV4)
{
hints.ai_family = AF_INET; // use IPv4
n = getaddrinfo(&arp->hostname[5], NULL, &hints, &res);
}
else if (PORT->PortIPv6) // Can use IPv6
{
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
n = getaddrinfo(arp->hostname, NULL, &hints, &res);
}
else
{
hints.ai_family = AF_INET; // use IPv4 only
n = getaddrinfo(arp->hostname, NULL, &hints, &res);
}
if (res)
{
arp->error = 0;
if (res->ai_family == AF_INET)
{
memcpy(&arp->destaddr.sin_addr.s_addr, &res->ai_addr->sa_data[2], 4);
arp->IPv6 = FALSE;
arp->destaddr.sin_family = AF_INET;
// Debugprintf("AXIP %s = %d.%d.%d.%d", arp->hostname, (UCHAR)res->ai_addr->sa_data[2],
// (UCHAR)res->ai_addr->sa_data[3], (UCHAR)res->ai_addr->sa_data[4], (UCHAR)res->ai_addr->sa_data[5]);
}
else
{
struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)res->ai_addr;
memcpy(&arp->destaddr6.sin6_addr, &sa6->sin6_addr, 16);
arp->IPv6 = TRUE;
arp->destaddr.sin_family = AF_INET6;
}
arp->destaddr.sin_port = htons(arp->port);
freeaddrinfo(res);
}
else
{
PORT->arp_table[PORT->ResolveIndex].error = WSAGetLastError();
if (count < 4)
ResolveDelay = 30; // if errors try again soon
}
}
}
SaveAXIPCache(PORT);
#ifndef LINBPQ
InvalidateRect(PORT->hResWnd,NULL,TRUE);
#endif
while(ResolveDelay-- > 0)
{
if (pthread_equal(PORT->ResolveNamesThreadId, GetCurrentThreadId()) == FALSE)
{
Debugprintf("AXIP Resolve thread %x redundant - closing", GetCurrentThreadId());
return;
}
Sleep(1000);
}
}
Debugprintf("AXIP Resolve thread exitied");
}
#ifndef LINBPQ
LRESULT CALLBACK MHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HFONT hOldFont ;
char line[100];
char outcall[10];
HGLOBAL hMem;
struct AXIPPORTINFO * PORT;
int index,displayline;
MINMAXINFO * mmi;
int nScrollCode,nPos;
int i;
for (i=1; i <= MAXBPQPORTS; i++)
{
PORT = Portlist[i];
if (PORT == NULL)
continue;
if (PORT->hMHWnd == hWnd)
break;
}
if (PORT == NULL)
return DefMDIChildProc(hWnd, message, wParam, lParam);
switch (message)
{
case WM_GETMINMAXINFO:
mmi = (MINMAXINFO *)lParam;
mmi->ptMaxSize.x = 600;
mmi->ptMaxSize.y = PORT->MaxMHWindowlength;
mmi->ptMaxTrackSize.x = 600;
mmi->ptMaxTrackSize.y = PORT->MaxMHWindowlength;
break;
case WM_MDIACTIVATE:
{
// Set the system info menu when getting activated
if (lParam == (LPARAM) hWnd)
{
// Activate
RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)PORT->hMHMenu, "Edit");
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM)hBaseMenu, (LPARAM)hWndMenu);
}
else
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
DrawMenuBar(FrameWnd);
return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
}
case WM_COMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
switch (wmId) {
case BPQCLEAR:
memset(PORT->MHTable, 0, sizeof(PORT->MHTable));
InvalidateRect(hWnd,NULL,TRUE);
return 0;
case BPQCOPY:
hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, MaxMHEntries * 100);
if (hMem != 0)
{
if (OpenClipboard(hWnd))
{
CopyScreentoBuffer(GlobalLock(hMem), PORT);
GlobalUnlock(hMem);
EmptyClipboard();
SetClipboardData(CF_TEXT,hMem);
CloseClipboard();
}
else
{
GlobalFree(hMem);
}
}
return 0;
default:
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
case WM_SYSCOMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
switch (wmId)
{
case SC_RESTORE:
PORT->MHMinimized = FALSE;
SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
break;
case SC_MINIMIZE:
PORT->MHMinimized = TRUE;
break;
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
case WM_VSCROLL:
nScrollCode = (int) LOWORD(wParam); // scroll bar value
nPos = (short int) HIWORD(wParam); // scroll box position
//hwndScrollBar = (HWND) lParam; // handle of scroll bar
if (nScrollCode == SB_LINEUP || nScrollCode == SB_PAGEUP)
{
PORT->mhbaseline--;
if (PORT->mhbaseline <0)
PORT->mhbaseline=0;
}
if (nScrollCode == SB_LINEDOWN || nScrollCode == SB_PAGEDOWN)
{
PORT->mhbaseline++;
if (PORT->mhbaseline > PORT->CurrentMHEntries)
PORT->mhbaseline = PORT->CurrentMHEntries;
}
if (nScrollCode == SB_THUMBTRACK)
{
PORT->mhbaseline=nPos;
}
SetScrollPos(hWnd,SB_VERT,PORT->mhbaseline,TRUE);
InvalidateRect(hWnd,NULL,TRUE);
break;
case WM_PAINT:
hdc = BeginPaint (hWnd, &ps);
hOldFont = SelectObject( hdc, hFont) ;
index = PORT->mhbaseline;
displayline=0;
PORT->CurrentMHEntries = 0;
while (index < MaxMHEntries)
{
if (PORT->MHTable[index].proto != 0)
{
char Addr[80];
Format_Addr((unsigned char *)&PORT->MHTable[index].ipaddr6, Addr, PORT->MHTable[index].IPv6);
CONVFROMAX25(PORT->MHTable[index].callsign,outcall);
i=sprintf(line,"%-10s%-15s %c %-6d %-25s%c",outcall,
Addr,
PORT->MHTable[index].proto,
PORT->MHTable[index].port,
asctime(gmtime( &PORT->MHTable[index].LastHeard )),
(PORT->MHTable[index].Keepalive == 0) ? ' ' : 'K');
line[i-2]= ' '; // Clear CR returned by asctime
TextOut(hdc,0,(displayline++)*14+2,line,i);
PORT->CurrentMHEntries ++;
}
index++;
}
if (PORT->MaxMHWindowlength < PORT->CurrentMHEntries * 14 + 40)
PORT->MaxMHWindowlength = PORT->CurrentMHEntries * 14 + 40;
SelectObject( hdc, hOldFont ) ;
EndPaint (hWnd, &ps);
break;
case WM_DESTROY:
PORT->MHEnabled=FALSE;
break;
default:
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
#endif
BOOL CopyScreentoBuffer(char * buff, struct AXIPPORTINFO * PORT)
{
int index;
char outcall[10];
index = 0;
while (index < MaxMHEntries)
{
if (PORT->MHTable[index].proto != 0)
{
CONVFROMAX25(PORT->MHTable[index].callsign,outcall);
buff+=sprintf(buff,"%-10s%-15s %c %-6d %-26s",outcall,
inet_ntoa(PORT->MHTable[index].ipaddr),
PORT->MHTable[index].proto,
PORT->MHTable[index].port,
asctime(gmtime( &PORT->MHTable[index].LastHeard )));
}
*(buff-2)=13;
*(buff-1)=10;
index++;
}
*(buff)=0;
return 0;
}
void CreateMHWindow(struct AXIPPORTINFO * PORT)
{
#ifndef LINBPQ
WNDCLASS wc;
char WindowTitle[100];
int retCode, Type, Vallen;
HKEY hKey=0;
char Size[80];
HWND hMHWnd;
char Key[80];
RECT Rect = {0, 0, 300, 300};
int Top, Left, Width, Height;
sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\PACTOR\\PORT%d", PORT->Port);
retCode = RegOpenKeyEx (REGTREE, Key, 0, KEY_QUERY_VALUE, &hKey);
if (retCode == ERROR_SUCCESS)
{
Vallen=80;
retCode = RegQueryValueEx(hKey,"MHSize",0,
(ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
if (retCode == ERROR_SUCCESS)
sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &PORT->MHMinimized);
if (Rect.top < - 500 || Rect.left < - 500)
{
Rect.left = 0;
Rect.top = 0;
Rect.right = 600;
Rect.bottom = 400;
}
if (Rect.top < OffsetH) // Make sure not off top of MDI frame
{
int Error = OffsetH - Rect.top;
Rect.top += Error;
Rect.bottom += Error;
}
RegCloseKey(hKey);
}
Top = Rect.top;
Left = Rect.left;
Width = Rect.right - Left;
Height = Rect.bottom - Top;
PORT->MaxMHWindowlength = Height;
wc.style = CS_HREDRAW | CS_VREDRAW ;//| CS_NOCLOSE;
wc.lpfnWndProc = (WNDPROC)MHWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL ;
wc.lpszClassName = "MHAppName";
RegisterClass(&wc);
sprintf(WindowTitle,"AXIP Port %d MHEARD", PORT->Port);
PORT->hMHWnd = hMHWnd = CreateMDIWindow("MHAppName", WindowTitle,
WS_OVERLAPPEDWINDOW | WS_VSCROLL,
Left - (OffsetW /2), Top - OffsetH, Width, Height, ClientWnd, hInstance, 1234);
PORT->hMHMenu = CreatePopupMenu();
AppendMenu(PORT->hMHMenu, MF_STRING, BPQCOPY, "Copy");
AppendMenu(PORT->hMHMenu, MF_STRING, BPQCLEAR, "Clear");
if (PORT->MHMinimized)
ShowWindow(hMHWnd, SW_SHOWMINIMIZED);
else
ShowWindow(hMHWnd, SW_RESTORE);
#endif
}
unsigned short int compute_crc(unsigned char *buf,int len)
{
unsigned short fcs = 0xffff;
int i;
for(i = 0; i < len; i++)
fcs = (fcs >>8 ) ^ CRCTAB[(fcs ^ buf[i]) & 0xff];
return fcs;
}
/*
static const unsigned short ccittTab[] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
unsigned short int compute_crc_ccitt(unsigned char *buf, int len)
{
int i;
unsigned short fcs = 0;
for(i = 0; i < len; i++)
fcs = (fcs >>8 ) ^ ccittTab[(fcs ^ buf[i]) & 0xff];
return fcs;
}
union {
unsigned short m_crc16;
unsigned char m_crc8[2U];
} fcs;
unsigned short CCCITTChecksum(unsigned char* data, unsigned int length)
{
int i;
fcs.m_crc16 = 0;
for (i = 0U; i < length; i++)
fcs.m_crc16 = (fcs.m_crc8[0U] << 8) ^ ccittTab[fcs.m_crc8[1U] ^ data[i]];
return fcs.m_crc16;
}
*/
static BOOL ReadConfigFile(int Port)
{
/* Linux Format
broadcast QST-0 NODES-0
#
# ax.25 route definition, define as many as you need.
# format is route (call/wildcard) (ip host at destination)
# ssid of 0 routes all ssid's
#
# route <destcall> <destaddr> [flags]
#
# Valid flags are:
# b - allow broadcasts to be transmitted via this route
# d - this route is the default route
#
#route vk2sut-0 44.136.8.68 b
#route vk5xxx 44.136.188.221 b
#route vk2abc 44.1.1.1
#
*/
//UDP 9999 # Port we listen on
//MAP G8BPQ-7 10.2.77.1 # IP 93 for compatibility
//MAP BPQ7 10.2.77.1 UDP 2222 # UDP port to send to
//MAP BPQ8 10.2.77.2 UDP 3333 # UDP port to send to
char buf[256],errbuf[256];
HKEY hKey=0;
char * Config;
struct AXIPPORTINFO * PORT;
Config = PortConfig[Port];
if (Portlist[Port]) // Already defined, so must be re-read
{
PORT = Portlist[Port];
PORT->NumberofBroadcastAddreses = 0;
PORT->needip = FALSE;
PORT->NeedTCP = FALSE;
PORT->MHAvailable = FALSE;
PORT->MHEnabled = FALSE;
PORT->NumberofUDPPorts = 0;
PORT->NeedResolver = FALSE;
PORT->arp_table_len = 0;
memset(PORT->arp_table, 0, sizeof(struct arp_table_entry) * MAX_ENTRIES);
PORT->AutoAddARP = FALSE;
PORT->AutoAddBC = FALSE;
}
else
{
Portlist[Port] = PORT = zalloc(sizeof (struct AXIPPORTINFO));
}
PORT->Checkifcanreply = TRUE;
if (Config)
{
char * ptr1 = Config, * ptr2;
// Using config from bpq32.cfg
ptr2 = strchr(ptr1, 13);
while(ptr2)
{
memcpy(buf, ptr1, ptr2 - ptr1);
buf[ptr2 - ptr1] = 0;
ptr1 = ptr2 + 2;
ptr2 = strchr(ptr1, 13);
strcpy(errbuf,buf); // save in case of error
if (!ProcessLine(buf, PORT))
{
WritetoConsole("BPQAXIP - Bad config record");
WritetoConsole(errbuf);
WritetoConsole("\n");
}
}
if (PORT->NumberofUDPPorts > MAXUDPPORTS)
{
n=sprintf(buf,"BPQAXIP - Too many UDP= lines - max is %d\n", MAXUDPPORTS);
WritetoConsole(buf);
}
return TRUE;
}
WritetoConsole("No Configuration info in bpq32.cfg");
return FALSE;
}
static int ProcessLine(char * buf, struct AXIPPORTINFO * PORT)
{
char * ptr;
char * p_call;
char * p_ipad;
char * p_UDP;
char * p_udpport;
char * p_Interval;
int calllen;
int port, SourcePort;
int bcflag;
char axcall[7];
int Interval;
int noUpdate=FALSE;
int TCPMode;
ptr = strtok(buf, " \t\n\r");
if(ptr == NULL) return (TRUE);
if(*ptr =='#') return (TRUE); // comment
if(*ptr ==';') return (TRUE); // comment
if(_stricmp(ptr,"UDP") == 0)
{
if (PORT->NumberofUDPPorts > MAXUDPPORTS) PORT->NumberofUDPPorts--;
p_udpport = strtok(NULL, " ,\t\n\r");
if (p_udpport == NULL) return (FALSE);
PORT->udpport[PORT->NumberofUDPPorts] = atoi(p_udpport);
if (PORT->udpport[PORT->NumberofUDPPorts] == 0) return (FALSE);
ptr = strtok(NULL, " \t\n\r");
if (ptr && _stricmp(ptr, "ipv6") == 0)
{
PORT->PortIPv6 = TRUE;
PORT->IPv6[PORT->NumberofUDPPorts] = TRUE;
}
PORT->NumberofUDPPorts++;
return (TRUE);
}
if(_stricmp(ptr,"MHEARD") == 0)
{
PORT->MHEnabled = TRUE;
PORT->MHAvailable = TRUE;
return (TRUE);
}
if(_stricmp(ptr,"DONTCHECKSOURCECALL") == 0)
{
PORT->Checkifcanreply = FALSE;
return (TRUE);
}
if(_stricmp(ptr,"AUTOADDMAP") == 0)
{
PORT->AutoAddARP = TRUE;
PORT->AutoAddBC = TRUE;
return (TRUE);
}
if(_stricmp(ptr,"AUTOADDQUIET") == 0)
{
PORT->AutoAddARP = TRUE;
PORT->AutoAddBC = FALSE;
return (TRUE);
}
if(_stricmp(ptr,"MAP") == 0)
{
p_call = strtok(NULL, " \t\n\r");
if (p_call == NULL) return (FALSE);
_strupr(p_call);
if (_stricmp(p_call, "DUMMY") == 0)
{
Consoleprintf("MAP DUMMY is no longer needed - statement ignored");
return TRUE;
}
p_ipad = strtok(NULL, " \t\n\r");
if (p_ipad == NULL) return (FALSE);
p_UDP = strtok(NULL, " \t\n\r");
Interval=0;
port=0; // Raw IP
bcflag=0;
TCPMode=0;
SourcePort = 0;
//
// Look for (optional) KEEPALIVE, DYNAMIC, UDP or BROADCAST params
//
while (p_UDP != NULL)
{
if (_stricmp(p_UDP,"NOUPDATE") == 0)
{
noUpdate = TRUE;
p_UDP = strtok(NULL, " \t\n\r");
continue;
}
if (_stricmp(p_UDP,"KEEPALIVE") == 0)
{
p_Interval = strtok(NULL, " \t\n\r");
if (p_Interval == NULL) return (FALSE);
Interval = atoi(p_Interval);
p_UDP = strtok(NULL, " \t\n\r");
continue;
}
if (_stricmp(p_UDP,"UDP") == 0)
{
p_udpport = strtok(NULL, " \t\n\r");
if (p_udpport == NULL) return (FALSE);
port = atoi(p_udpport);
p_UDP = strtok(NULL, " \t\n\r");
continue;
}
if (_stricmp(p_UDP,"SOURCEPORT") == 0)
{
p_udpport = strtok(NULL, " \t\n\r");
if (p_udpport == NULL) return (FALSE);
SourcePort = atoi(p_udpport);
p_UDP = strtok(NULL, " \t\n\r");
continue;
}
if (_stricmp(p_UDP,"TCP-Master") == 0)
{
p_udpport = strtok(NULL, " \t\n\r");
if (p_udpport == NULL) return (FALSE);
port = atoi(p_udpport);
p_UDP = strtok(NULL, " \t\n\r");
TCPMode=TCPMaster;
continue;
}
if (_stricmp(p_UDP,"TCP-Slave") == 0)
{
p_udpport = strtok(NULL, " \t\n\r");
if (p_udpport == NULL) return (FALSE);
port = atoi(p_udpport);
p_UDP = strtok(NULL, " \t\n\r");
TCPMode = TCPSlave;
continue;
}
if (_stricmp(p_UDP,"B") == 0)
{
bcflag =TRUE;
p_UDP = strtok(NULL, " \t\n\r");
continue;
}
if ((*p_UDP == ';') || (*p_UDP == '#')) break; // Comment on end
return FALSE;
}
if (convtoax25(p_call,axcall,&calllen))
{
if (SourcePort == 0)
SourcePort = port;
add_arp_entry(PORT, axcall, 0, calllen, port, p_ipad, Interval, bcflag, FALSE, TCPMode, SourcePort, FALSE, noUpdate);
return (TRUE);
}
} // End of Process MAP
if(_stricmp(ptr,"BROADCAST") == 0)
{
p_call = strtok(NULL, " \t\n\r");
if (p_call == NULL) return (FALSE);
if (convtoax25(p_call,axcall,&calllen))
{
add_bc_entry(PORT, axcall,calllen);
return (TRUE);
}
return (FALSE); // Failed convtoax25
}
//
// Bad line
//
return (FALSE);
}
int CONVFROMAX25(char * incall, char * outcall)
{
int in,out=0;
unsigned char chr;
//
// CONVERT AX25 FORMAT CALL IN incall TO NORMAL FORMAT IN out
// RETURNS LENGTH
//
memset(outcall,0x20,9);
outcall[9]=0;
for (in=0;in<6;in++)
{
chr=incall[in];
if (chr == 0x40)
break;
chr >>= 1;
outcall[out++]=chr;
}
chr=incall[6]; // ssid
chr >>= 1;
chr &= 15;
if (chr > 0)
{
outcall[out++]='-';
if (chr > 9)
{
chr-=10;
outcall[out++]='1';
}
chr+=48;
outcall[out++]=chr;
}
return (out);
}
BOOL convtoax25(unsigned char * callsign, unsigned char * ax25call,int * calllen)
{
int i;
memset(ax25call,0x40,6); // in case short
ax25call[6]=0x60; // default SSID
for (i=0;i<7;i++)
{
if (callsign[i] == '-')
{
//
// process ssid and return
//
i = atoi(&callsign[i+1]);
if (i < 16)
{
ax25call[6] |= i<<1;
*calllen = 7; // include ssid in test
return (TRUE);
}
return (FALSE);
}
if (callsign[i] == 0 || callsign[i] == ' ')
{
//
// End of call - no ssid
//
*calllen = 6; // wildcard ssid
return (TRUE);
}
ax25call[i] = callsign[i] << 1;
}
//
// Too many chars
//
return (FALSE);
}
BOOL add_arp_entry(struct AXIPPORTINFO * PORT, UCHAR * call, UCHAR * ip, int len, int port,
UCHAR * name, int keepalive, BOOL BCFlag, BOOL AutoAdded, int TCPFlag, int SourcePort, BOOL IPv6, int noUpdate)
{
struct arp_table_entry * arp;
if (PORT->arp_table_len == MAX_ENTRIES)
//
// Table full
//
return (FALSE);
arp = &PORT->arp_table[PORT->arp_table_len];
if (SourcePort)
arp->SourcePort = SourcePort;
else
arp->SourcePort = port;
arp->PORT = PORT;
if (port == 0) PORT->needip = 1; // Enable Raw IP Mode
arp->ResolveFlag=TRUE;
PORT->NeedResolver=TRUE;
memcpy (&arp->callsign,call,7);
strncpy((char *)&arp->hostname,name,64);
arp->len = len;
arp->port = port;
keepalive+=9;
keepalive/=10;
arp->keepalive = keepalive;
arp->keepaliveinit = keepalive;
arp->BCFlag = BCFlag;
arp->AutoAdded = AutoAdded;
arp->TCPMode = TCPFlag;
arp->noUpdate = noUpdate;
PORT->arp_table_len++;
if (PORT->MaxResWindowlength < (PORT->arp_table_len * 14) + 70)
PORT->MaxResWindowlength = (PORT->arp_table_len * 14) + 70;
PORT->NeedResolver |= TCPFlag; // Need Resolver window to handle tcp socket messages
PORT->NeedTCP |= TCPFlag;
if (ip)
{
// Only have an IP address if dynamically added - so update destaddr
if (IPv6)
{
memcpy(&arp->destaddr6.sin6_addr, ip, 16);
arp->IPv6 = TRUE;
arp->destaddr.sin_family = AF_INET6;
}
else
{
memcpy(&arp->destaddr.sin_addr.s_addr, ip, 4);
arp->IPv6 = FALSE;
arp->destaddr.sin_family = AF_INET;
}
arp->destaddr.sin_port = htons(arp->port);
#ifndef LINBPQ
SetScrollRange(PORT->hResWnd,SB_VERT, 0, PORT->arp_table_len, TRUE);
InvalidateRect(PORT->hResWnd, NULL, TRUE);
#endif
}
return (TRUE);
}
BOOL add_bc_entry(struct AXIPPORTINFO * PORT, unsigned char * call, int len)
{
if (PORT->NumberofBroadcastAddreses == MAX_BROADCASTS)
//
// Table full
//
return (FALSE);
memcpy (PORT->BroadcastAddresses[PORT->NumberofBroadcastAddreses].callsign,call,7);
PORT->BroadcastAddresses[PORT->NumberofBroadcastAddreses].len = len;
PORT->NumberofBroadcastAddreses++;
return (TRUE);
}
int CheckKeepalives(struct AXIPPORTINFO * PORT)
{
int index=0;
SOCKET txsock;
struct arp_table_entry * arp;
if (PORT->arp_table_len >= MAX_ENTRIES)
{
Debugprintf("arp_table_len corrupt - %d", PORT->arp_table_len);
PORT->arp_table_len = MAX_ENTRIES - 1;
}
while (index < PORT->arp_table_len)
{
if (PORT->arp_table[index].keepalive != 0)
{
arp = &PORT->arp_table[index];
arp->keepalive--;
if (arp->keepalive == 0)
{
//
// Send Keepalive Packet
//
arp->keepalive=arp->keepaliveinit;
if (arp->error == 0)
{
if (arp->port == 0) txsock = PORT->sock; else txsock = PORT->udpsock[0];
sendto(txsock,"Keepalive",9,0,(struct sockaddr *)&arp->destaddr,sizeof(arp->destaddr));
}
}
}
index++;
}
// Decrement MH Keepalive flags
for (index = 0; index < MaxMHEntries; index++)
{
if (PORT->MHTable[index].Keepalive != 0)
PORT->MHTable[index].Keepalive--;
}
return (0);
}
BOOL CheckSourceisResolvable(struct AXIPPORTINFO * PORT, char * call, int Port, VOID * rxaddr)
{
// Makes sure we can reply to call before accepting message
int index = 0;
struct arp_table_entry * arp;
while (index < PORT->arp_table_len)
{
arp = &PORT->arp_table[index];
if (memcmp(arp->callsign, call, arp->len) == 0)
{
// Call is present - if AutoAdded, refresh IP address and Port
// Why not refreesh resolved addresses - if dynamic addr has changed
// this will give quicker response
if (arp->noUpdate == 0)
{
if (arp->IPv6)
{
struct sockaddr_in6 * SA6 = rxaddr;
memcpy(&arp->destaddr6.sin6_addr, &SA6->sin6_addr, 16);
}
else
{
struct sockaddr_in * SA = rxaddr;
memcpy(&arp->destaddr.sin_addr.s_addr, &SA->sin_addr, 4);
}
// Dont think I should update port
//arp->port = Port;
}
return 1; // Ok to process
}
index++;
}
return (0); // Not in list
}
int Update_MH_List(struct AXIPPORTINFO * PORT, UCHAR * ipad, char * call, char proto, short port, BOOL IPv6)
{
int index;
char callsign[7];
int SaveKeepalive=0;
struct MHTableEntry * MH;
memcpy(callsign,call,7);
callsign[6] &= 0x3e; // Mask non-ssid bits
for (index = 0; index < MaxMHEntries; index++)
{
MH = &PORT->MHTable[index];
if (MH->callsign[0] == 0)
{
// empty entry, so call not present. Move all down, and add to front
#ifdef WIN32
SetScrollRange(PORT->hMHWnd, SB_VERT, 0, index + 1, TRUE);
#endif
goto MoveEntries;
}
if (memcmp(MH->callsign,callsign,7) == 0 &&
memcmp(&MH->ipaddr, ipad, (MH->IPv6) ? 16 : 4) == 0 &&
MH->proto == proto &&
MH->port == port)
{
// Entry found, move preceeding entries down and put on front
SaveKeepalive = MH->Keepalive;
goto MoveEntries;
}
}
// Table full move MaxMHEntries-1 entries down, and add on front
index=MaxMHEntries-1;
MoveEntries:
//
// Move all preceeding entries down one, and put on front
//
if (index > 0)
memmove(&PORT->MHTable[1],&PORT->MHTable[0],index*sizeof(struct MHTableEntry));
MH = &PORT->MHTable[0];
memcpy(MH->callsign,callsign,7);
memcpy(&MH->ipaddr6, ipad, (IPv6) ? 16 : 4);
MH->proto = proto;
MH->port = port;
time(&MH->LastHeard);
MH->Keepalive = SaveKeepalive;
MH->IPv6 = IPv6;
#ifndef LINBPQ
InvalidateRect(PORT->hMHWnd,NULL,TRUE);
#endif
return 0;
}
int Update_MH_KeepAlive(struct AXIPPORTINFO * PORT, struct in_addr ipad, char proto, short port)
{
int index;
for (index = 0; index < MaxMHEntries; index++)
{
if (PORT->MHTable[index].callsign[0] == 0)
// empty entry, so call not present.
return 0;
if (memcmp(&PORT->MHTable[index].ipaddr,&ipad,4) == 0 &&
PORT->MHTable[index].proto == proto &&
PORT->MHTable[index].port == port)
{
PORT->MHTable[index].Keepalive = 30; // 5 Minutes at 10 sec ticks
return 0;
}
}
return 0;
}
int DumpFrameInHex(unsigned char * msg, int len)
{
char errmsg[100];
int i=0;
for (i=0;i<len;i+=16)
{
sprintf(errmsg,"%04x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ",
i, msg[i], msg[i+1],msg[i+2],msg[i+3],msg[i+4],msg[i+5],msg[i+6],msg[i+7],
msg[i+8],msg[i+9],msg[i+10],msg[i+11],msg[i+12],msg[i+13],msg[i+14],msg[i+15]);
OutputDebugString(errmsg);
}
return 0;
}
int GetMessageFromBuffer(struct AXIPPORTINFO * PORT, char * Buffer)
{
struct arp_table_entry * sockptr;
int index=0;
int MsgLen;
char * ptr, * ptr2;
ULONG param = 1;
// Look for data in tcp buffers
while (index < PORT->arp_table_len)
{
sockptr = &PORT->arp_table[index++];
if (sockptr->TCPMode)
{
if (sockptr->TCPState == TCPListening)
{
int addrlen;
SOCKET sock;
BOOL bOptVal = TRUE;
struct sockaddr sin;
addrlen = sizeof(struct sockaddr);
sock = accept(sockptr->TCPListenSock, &sin, &addrlen);
if (sock == INVALID_SOCKET)
{
int err = WSAGetLastError();
if (err == 10035 || err == 11)
continue;
if (err == 10038 || err == 9)
{
// Not a socket
closesocket(sockptr->TCPListenSock);
OpenListeningSocket(PORT, sockptr);
continue;
}
Debugprintf("AXIP accept() failed Error %d", err);
continue;
}
Debugprintf("AXIP Connect accepted - Socket %d Port %d", sock, sockptr->port);
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, 4) != SOCKET_ERROR)
Debugprintf("Set SO_KEEPALIVE: ON");
sockptr->TCPSock = sock;
sockptr->TCPState = TCPConnected;
}
if (sockptr->TCPState == TCPConnected)
{
int InputLen;
// Poll TCP Connection for data
// May have several messages per packet, or message split over packets
if (sockptr->InputLen > 3000) // Shouldnt have lines longer than this in text mode
{
sockptr->InputLen = 0;
}
ioctl(sockptr->TCPSock, FIONBIO, &param);
InputLen = recv(sockptr->TCPSock, &sockptr->TCPBuffer[sockptr->InputLen], 1000, 0);
if (InputLen == 0)
{
Debugprintf("TCP Close received for socket %d", sockptr->TCPSock);
if (sockptr->TCPMode == TCPSlave)
sockptr->TCPState = TCPListening;
else
sockptr->TCPState = 0;
closesocket(sockptr->TCPSock);
continue;
}
if (InputLen < 0)
{
int err = WSAGetLastError();
if (err == 10035 || err == 11)
InputLen = 0;
else
{
if (sockptr->TCPMode == TCPSlave)
sockptr->TCPState = TCPListening;
else
sockptr->TCPState = 0;
closesocket(sockptr->TCPSock);
continue;
}
}
sockptr->InputLen += InputLen;
if (sockptr->InputLen == 0)
{
sockptr->TCPOK++;
if (sockptr->TCPOK > 36000) // 60 MINS
{
if (sockptr->TCPSock)
{
Debugprintf("No Data for 60 Mins on Data Sock %d State %d",
sockptr->TCPListenSock, sockptr->TCPSock, sockptr->TCPState);
sockptr->TCPState = 0;
closesocket(sockptr->TCPSock);
sockptr->TCPSock = 0;
}
closesocket(sockptr->TCPListenSock);
OpenListeningSocket(PORT, sockptr);
sockptr->TCPOK = 0;
}
continue;
}
}
ptr = memchr(sockptr->TCPBuffer, FEND, sockptr->InputLen);
if (ptr) // FEND in buffer
{
ptr2 = &sockptr->TCPBuffer[sockptr->InputLen];
ptr++;
if (ptr == ptr2)
{
// Usual Case - single meg in buffer
MsgLen = sockptr->InputLen;
sockptr->InputLen = 0;
if (MsgLen > 1)
{
memcpy(Buffer, sockptr->TCPBuffer, MsgLen);
if (PORT->MHEnabled)
Update_MH_List(PORT, (UCHAR *)&sockptr->destaddr.sin_addr.s_addr, &Buffer[7],'T', sockptr->port, 0);
sockptr->TCPOK = 0;
return MsgLen;
}
}
else
{
// buffer contains more that 1 message
MsgLen = sockptr->InputLen - (int)((ptr2-ptr));
memcpy(Buffer, sockptr->TCPBuffer, MsgLen);
memmove(sockptr->TCPBuffer, ptr, sockptr->InputLen-MsgLen);
sockptr->InputLen -= MsgLen;
if (MsgLen > 1)
{
if (PORT->MHEnabled)
Update_MH_List(PORT, (UCHAR *)&sockptr->destaddr.sin_addr.s_addr, &Buffer[7],'T', sockptr->port, 0);
sockptr->TCPOK = 0;
return MsgLen;
}
}
}
}
}
return 0;
}
int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len)
{
int i,txptr=0;
UCHAR c;
outbuff[0]=FEND;
txptr=1;
for (i=0;i<len;i++)
{
c=inbuff[i];
switch (c)
{
case FEND:
outbuff[txptr++]=FESC;
outbuff[txptr++]=TFEND;
break;
case FESC:
outbuff[txptr++]=FESC;
outbuff[txptr++]=TFESC;
break;
default:
outbuff[txptr++]=c;
}
}
outbuff[txptr++]=FEND;
return txptr;
}
int KissDecode(UCHAR * inbuff, int len)
{
int i,txptr=0;
UCHAR c;
for (i=0;i<len;i++)
{
c=inbuff[i];
if (c == FESC)
{
c=inbuff[++i];
{
if (c == TFESC)
c=FESC;
else
if (c == TFEND)
c=FEND;
}
}
inbuff[txptr++]=c;
}
return txptr;
}
VOID TCPConnectThread(struct arp_table_entry * arp)
{
char Msg[255];
int err, i;
u_long param=1;
BOOL bcopt=TRUE;
struct sockaddr_in sinx;
// struct AXIPPORTINFO * PORT;
int Alerted = 0;
Sleep(15000); // Delay startup a bit
while(arp->TCPMode == TCPMaster)
{
if (arp->TCPState == 0)
{
arp->TCPSock=socket(AF_INET,SOCK_STREAM,0);
if (arp->TCPSock == INVALID_SOCKET)
{
i=sprintf(Msg, "Socket Failed for AX/TCP socket - error code = %d\n", WSAGetLastError());
WritetoConsole(Msg);
goto wait;
}
setsockopt (arp->TCPSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
setsockopt(arp->TCPSock, SOL_SOCKET, SO_KEEPALIVE, (char*)&bcopt, 4);
sinx.sin_family = AF_INET;
sinx.sin_addr.s_addr = INADDR_ANY;
sinx.sin_port = 0;
if (bind(arp->TCPSock, (struct sockaddr *) &sinx, addrlen) != 0 )
{
//
// Bind Failed
//
i=sprintf(Msg, "Bind Failed for AX/TCP socket - error code = %d\n", WSAGetLastError());
WritetoConsole(Msg);
goto wait;
}
arp->TCPState = TCPConnecting;
if (connect(arp->TCPSock,(struct sockaddr *) &arp->destaddr, sizeof(arp->destaddr)) == 0)
{
//
// Connected successful
//
arp->TCPState = TCPConnected;
OutputDebugString("AXTCP Connected\r\n");
ioctl (arp->TCPSock, FIONBIO, &param);
Alerted = 0;
}
else
{
err=WSAGetLastError();
// Connect failed
//
if (Alerted == 0)
{
i = sprintf(Msg, "Connect Failed for AX/TCP port %d - error code = %d\n", htons(arp->destaddr.sin_port), err);
WritetoConsole(Msg);
OutputDebugString(Msg);
Alerted = 1;
}
closesocket(arp->TCPSock);
arp->TCPSock = 0;
arp->TCPState = 0;
}
}
wait:
Sleep (115000); // 2 Mins
}
Debugprintf("AX/TCP Connect Thread %x Closing", arp->TCPThreadID);
arp->TCPThreadID = 0;
return; // Not Used
}
VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6)
{
unsigned char * src;
char zeros[12] = "";
char * ptr;
struct
{
int base, len;
} best, cur;
unsigned int words[8];
int i;
if (IPV6 == FALSE)
{
sprintf((char *)Output, "%d.%d.%d.%d", Addr[0], Addr[1], Addr[2], Addr[3]);
return;
}
src = Addr;
// See if Encapsulated IPV4 addr
if (src[12] != 0)
{
if (memcmp(src, zeros, 12) == 0) // 12 zeros, followed by non-zero
{
sprintf((char *)Output, "::%d.%d.%d.%d", src[12], src[13], src[14], src[15]);
return;
}
}
// COnvert 16 bytes to 8 words
for (i = 0; i < 16; i += 2)
words[i / 2] = (src[i] << 8) | src[i + 1];
// Look for longest run of zeros
best.base = -1;
cur.base = -1;
for (i = 0; i < 8; i++)
{
if (words[i] == 0)
{
if (cur.base == -1)
cur.base = i, cur.len = 1; // New run, save start
else
cur.len++; // Continuation - increment length
}
else
{
// End of a run of zeros
if (cur.base != -1)
{
// See if this run is longer
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1; // Start again
}
}
}
if (cur.base != -1)
{
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
ptr = Output;
for (i = 0; i < 8; i++)
{
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base && i < (best.base + best.len))
{
// Just output one : for whole string of zeros
*ptr++ = ':';
i = best.base + best.len - 1; // skip rest of zeros
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*ptr++ = ':';
ptr += sprintf (ptr, "%x", words[i]);
// Was it a trailing run of 0x00's?
}
if (best.base != -1 && (best.base + best.len) == 8)
*ptr++ = ':';
*ptr++ = '\0';
}
#define LIBCONFIG_STATIC
#include "libconfig.h"
VOID SaveAXIPCache(struct AXIPPORTINFO * PORT)
{
config_setting_t *root, *group;
config_t cfg;
char ConfigName[256];
int index=0;
struct arp_table_entry * arp;
unsigned char hostaddr[64];
char Key[128];
if (BPQDirectory[0] == 0)
{
sprintf(ConfigName,"axipcache%d.cfg", PORT->Port);
}
else
{
sprintf(ConfigName,"%s/axipcache%d.cfg", BPQDirectory, PORT->Port);
}
// Get rid of old config before saving
config_init(&cfg);
root = config_root_setting(&cfg);
group = config_setting_add(root, "main", CONFIG_TYPE_GROUP);
if (PORT->arp_table_len >= MAX_ENTRIES)
{
Debugprintf("arp_table_len corrupt - %d", PORT->arp_table_len);
PORT->arp_table_len = MAX_ENTRIES - 1;
}
while (index < PORT->arp_table_len)
{
char * ptr = Key;
arp = &PORT->arp_table[index++];
if (arp->IPv6)
Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, hostaddr, TRUE);
else
Format_Addr((unsigned char *)&arp->destaddr.sin_addr, hostaddr, FALSE);
sprintf(Key, "*%s", arp->hostname);
// libconfig keys can't contain . so replace with *
while (*ptr)
{
if (*ptr == '.') *ptr = '*';
ptr++;
}
SaveStringValue(group, Key, hostaddr);
}
if(!config_write_file(&cfg, ConfigName))
{
fprintf(stderr, "Error while writing file.\n");
config_destroy(&cfg);
return;
}
config_destroy(&cfg);
}
#ifndef LINBPQ
static BOOL GetStringValue(config_setting_t * group, char * name, char * value)
{
const char * str;
config_setting_t *setting;
setting = config_setting_get_member (group, name);
if (setting)
{
str = config_setting_get_string (setting);
strcpy(value, str);
return TRUE;
}
return FALSE;
}
#endif
VOID GetAXIPCache(struct AXIPPORTINFO * PORT)
{
config_setting_t *group;
config_t cfg;
char ConfigName[256];
int index=0;
struct arp_table_entry * arp;
unsigned char hostaddr[64];
char Key[128];
struct stat STAT;
if (BPQDirectory[0] == 0)
{
sprintf(ConfigName,"axipcache%d.cfg", PORT->Port);
}
else
{
sprintf(ConfigName,"%s/axipcache%d.cfg", BPQDirectory, PORT->Port);
}
memset((void *)&cfg, 0, sizeof(config_t));
config_init(&cfg);
if (stat(ConfigName, &STAT) == -1)
return;
if(!config_read_file(&cfg, ConfigName))
{
fprintf(stderr, "AXIP Cache read error line %d - %s\n", config_error_line(&cfg), config_error_text(&cfg));
config_destroy(&cfg);
return;
}
group = config_lookup(&cfg, "main");
if (group == NULL)
{
config_destroy(&cfg);
return;
}
while (index < PORT->arp_table_len)
{
char * ptr = Key;
arp = &PORT->arp_table[index++];
sprintf(Key, "*%s", arp->hostname);
// libconfig keys can't contain . so replace with *
while (*ptr)
{
if (*ptr == '.') *ptr = '*';
ptr++;
}
if (GetStringValue(group, Key, hostaddr))
{
arp->destaddr.sin_addr.s_addr = inet_addr(hostaddr);
}
}
config_destroy(&cfg);
}