2022-08-28 09:35:46 +01:00
|
|
|
|
/*
|
2022-11-14 14:02:28 +00:00
|
|
|
|
Copyright 2001-2022 John Wiseman G8BPQ
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
AGWPE emulation Interface for BPQ32
|
|
|
|
|
|
|
|
|
|
Based on AGWtoBPQ
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
|
|
|
|
|
|
#include "CHeaders.h"
|
|
|
|
|
|
|
|
|
|
#include "bpq32.h"
|
|
|
|
|
|
|
|
|
|
// Internal AGW Interface
|
|
|
|
|
|
|
|
|
|
//#define VVICON 400
|
|
|
|
|
|
|
|
|
|
struct AGWHeader
|
|
|
|
|
{
|
2024-11-12 21:20:01 +00:00
|
|
|
|
unsigned int Port;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
unsigned char DataKind;
|
|
|
|
|
unsigned char filler2;
|
|
|
|
|
unsigned char PID;
|
|
|
|
|
unsigned char filler3;
|
|
|
|
|
unsigned char callfrom[10];
|
|
|
|
|
unsigned char callto[10];
|
2024-11-12 21:20:01 +00:00
|
|
|
|
unsigned int DataLength;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
int reserved;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AGWSocketConnectionInfo
|
|
|
|
|
{
|
|
|
|
|
int Number; // Number of record - for AGWConnections display
|
|
|
|
|
SOCKET socket;
|
|
|
|
|
SOCKADDR_IN sin;
|
|
|
|
|
BOOL SocketActive;
|
|
|
|
|
BOOL RawFlag;
|
|
|
|
|
BOOL MonFlag;
|
2023-10-31 22:42:23 +00:00
|
|
|
|
BOOL useLocalTime;
|
|
|
|
|
BOOL doNodes;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
unsigned char CallSign1[10];
|
|
|
|
|
unsigned char CallSign2[10];
|
|
|
|
|
BOOL GotHeader;
|
|
|
|
|
int MsgDataLength;
|
|
|
|
|
struct AGWHeader AGWRXHeader;
|
2023-10-31 22:42:23 +00:00
|
|
|
|
unsigned char * MsgData;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct BPQConnectionInfo
|
|
|
|
|
{
|
|
|
|
|
struct AGWSocketConnectionInfo * SocketIndex;
|
|
|
|
|
int BPQStream;
|
|
|
|
|
unsigned char CallKey[21]; // Port + two calls
|
|
|
|
|
BOOL Connecting; // Set while waiting for connection to complete
|
|
|
|
|
BOOL Listening;
|
|
|
|
|
int ApplMask;
|
|
|
|
|
} ConInfoRec;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char AGWPorts[1000];
|
|
|
|
|
|
|
|
|
|
struct AGWHeader AGWTXHeader;
|
|
|
|
|
|
|
|
|
|
char SessionList[100];
|
|
|
|
|
|
|
|
|
|
struct BPQConnectionInfo AGWConnections[65];
|
|
|
|
|
|
|
|
|
|
#define MaxSockets 64
|
|
|
|
|
|
|
|
|
|
static struct AGWSocketConnectionInfo Sockets[MaxSockets+1];
|
|
|
|
|
|
|
|
|
|
int CurrentConnections;
|
|
|
|
|
|
|
|
|
|
static int CurrentSockets=0;
|
|
|
|
|
|
|
|
|
|
int AGWPort = 0;
|
|
|
|
|
int AGWSessions = 0;
|
|
|
|
|
int AGWMask = 0;
|
|
|
|
|
|
|
|
|
|
BOOL LoopMonFlag = FALSE;
|
|
|
|
|
BOOL Loopflag = FALSE;
|
|
|
|
|
|
|
|
|
|
extern char pgm[256];
|
|
|
|
|
|
|
|
|
|
SOCKET agwsock;
|
|
|
|
|
|
|
|
|
|
extern BPQVECSTRUC * AGWMONVECPTR;
|
|
|
|
|
|
|
|
|
|
extern int SemHeldByAPI;
|
|
|
|
|
|
|
|
|
|
char szBuff[80];
|
|
|
|
|
|
2023-05-25 14:17:53 +01:00
|
|
|
|
static int VisiblePortToRealPort[MaxBPQPortNo + 1];
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
int SetUpHostSessions();
|
|
|
|
|
int DisplaySessions();
|
|
|
|
|
int AGWDoStateChange(int Stream);
|
|
|
|
|
int AGWDoReceivedData(int Stream);
|
|
|
|
|
int AGWDoMonitorData();
|
|
|
|
|
int AGWConnected(struct BPQConnectionInfo * Con, int Stream);
|
|
|
|
|
int AGWDisconnected(struct BPQConnectionInfo * Con, int Stream);
|
|
|
|
|
int DeleteConnection(struct BPQConnectionInfo * Con);
|
|
|
|
|
int SendConMsgtoAppl(BOOL Incomming, struct BPQConnectionInfo * Con, char * CallSign);
|
|
|
|
|
int SendDisMsgtoAppl(char * Msg, struct AGWSocketConnectionInfo * sockptr);
|
|
|
|
|
int AGWSocket_Accept(SOCKET SocketId);
|
|
|
|
|
int Socket_Data(int SocketId,int error, int eventcode);
|
|
|
|
|
int AGWDataSocket_Read(struct AGWSocketConnectionInfo * sockptr, SOCKET sock);
|
|
|
|
|
int DataSocket_Write(struct AGWSocketConnectionInfo * sockptr, SOCKET sock);
|
|
|
|
|
int AGWGetSessionKey(char * key, struct AGWSocketConnectionInfo * sockptr);
|
|
|
|
|
int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr);
|
|
|
|
|
int SendDataToAppl(int Stream, byte * Buffer, int Length);
|
2024-12-16 17:54:16 +00:00
|
|
|
|
int InternalAGWDecodeFrame(char * msg, char * buffer, time_t Stamp, int * FrameType, int useLocalTime, int doNodes);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
int AGWDataSocket_Disconnect( struct AGWSocketConnectionInfo * sockptr);
|
|
|
|
|
int SendRawPacket(struct AGWSocketConnectionInfo * sockptr, char *txmsg, int Length);
|
|
|
|
|
int ShowApps();
|
|
|
|
|
int Terminate();
|
|
|
|
|
int SendtoSocket(SOCKET sock,char * Msg);
|
|
|
|
|
char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...);
|
|
|
|
|
|
|
|
|
|
VOID Poll_AGW()
|
|
|
|
|
{
|
|
|
|
|
int state, change, i;
|
|
|
|
|
int Stream;
|
|
|
|
|
struct BPQConnectionInfo * Con;
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
|
|
|
|
|
// Look for incoming connects
|
|
|
|
|
|
|
|
|
|
fd_set readfd, writefd, exceptfd;
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
int retval;
|
|
|
|
|
int n;
|
|
|
|
|
int Active = 0;
|
|
|
|
|
SOCKET maxsock;
|
|
|
|
|
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
|
timeout.tv_usec = 0; // poll
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&readfd);
|
|
|
|
|
|
|
|
|
|
FD_SET(agwsock, &readfd);
|
|
|
|
|
|
|
|
|
|
retval = select((int)agwsock + 1, &readfd, NULL, NULL, &timeout);
|
|
|
|
|
|
|
|
|
|
if (retval == -1)
|
|
|
|
|
{
|
|
|
|
|
retval = WSAGetLastError();
|
|
|
|
|
perror("listen select");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
|
if (FD_ISSET((int)agwsock, &readfd))
|
|
|
|
|
AGWSocket_Accept(agwsock);
|
|
|
|
|
|
|
|
|
|
// look for data on any active sockets
|
|
|
|
|
|
|
|
|
|
maxsock = 0;
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&readfd);
|
|
|
|
|
FD_ZERO(&writefd);
|
|
|
|
|
FD_ZERO(&exceptfd);
|
|
|
|
|
|
|
|
|
|
// Check for data on active streams
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < CurrentConnections; i++)
|
|
|
|
|
{
|
|
|
|
|
Con = &AGWConnections[i];
|
|
|
|
|
Stream = Con->BPQStream;
|
|
|
|
|
|
|
|
|
|
SessionState(Stream, &state, &change);
|
|
|
|
|
|
|
|
|
|
if (change == 1)
|
|
|
|
|
{
|
|
|
|
|
if (state == 1)
|
|
|
|
|
|
|
|
|
|
// Connected
|
|
|
|
|
|
|
|
|
|
AGWConnected(Con, Stream);
|
|
|
|
|
else
|
|
|
|
|
AGWDisconnected(Con, Stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (Con->SocketIndex) // Active Session
|
|
|
|
|
{
|
|
|
|
|
AGWDoReceivedData(Stream);
|
|
|
|
|
|
|
|
|
|
// Get current Session State. Any state changed is ACK'ed
|
|
|
|
|
// automatically. See BPQHOST functions 4 and 5.
|
|
|
|
|
|
|
|
|
|
SessionState(Stream, &state, &change);
|
|
|
|
|
|
|
|
|
|
if (change == 1)
|
|
|
|
|
{
|
|
|
|
|
if (state == 1)
|
|
|
|
|
|
|
|
|
|
// Connected
|
|
|
|
|
|
|
|
|
|
AGWConnected(Con, Stream);
|
|
|
|
|
else
|
|
|
|
|
AGWDisconnected(Con, Stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (n = 1; n <= MaxSockets; n++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[n];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive)
|
|
|
|
|
{
|
|
|
|
|
SOCKET sock = sockptr->socket;
|
|
|
|
|
|
|
|
|
|
FD_SET(sock, &readfd);
|
|
|
|
|
FD_SET(sock, &exceptfd);
|
|
|
|
|
|
|
|
|
|
Active++;
|
|
|
|
|
if (sock > maxsock)
|
|
|
|
|
maxsock = sock;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Active)
|
|
|
|
|
{
|
|
|
|
|
retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout);
|
|
|
|
|
|
|
|
|
|
if (retval == -1)
|
|
|
|
|
{
|
|
|
|
|
perror("data select yy");
|
|
|
|
|
Debugprintf("Select Error %d", WSAGetLastError());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (retval)
|
|
|
|
|
{
|
|
|
|
|
// see who has data
|
|
|
|
|
|
|
|
|
|
for (n = 1; n <= MaxSockets; n++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[n];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive)
|
|
|
|
|
{
|
|
|
|
|
SOCKET sock = sockptr->socket;
|
|
|
|
|
|
|
|
|
|
if (FD_ISSET(sock, &exceptfd))
|
|
|
|
|
AGWDataSocket_Disconnect(sockptr);
|
|
|
|
|
|
|
|
|
|
if (FD_ISSET(sock, &readfd))
|
|
|
|
|
AGWDataSocket_Read(sockptr, sock);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AGWDoMonitorData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
|
static SOCKADDR_IN local_sin; /* Local socket - internet style */
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
|
static PSOCKADDR_IN psin;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL AGWAPIInit()
|
|
|
|
|
{
|
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
|
int i = 1;
|
|
|
|
|
int v = 0;
|
|
|
|
|
char * ptr;
|
|
|
|
|
BOOL opt=TRUE;
|
|
|
|
|
|
|
|
|
|
if (AGWPort == 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
// Create listening socket
|
|
|
|
|
|
|
|
|
|
agwsock = socket( AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
|
|
|
|
|
if (agwsock == INVALID_SOCKET)
|
|
|
|
|
{
|
|
|
|
|
sprintf(szBuff, "socket() failed error %d", WSAGetLastError());
|
|
|
|
|
WritetoConsole(szBuff);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setsockopt (agwsock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&opt,4);
|
|
|
|
|
|
|
|
|
|
psin=&local_sin;
|
|
|
|
|
|
|
|
|
|
psin->sin_family = AF_INET;
|
|
|
|
|
psin->sin_addr.s_addr = INADDR_ANY;
|
|
|
|
|
psin->sin_port = htons(AGWPort); /* Convert to network ordering */
|
|
|
|
|
|
|
|
|
|
if (bind(agwsock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
|
|
|
|
|
{
|
|
|
|
|
sprintf(szBuff, "bind(sock) failed Port %d Error %d", AGWPort, WSAGetLastError());
|
|
|
|
|
WritetoConsole(szBuff);
|
|
|
|
|
closesocket(agwsock);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (listen(agwsock, 5) < 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf(szBuff, "listen(sock) failed Error %d", WSAGetLastError());
|
|
|
|
|
WritetoConsole(szBuff);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetUpHostSessions();
|
|
|
|
|
|
|
|
|
|
// Set up port List
|
|
|
|
|
|
|
|
|
|
ptr = &AGWPorts[0];
|
|
|
|
|
|
|
|
|
|
ptr += sprintf(ptr, "%d", NUMBEROFPORTS);
|
|
|
|
|
|
|
|
|
|
*(ptr)=';';
|
|
|
|
|
*(++ptr)=0;
|
|
|
|
|
|
|
|
|
|
while (PORT)
|
|
|
|
|
{
|
|
|
|
|
if (PORT->Hide == 0)
|
|
|
|
|
{
|
2023-06-21 08:21:04 +01:00
|
|
|
|
VisiblePortToRealPort[v++] = i - 1;
|
|
|
|
|
memcpy(ptr,"Port",4);
|
|
|
|
|
ptr += sprintf(ptr, "%d", i);
|
|
|
|
|
memcpy(ptr, " with ", 6);
|
|
|
|
|
ptr+=6;
|
|
|
|
|
memcpy(ptr, PORT->PORTDESCRIPTION, 29); // ";"
|
|
|
|
|
ptr+=29;
|
|
|
|
|
|
|
|
|
|
while (*(--ptr) == ' ') {}
|
|
|
|
|
|
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
|
|
*(ptr++)=';';
|
2022-08-28 09:35:46 +01:00
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
PORT=PORT->PORTPOINTER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*(ptr)=0;
|
|
|
|
|
|
|
|
|
|
AGWMONVECPTR->HOSTAPPLFLAGS = 0x80; // Requext Monitoring
|
2023-06-21 08:21:04 +01:00
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
int SetUpHostSessions()
|
|
|
|
|
{
|
|
|
|
|
int Stream, i;
|
|
|
|
|
|
|
|
|
|
if (AGWMask == 0) return 0;
|
2023-06-21 08:21:04 +01:00
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
for (i = 1; i <= AGWSessions; i++)
|
|
|
|
|
{
|
|
|
|
|
strcpy(pgm, "AGW");
|
|
|
|
|
|
|
|
|
|
Stream = FindFreeStream();
|
|
|
|
|
|
|
|
|
|
if (Stream == 255) break;
|
|
|
|
|
|
|
|
|
|
SetAppl(Stream, 2, AGWMask);
|
|
|
|
|
|
|
|
|
|
strcpy(pgm, "bpq32.exe");
|
|
|
|
|
|
|
|
|
|
AGWConnections[CurrentConnections].CallKey[0] = 0;
|
|
|
|
|
AGWConnections[CurrentConnections].BPQStream = Stream;
|
|
|
|
|
AGWConnections[CurrentConnections].SocketIndex = 0;
|
|
|
|
|
AGWConnections[CurrentConnections].Connecting = FALSE;
|
|
|
|
|
AGWConnections[CurrentConnections].Listening = TRUE;
|
|
|
|
|
AGWConnections[CurrentConnections].ApplMask = AGWMask;
|
|
|
|
|
|
|
|
|
|
CurrentConnections++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern struct DATAMESSAGE * REPLYBUFFER;
|
|
|
|
|
extern BOOL AGWActive;
|
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
VOID SHOWAGW(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
|
2022-08-28 09:35:46 +01:00
|
|
|
|
{
|
|
|
|
|
// DISPLAY AGW Session Status
|
|
|
|
|
|
|
|
|
|
int i, con;
|
|
|
|
|
struct BPQConnectionInfo * Con;
|
|
|
|
|
byte key[21];
|
|
|
|
|
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
char IPAddr[20];
|
|
|
|
|
|
|
|
|
|
if (AGWActive == FALSE)
|
|
|
|
|
{
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\rAGW Interface is not enabled\r");
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\rSockets\r");
|
|
|
|
|
for (i = 1; i <= CurrentSockets; i++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[i];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive)
|
|
|
|
|
{
|
|
|
|
|
unsigned char work[4];
|
|
|
|
|
memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);
|
|
|
|
|
|
|
|
|
|
sprintf(IPAddr, "%d.%d.%d.%d", work[0], work[1], work[2], work[3]);
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%2d %-16s %5d %-10s %-10s\r", i, IPAddr, htons(sockptr->sin.sin_port), &sockptr->CallSign1, &sockptr->CallSign2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%2d Idle\r", 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\rPort Calls Stream Socket Connecting Listening Mask\r");
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
Con = &AGWConnections[con];
|
|
|
|
|
|
|
|
|
|
memcpy(key,Con->CallKey,21);
|
|
|
|
|
|
|
|
|
|
if (key[0] == 0) key[0] = 32;
|
|
|
|
|
|
|
|
|
|
key[10]=0;
|
|
|
|
|
key[20]=0;
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%2c ", key[0]);
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s%-10s ",&key[1],&key[11]);
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%2d %2d %s %s %X\r",
|
|
|
|
|
Con->BPQStream,
|
|
|
|
|
(Con->SocketIndex == 0) ? 0 : AGWConnections[con].SocketIndex->Number,
|
|
|
|
|
(Con->Connecting == 0) ? "FALSE" : "TRUE ",
|
|
|
|
|
(Con->Listening == 0) ? "FALSE" : "TRUE ",
|
|
|
|
|
Con->ApplMask);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int DisplaySessions()
|
|
|
|
|
{
|
|
|
|
|
/* char * ptr;
|
|
|
|
|
int i, con;
|
|
|
|
|
|
|
|
|
|
byte key[21]; // As String, char As String
|
|
|
|
|
|
|
|
|
|
strcpy (SessionList," Port Calls Stream Socket Connecting Listening Mask");
|
|
|
|
|
|
|
|
|
|
SendDlgItemMessage(MainWnd,IDC_TEXTBOX3,LB_RESETCONTENT,0,0);
|
|
|
|
|
SendDlgItemMessage(MainWnd,IDC_TEXTBOX3,LB_ADDSTRING,0,(LPARAM) SessionList);
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
memcpy(key,AGWConnections[con].CallKey,21);
|
|
|
|
|
|
|
|
|
|
if (key[0] == 0) key[0] = 32;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
key[10]=0;
|
|
|
|
|
key[20]=0;
|
|
|
|
|
|
|
|
|
|
ptr=&SessionList[0];
|
|
|
|
|
|
|
|
|
|
i=sprintf(ptr,"%2d %2c ",con,key[0]);
|
|
|
|
|
|
|
|
|
|
ptr+=i;
|
|
|
|
|
|
|
|
|
|
i=sprintf(ptr,"%-10s%-10s ",&key[1],&key[11]);
|
|
|
|
|
|
|
|
|
|
ptr+=i;
|
|
|
|
|
|
|
|
|
|
i=sprintf(ptr,"%2d %2d %s %s %x",
|
|
|
|
|
AGWConnections[con].BPQStream,
|
|
|
|
|
(AGWConnections[con].SocketIndex == 0) ? 0 : AGWConnections[con].SocketIndex->Number,
|
|
|
|
|
(AGWConnections[con].Connecting == 0) ? "FALSE" : "TRUE ",
|
|
|
|
|
(AGWConnections[con].Listening == 0) ? "FALSE" : "TRUE ",
|
|
|
|
|
AGWConnections[con].ApplMask);
|
|
|
|
|
|
|
|
|
|
SendDlgItemMessage(MainWnd,IDC_TEXTBOX3,LB_ADDSTRING,0,(LPARAM) SessionList);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AGWConnected(struct BPQConnectionInfo * Con, int Stream)
|
|
|
|
|
{
|
|
|
|
|
byte ConnectingCall[10];
|
|
|
|
|
byte * ApplCallPtr;
|
|
|
|
|
byte * keyptr;
|
|
|
|
|
byte ApplCall[10]="";
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
int ApplNum;
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
|
|
|
|
|
GetCallsign(Stream, ConnectingCall);
|
|
|
|
|
|
|
|
|
|
for (i=9;i>0;i--)
|
|
|
|
|
if (ConnectingCall[i]==32)
|
|
|
|
|
ConnectingCall[i]=0;
|
|
|
|
|
|
|
|
|
|
ApplNum = GetApplNum(Stream);
|
|
|
|
|
|
|
|
|
|
if (ApplNum == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0; // Cant be an incomming connect
|
|
|
|
|
}
|
|
|
|
|
ApplCallPtr = GetApplCall(ApplNum);
|
|
|
|
|
|
|
|
|
|
if (ApplCallPtr != 0) memcpy(ApplCall,ApplCallPtr,10);
|
|
|
|
|
|
|
|
|
|
// Convert trailing spaces to nulls
|
|
|
|
|
|
|
|
|
|
for (i=9;i>0;i--)
|
|
|
|
|
if (ApplCall[i]==32)
|
|
|
|
|
ApplCall[i]=0;
|
|
|
|
|
|
|
|
|
|
// See if incomming connection
|
|
|
|
|
|
|
|
|
|
if (Con->Listening)
|
|
|
|
|
{
|
|
|
|
|
// Allocate Session and send "c" Message
|
|
|
|
|
//
|
|
|
|
|
// Find an AGW session
|
|
|
|
|
|
|
|
|
|
for (sockptr=&Sockets[1]; sockptr <= &Sockets[CurrentSockets]; sockptr++)
|
|
|
|
|
{
|
|
|
|
|
if (sockptr->SocketActive &&
|
|
|
|
|
(memcmp(sockptr->CallSign1, ApplCall, 10) == 0) || (memcmp(sockptr->CallSign2, ApplCall, 10) == 0))
|
|
|
|
|
{
|
|
|
|
|
// Create Key
|
2024-11-05 21:03:15 +00:00
|
|
|
|
|
|
|
|
|
char callsign[10];
|
|
|
|
|
int port;
|
|
|
|
|
int sesstype;
|
|
|
|
|
int paclen;
|
|
|
|
|
int maxframe;
|
|
|
|
|
int l4window;
|
|
|
|
|
|
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
keyptr=(byte *)&Con->CallKey;
|
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
|
// Try using the BPQ Port Number if a L2 connect, first free port number if not
|
|
|
|
|
|
|
|
|
|
GetConnectionInfo(Stream, callsign,
|
|
|
|
|
&port, &sesstype, &paclen,
|
|
|
|
|
&maxframe, &l4window);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (port == 0)
|
|
|
|
|
port = 64;
|
|
|
|
|
|
|
|
|
|
*(keyptr++)='0' + port;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
memcpy(keyptr, ApplCall, 10);
|
|
|
|
|
keyptr+=10;
|
|
|
|
|
memcpy(keyptr,ConnectingCall, 10);
|
|
|
|
|
|
|
|
|
|
// Make sure key is not already in use
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < CurrentConnections; i++)
|
|
|
|
|
{
|
|
|
|
|
if (Con->BPQStream == Stream)
|
|
|
|
|
continue; // Dont Check ourself!
|
|
|
|
|
|
|
|
|
|
if (AGWConnections[i].SocketIndex == sockptr &&
|
|
|
|
|
memcmp(&Con->CallKey, &AGWConnections[i].CallKey,21) == 0)
|
|
|
|
|
{
|
|
|
|
|
SendMsg(Stream, "AGWtoBPQ - Callsign is already connected\r", 43);
|
|
|
|
|
Sleep (500);
|
|
|
|
|
Disconnect(Stream);
|
|
|
|
|
Con->CallKey[0]=0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Con->Listening = FALSE;
|
|
|
|
|
Con->SocketIndex = sockptr;
|
|
|
|
|
|
|
|
|
|
DisplaySessions();
|
|
|
|
|
|
|
|
|
|
SendConMsgtoAppl(TRUE, Con, ConnectingCall);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SendMsg(Stream, "No AGWPE Host Sessions available\r", 33);
|
|
|
|
|
Sleep (500);
|
|
|
|
|
Disconnect(Stream); // disconnect
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Not listening ??
|
|
|
|
|
|
|
|
|
|
OutputDebugString("Inbound Connection on Outgoing Stream");
|
|
|
|
|
|
|
|
|
|
SendMsg(Stream, "AGWtoBPQ - Inbound Connection on Outgoing Stream\r", 49);
|
|
|
|
|
Sleep (500);
|
|
|
|
|
Disconnect(Stream); // disconnect
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AGWDisconnected(struct BPQConnectionInfo * Con, int Stream)
|
|
|
|
|
{
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
char key[21];
|
|
|
|
|
|
|
|
|
|
memcpy(key,Con->CallKey,21);
|
|
|
|
|
|
|
|
|
|
sockptr = Con->SocketIndex;
|
|
|
|
|
|
|
|
|
|
if (sockptr != 0)
|
|
|
|
|
{
|
|
|
|
|
AGWTXHeader.Port = key[0] - 49;
|
|
|
|
|
|
|
|
|
|
memcpy(&AGWTXHeader.callfrom,&key[11],10);
|
|
|
|
|
memcpy(&AGWTXHeader.callto,&key[1],10);
|
|
|
|
|
|
|
|
|
|
// Send a "d" Message
|
|
|
|
|
|
|
|
|
|
// DisMsg = "*** DISCONNECTED From Station "
|
|
|
|
|
|
|
|
|
|
SendDisMsgtoAppl("*** DISCONNECTED From Station ", sockptr);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Con->ApplMask != 0)
|
|
|
|
|
{
|
|
|
|
|
Con->Listening = TRUE;
|
|
|
|
|
Con->SocketIndex = 0;
|
|
|
|
|
memset(&Con->CallKey ,0 ,21);
|
|
|
|
|
|
|
|
|
|
DisplaySessions();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DeleteConnection(Con);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
int AGWDoReceivedData(int Stream)
|
|
|
|
|
{
|
|
|
|
|
byte Buffer[400];
|
|
|
|
|
int len,count;
|
|
|
|
|
|
|
|
|
|
//Dim n As Integer, i As Integer, j As Integer, portcount As Integer
|
|
|
|
|
//Dim start As Integer
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
GetMsg(Stream, Buffer,&len, &count);
|
|
|
|
|
|
|
|
|
|
if (len > 0)
|
|
|
|
|
SendDataToAppl(Stream, Buffer,len);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
while (count > 0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AGWDoMonitorData()
|
|
|
|
|
{
|
|
|
|
|
byte Buffer[500];
|
|
|
|
|
int RawLen, Length;
|
|
|
|
|
byte Port;
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
byte AGWBuffer[1000];
|
|
|
|
|
int n;
|
2024-11-05 21:03:15 +00:00
|
|
|
|
int Frametype;
|
2023-10-31 22:42:23 +00:00
|
|
|
|
BOOL RXFlag;
|
2024-11-05 21:03:15 +00:00
|
|
|
|
time_t Stamp;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
// Look for Monitor Data
|
|
|
|
|
|
|
|
|
|
while (AGWMONVECPTR->HOSTTRACEQ)
|
|
|
|
|
{
|
|
|
|
|
MESSAGE * monbuff;
|
|
|
|
|
|
|
|
|
|
GetSemaphore(&Semaphore, 99);
|
|
|
|
|
|
|
|
|
|
monbuff = Q_REM((void *)&AGWMONVECPTR->HOSTTRACEQ);
|
|
|
|
|
|
|
|
|
|
RawLen = monbuff->LENGTH;
|
|
|
|
|
|
|
|
|
|
if (RawLen < 7 || RawLen > 350)
|
|
|
|
|
{
|
|
|
|
|
ReleaseBuffer(monbuff);
|
|
|
|
|
FreeSemaphore(&Semaphore);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
|
Stamp = monbuff->Timestamp;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
memcpy(Buffer, monbuff, RawLen);
|
|
|
|
|
|
|
|
|
|
ReleaseBuffer(monbuff);
|
|
|
|
|
|
|
|
|
|
FreeSemaphore(&Semaphore);
|
|
|
|
|
|
|
|
|
|
//' 4 byte chain
|
|
|
|
|
//' 1 byte port - top bit = transmit
|
|
|
|
|
//' 2 byte length (LO-HI)
|
|
|
|
|
|
|
|
|
|
Port = Buffer[4];
|
|
|
|
|
|
|
|
|
|
if (Port > 127)
|
|
|
|
|
{
|
|
|
|
|
RXFlag = FALSE;
|
|
|
|
|
Port = Port - 128;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RXFlag = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
|
// Can now have different mon flags per connection, so need to run decode for each socket
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
for (n = 1; n<= CurrentSockets; n++)
|
|
|
|
|
{
|
2023-10-31 22:42:23 +00:00
|
|
|
|
sockptr = &Sockets[n];
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
|
if (sockptr->SocketActive && sockptr->MonFlag && (RXFlag || LoopMonFlag))
|
2022-08-28 09:35:46 +01:00
|
|
|
|
{
|
2023-10-31 22:42:23 +00:00
|
|
|
|
Length = InternalAGWDecodeFrame(Buffer, AGWBuffer, Stamp, &Frametype, sockptr->useLocalTime, sockptr->doNodes);
|
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
if (Length > 0)
|
|
|
|
|
{
|
|
|
|
|
AGWTXHeader.Port = Port - 1; // AGW Ports start from 0
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Patch by D. van der Locht 09-10-2020
|
|
|
|
|
* Added support for sending 'T' frames to AGW clients if LoopMonFlag is set.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (RXFlag)
|
|
|
|
|
{
|
|
|
|
|
if (Frametype == 3)
|
|
|
|
|
{
|
|
|
|
|
AGWTXHeader.DataKind = 'U';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (Frametype && 1 == 0)
|
|
|
|
|
{
|
|
|
|
|
AGWTXHeader.DataKind = 'I';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AGWTXHeader.DataKind = 'S';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AGWTXHeader.DataKind = 'T';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = Length;
|
|
|
|
|
|
|
|
|
|
memset(AGWTXHeader.callfrom, 0,10);
|
|
|
|
|
ConvFromAX25(monbuff->ORIGIN, AGWTXHeader.callfrom);
|
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
|
SendRawPacket(sockptr, AGWBuffer, Length);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RawLen = RawLen - 6;
|
|
|
|
|
|
|
|
|
|
if (RXFlag || Loopflag) // Send transmitted frames if requested
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Send raw data to any sockets that have requested Raw frames
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Buffer[6]=0;
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.Port = Port - 1; // AGW Ports start from 0
|
|
|
|
|
AGWTXHeader.DataKind = 'K';
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = RawLen;
|
|
|
|
|
|
|
|
|
|
for (n = 1; n<= CurrentSockets; n++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[n];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive && sockptr->RawFlag)
|
|
|
|
|
SendRawPacket(sockptr, &Buffer[6], RawLen);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int DeleteConnection(struct BPQConnectionInfo * Con)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int con;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// remove specified session
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
SetAppl(Con->BPQStream, 0, 0);
|
|
|
|
|
|
|
|
|
|
Disconnect(Con->BPQStream);
|
|
|
|
|
|
|
|
|
|
DeallocateStream(Con->BPQStream);
|
|
|
|
|
|
|
|
|
|
// move all down one
|
|
|
|
|
|
|
|
|
|
con = (int)(Con - &AGWConnections[0]);
|
|
|
|
|
|
|
|
|
|
for (i = con; i <= CurrentConnections - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&AGWConnections[i],&AGWConnections[i + 1],sizeof ConInfoRec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentConnections--;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SendConMsgtoAppl(BOOL Incomming, struct BPQConnectionInfo * Con, char * CallSign)
|
|
|
|
|
{
|
|
|
|
|
char key[21];
|
|
|
|
|
char ConMsg[80]="*** CONNECTED ";
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(key,&Con->CallKey,21);
|
|
|
|
|
|
|
|
|
|
sockptr = Con->SocketIndex;
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.Port = key[0] - 49;
|
|
|
|
|
|
|
|
|
|
memcpy(AGWTXHeader.callfrom, &key[11],10);
|
|
|
|
|
|
|
|
|
|
memcpy(AGWTXHeader.callto, &key[1],10);
|
|
|
|
|
|
|
|
|
|
/* '
|
|
|
|
|
' Send a "C" Message
|
|
|
|
|
'
|
|
|
|
|
'01 00 00 00 43 00 00 00 47 4D 38 42 50 51 2D 34 C GM8BPQ-4
|
|
|
|
|
'00 EA 47 4D 38 42 50 51 2D 34 00 FF 25 00 00 00 <EFBFBD>GM8BPQ-4 <EFBFBD>%
|
|
|
|
|
'00 00 00 00 2A 2A 2A 20 43 4F 4E 4E 45 43 54 45 *** CONNECTE
|
|
|
|
|
'44 20 57 69 74 68 20 53 74 61 74 69 6F 6E 20 47 D With Station G
|
|
|
|
|
'4D 38 42 50 51 2D 34 0D 00 M8BPQ-4
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataKind = 'C';
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.PID = 0;
|
|
|
|
|
|
|
|
|
|
if (Incomming)
|
|
|
|
|
strcat(ConMsg,"To");
|
|
|
|
|
else
|
|
|
|
|
strcat(ConMsg,"With");
|
|
|
|
|
|
|
|
|
|
strcat(ConMsg," Station ");
|
|
|
|
|
strcat(ConMsg,CallSign);
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = (int)strlen(ConMsg)+1;
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, ConMsg);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int SendDisMsgtoAppl(char * Msg, struct AGWSocketConnectionInfo * sockptr)
|
|
|
|
|
{
|
|
|
|
|
byte DisMsg[100];
|
|
|
|
|
|
|
|
|
|
strcpy(DisMsg,Msg);
|
|
|
|
|
strcat(DisMsg,(const char *)&AGWTXHeader.callfrom);
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.Port = sockptr->AGWRXHeader.Port;
|
|
|
|
|
AGWTXHeader.DataKind = 'd';
|
|
|
|
|
|
|
|
|
|
strcat(DisMsg,"\r");
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = (int)strlen(DisMsg)+1;
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, DisMsg);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int AGWSocket_Accept(SOCKET SocketId)
|
|
|
|
|
{
|
|
|
|
|
int n,addrlen;
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
SOCKET sock;
|
|
|
|
|
|
|
|
|
|
// Find a free Socket
|
|
|
|
|
|
|
|
|
|
for (n = 1; n <= MaxSockets; n++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[n];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive == FALSE)
|
|
|
|
|
{
|
|
|
|
|
addrlen=sizeof(struct sockaddr);
|
|
|
|
|
|
|
|
|
|
memset(sockptr, 0, sizeof(struct AGWSocketConnectionInfo));
|
|
|
|
|
|
|
|
|
|
sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen);
|
|
|
|
|
|
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
|
|
|
{
|
|
|
|
|
sprintf(szBuff, "AGW accept() failed Error %d\r", WSAGetLastError());
|
|
|
|
|
WritetoConsole(szBuff);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sockptr->socket = sock;
|
|
|
|
|
sockptr->SocketActive = TRUE;
|
|
|
|
|
sockptr->GotHeader = FALSE;
|
|
|
|
|
sockptr->MsgDataLength = 0;
|
|
|
|
|
sockptr->Number = n;
|
|
|
|
|
|
|
|
|
|
if (CurrentSockets < n) CurrentSockets=n; //Record max used to save searching all entries
|
|
|
|
|
|
|
|
|
|
ShowApps();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Should accept, then immediately close
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SendtoSocket(SOCKET sock, char * Msg)
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
int n;
|
|
|
|
|
char * ptr;
|
|
|
|
|
|
|
|
|
|
len = AGWTXHeader.DataLength;
|
|
|
|
|
|
|
|
|
|
// Make sure calls are null terminated
|
|
|
|
|
|
|
|
|
|
n = 10;
|
|
|
|
|
ptr = &AGWTXHeader.callfrom[9];
|
|
|
|
|
while (n-- && *(ptr) == ' ')
|
|
|
|
|
{
|
|
|
|
|
*(ptr) = 0;
|
|
|
|
|
ptr--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = 10;
|
|
|
|
|
ptr = &AGWTXHeader.callto[9];
|
|
|
|
|
while (n-- && *(ptr) == ' ')
|
|
|
|
|
{
|
|
|
|
|
*(ptr) = 0;
|
|
|
|
|
n--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
send(sock,(char *)&AGWTXHeader, 36,0);
|
|
|
|
|
if (len > 0) send(sock, Msg, len,0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AGWDataSocket_Read(struct AGWSocketConnectionInfo * sockptr, SOCKET sock)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int DataLength;
|
2024-12-16 17:54:16 +00:00
|
|
|
|
struct AGWHeader * AGW = &sockptr->AGWRXHeader;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
ioctlsocket(sock,FIONREAD,&DataLength);
|
|
|
|
|
|
|
|
|
|
if (DataLength == SOCKET_ERROR || DataLength == 0)
|
|
|
|
|
{
|
|
|
|
|
// Failed or closed - clear connection
|
|
|
|
|
|
|
|
|
|
AGWDataSocket_Disconnect(sockptr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
if (DataLength < 36) // A header
|
2024-11-28 22:33:53 +00:00
|
|
|
|
{
|
2024-12-16 17:54:16 +00:00
|
|
|
|
// If we don't get a header within a few ms assume a rogue connection and close it
|
2024-11-12 21:20:01 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
int n = 50;
|
|
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
|
{
|
|
|
|
|
Sleep(10);
|
2024-11-30 11:27:28 +00:00
|
|
|
|
ioctlsocket(sock,FIONREAD,&DataLength);
|
2024-12-16 17:54:16 +00:00
|
|
|
|
|
|
|
|
|
if (DataLength >= 36)
|
|
|
|
|
break;
|
2024-11-28 22:33:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
if (n < 1)
|
|
|
|
|
{
|
|
|
|
|
Debugprintf("Corrupt AGW Packet Received");
|
|
|
|
|
AGWDataSocket_Disconnect(sockptr);
|
|
|
|
|
return 0;
|
2024-11-28 22:33:53 +00:00
|
|
|
|
}
|
2024-12-16 17:54:16 +00:00
|
|
|
|
}
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
// Have a header
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
i=recv(sock,(char *)&sockptr->AGWRXHeader, 36, 0);
|
|
|
|
|
|
|
|
|
|
if (i == SOCKET_ERROR)
|
2024-11-30 11:27:28 +00:00
|
|
|
|
{
|
2024-12-16 17:54:16 +00:00
|
|
|
|
i=WSAGetLastError();
|
|
|
|
|
AGWDataSocket_Disconnect(sockptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sockptr->MsgDataLength = sockptr->AGWRXHeader.DataLength;
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
// Validate packet to protect against accidental (or malicious!) connects from a non-agw application
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
if (AGW->Port > 64 || AGW->filler2 != 0 || AGW->filler3 != 0 || AGW->DataLength > 400)
|
|
|
|
|
{
|
|
|
|
|
Debugprintf("Corrupt AGW Packet Received");
|
|
|
|
|
AGWDataSocket_Disconnect(sockptr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sockptr->MsgDataLength == 0)
|
|
|
|
|
ProcessAGWCommand (sockptr);
|
|
|
|
|
else
|
|
|
|
|
sockptr->GotHeader = TRUE; // Wait for data
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
ioctlsocket(sock,FIONREAD,&DataLength); // See if more data
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
if (sockptr->GotHeader)
|
|
|
|
|
{
|
|
|
|
|
// Received a header, without sufficient data bytes
|
|
|
|
|
|
|
|
|
|
if (DataLength < sockptr->MsgDataLength)
|
|
|
|
|
{
|
|
|
|
|
// Fiddle - seem to be problems somtimes with un-Neagled hosts so wait a few ms
|
|
|
|
|
// if we don't get a full packet assume a rogue connection and close it
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
int n = 50;
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
while (n--)
|
2024-11-30 11:27:28 +00:00
|
|
|
|
{
|
2024-12-16 17:54:16 +00:00
|
|
|
|
Sleep(10);
|
|
|
|
|
ioctlsocket(sock,FIONREAD,&DataLength);
|
|
|
|
|
|
|
|
|
|
if (DataLength >= sockptr->MsgDataLength)
|
|
|
|
|
break;
|
2024-11-30 11:27:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
if (n < 1)
|
2024-11-30 11:27:28 +00:00
|
|
|
|
{
|
2024-12-16 17:54:16 +00:00
|
|
|
|
Debugprintf("Corrupt AGW Packet Received");
|
|
|
|
|
AGWDataSocket_Disconnect(sockptr);
|
|
|
|
|
return 0;
|
2024-11-30 11:27:28 +00:00
|
|
|
|
}
|
2024-12-16 17:54:16 +00:00
|
|
|
|
}
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
if (DataLength >= sockptr->MsgDataLength)
|
|
|
|
|
{
|
|
|
|
|
// Read Data and Process Command
|
2024-11-30 11:27:28 +00:00
|
|
|
|
|
2024-12-16 17:54:16 +00:00
|
|
|
|
sockptr->MsgData = malloc(sockptr->MsgDataLength);
|
|
|
|
|
|
|
|
|
|
i = recv(sock, sockptr->MsgData, sockptr->MsgDataLength, 0);
|
|
|
|
|
|
|
|
|
|
ProcessAGWCommand (sockptr);
|
|
|
|
|
free(sockptr->MsgData);
|
|
|
|
|
sockptr->GotHeader = FALSE;
|
|
|
|
|
}
|
2022-08-28 09:35:46 +01:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr)
|
|
|
|
|
{
|
|
|
|
|
int AGWVersion[2]={2003,999};
|
|
|
|
|
char AGWRegReply[1];
|
|
|
|
|
struct BPQConnectionInfo * Connection;
|
|
|
|
|
int Stream;
|
|
|
|
|
char AXCall[10];
|
|
|
|
|
char RegCall[10];
|
|
|
|
|
unsigned char TXMessage[500];
|
|
|
|
|
int Digis,MsgStart,j;
|
|
|
|
|
byte * TXMessageptr;
|
|
|
|
|
char key[21];
|
|
|
|
|
char ToCall[10];
|
|
|
|
|
char ConnectMsg[128];
|
|
|
|
|
int con,conport;
|
|
|
|
|
int AGWYReply = 0;
|
|
|
|
|
int state, change;
|
|
|
|
|
|
|
|
|
|
// if we have hidden some ports then the port in the AGW packet will be an index into the visible ports,
|
|
|
|
|
// not the real port number
|
|
|
|
|
|
|
|
|
|
switch (sockptr->AGWRXHeader.DataKind)
|
|
|
|
|
{
|
|
|
|
|
case 'C':
|
|
|
|
|
case 'v':
|
|
|
|
|
|
|
|
|
|
// Connect or Connect with Digis
|
|
|
|
|
|
|
|
|
|
// Create Session Key from port and callsign pair
|
|
|
|
|
|
|
|
|
|
AGWGetSessionKey(key, sockptr);
|
|
|
|
|
|
|
|
|
|
memcpy(ToCall, &key[11],10);
|
|
|
|
|
|
|
|
|
|
strcpy(pgm, "AGW");
|
|
|
|
|
|
|
|
|
|
Stream = FindFreeStream();
|
|
|
|
|
|
|
|
|
|
strcpy(pgm, "bpq32.exe");
|
|
|
|
|
|
|
|
|
|
if (Stream == 255) return 0;
|
|
|
|
|
|
|
|
|
|
Connection=&AGWConnections[CurrentConnections];
|
|
|
|
|
|
|
|
|
|
memcpy(&Connection->CallKey,key,21);
|
|
|
|
|
Connection->BPQStream = Stream;
|
|
|
|
|
Connection->SocketIndex = sockptr;
|
|
|
|
|
Connection->Connecting = TRUE;
|
|
|
|
|
|
|
|
|
|
Connect(Stream); // Connect
|
|
|
|
|
SessionState(Stream, &state, &change);
|
|
|
|
|
|
|
|
|
|
ConvToAX25(sockptr->CallSign1, AXCall);
|
|
|
|
|
ChangeSessionCallsign(Stream, AXCall); // Prevent triggering incoming connect code
|
|
|
|
|
|
|
|
|
|
DisplaySessions();
|
|
|
|
|
|
|
|
|
|
if (memcmp(ToCall,"SWITCH",6) == 0)
|
|
|
|
|
{
|
|
|
|
|
// Just connect to command level on switch
|
|
|
|
|
|
|
|
|
|
SendConMsgtoAppl(FALSE, Connection, ToCall);
|
|
|
|
|
Connection->Connecting = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Need to convert port index (used by AGW) to port number
|
|
|
|
|
|
|
|
|
|
conport=GetPortNumber(VisiblePortToRealPort[key[0]-48]);
|
|
|
|
|
|
|
|
|
|
sprintf(ConnectMsg,"C %d %s",conport,ToCall);
|
|
|
|
|
|
|
|
|
|
// if 'v' command add digis
|
|
|
|
|
|
|
|
|
|
if (sockptr->AGWRXHeader.DataLength)
|
|
|
|
|
{
|
|
|
|
|
// Have digis
|
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
|
char * Digis = sockptr->MsgData;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
int nDigis = Digis[0];
|
|
|
|
|
|
|
|
|
|
Digis ++;
|
|
|
|
|
|
|
|
|
|
while(nDigis--)
|
|
|
|
|
{
|
|
|
|
|
sprintf(ConnectMsg, "%s, %s", ConnectMsg, Digis);
|
|
|
|
|
Digis += 10;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcat(ConnectMsg, "\r");
|
|
|
|
|
|
|
|
|
|
// Send C command to Node
|
|
|
|
|
|
|
|
|
|
SendMsg(Stream, ConnectMsg, (int)strlen(ConnectMsg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentConnections++;
|
|
|
|
|
|
|
|
|
|
DisplaySessions();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case 'D':
|
|
|
|
|
|
|
|
|
|
// Send Data
|
|
|
|
|
//
|
|
|
|
|
// Create Session Key from port and callsign pair
|
|
|
|
|
|
|
|
|
|
AGWGetSessionKey(key, sockptr);
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
if (memcmp(AGWConnections[con].CallKey,key,21) == 0)
|
|
|
|
|
{
|
2023-10-31 22:42:23 +00:00
|
|
|
|
SendMsg(AGWConnections[con].BPQStream, sockptr->MsgData, sockptr->MsgDataLength);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
|
|
|
|
|
|
// Disconnect
|
|
|
|
|
|
|
|
|
|
memcpy(AGWTXHeader.callto,sockptr->AGWRXHeader.callfrom,10);
|
|
|
|
|
memcpy(AGWTXHeader.callfrom,sockptr->AGWRXHeader.callto,10);
|
|
|
|
|
|
|
|
|
|
SendDisMsgtoAppl("*** DISCONNECTED RETRYOUT With ", sockptr);
|
|
|
|
|
|
|
|
|
|
AGWGetSessionKey(key, sockptr);
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
if (memcmp(AGWConnections[con].CallKey,key,21) == 0)
|
|
|
|
|
{
|
|
|
|
|
Disconnect(AGWConnections[con].BPQStream);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There is confusion about the correct ordring of calls in the "d" packet. AGW appears to accept either,
|
|
|
|
|
// so I will too.
|
|
|
|
|
|
|
|
|
|
memset(&key[1],0,20);
|
|
|
|
|
strcpy(&key[1],sockptr->AGWRXHeader.callto);
|
|
|
|
|
strcpy(&key[11],sockptr->AGWRXHeader.callfrom);
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
if (memcmp(AGWConnections[con].CallKey,key,21) == 0)
|
|
|
|
|
{
|
|
|
|
|
Disconnect(AGWConnections[con].BPQStream);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'R':
|
|
|
|
|
|
|
|
|
|
// Version
|
|
|
|
|
|
|
|
|
|
memset(&AGWTXHeader,0,36);
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataKind = 'R';
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = 8; // Length
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, (char *)&AGWVersion[0]);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'G':
|
|
|
|
|
|
|
|
|
|
// Port info. String is in AGWPorts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset(&AGWTXHeader,0,36);
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataKind = 'G';
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength =(int)strlen(AGWPorts)+1; // Length
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, AGWPorts);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'k':
|
|
|
|
|
|
|
|
|
|
// Toggle Raw receive
|
|
|
|
|
|
|
|
|
|
sockptr->RawFlag = !sockptr->RawFlag;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case 'K':
|
|
|
|
|
|
|
|
|
|
// Send Raw Frame
|
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
|
SendRaw(sockptr->AGWRXHeader.Port+1,&sockptr->MsgData[1], sockptr->MsgDataLength - 1);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case 'm':
|
|
|
|
|
|
|
|
|
|
// Toggle Monitor receive
|
2023-10-31 22:42:23 +00:00
|
|
|
|
|
|
|
|
|
if (sockptr->AGWRXHeader.DataLength == 12) // QtTermTCP monitor info
|
|
|
|
|
{
|
|
|
|
|
// Msg[AGWHDDRRLEN] = AGWUsers->MonSess->mlocaltime;
|
|
|
|
|
// Msg[AGWHDDRRLEN + 1] = AGWUsers->MonSess->MonitorNODES;
|
|
|
|
|
//Msg[AGWHDDRRLEN + 2] = AGWUsers->MonSess->MonitorColour;
|
|
|
|
|
// Msg[AGWHDDRRLEN + 3] = AGWUsers->MonSess->mtxparam;
|
|
|
|
|
// memcpy(&Msg[AGWHDDRRLEN + 4], (void *)&AGWUsers->MonSess->portmask, 8);
|
|
|
|
|
sockptr->useLocalTime = sockptr->MsgData[0];
|
|
|
|
|
sockptr->doNodes = sockptr->MsgData[1];
|
|
|
|
|
sockptr->MonFlag = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
sockptr->MonFlag = !sockptr->MonFlag;
|
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
|
case 'V': // Send UNProto Frame "V" includes Via string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ConvToAX25(sockptr->AGWRXHeader.callto,TXMessage);
|
|
|
|
|
ConvToAX25(sockptr->AGWRXHeader.callfrom,&TXMessage[7]);
|
|
|
|
|
|
|
|
|
|
Digis=0;
|
|
|
|
|
MsgStart = 0;
|
|
|
|
|
|
|
|
|
|
if (sockptr->AGWRXHeader.DataKind == 'V') // Unproto with VIA string
|
|
|
|
|
{
|
2023-10-31 22:42:23 +00:00
|
|
|
|
Digis = sockptr->MsgData[0]; // Number of digis
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
for (j = 1; j<= Digis; j++)
|
|
|
|
|
{
|
2023-10-31 22:42:23 +00:00
|
|
|
|
ConvToAX25(&sockptr->MsgData[(j - 1) * 10 + 1],&TXMessage[7+(j*7)]); // No "last" bit
|
2022-08-28 09:35:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set end of call
|
|
|
|
|
|
|
|
|
|
MsgStart = Digis * 10 + 1; // UI Data follows digis in message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TXMessageptr=&TXMessage[13+(Digis*7)];
|
|
|
|
|
|
|
|
|
|
*(TXMessageptr++) |= 1; // set last bit
|
|
|
|
|
|
|
|
|
|
*(TXMessageptr++) = 3; // UI
|
|
|
|
|
|
|
|
|
|
if (sockptr->AGWRXHeader.PID == 0)
|
|
|
|
|
|
|
|
|
|
*(TXMessageptr++) = 240; // PID
|
|
|
|
|
else
|
|
|
|
|
*(TXMessageptr++) = sockptr->AGWRXHeader.PID;
|
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
|
memcpy(TXMessageptr,&sockptr->MsgData[MsgStart], sockptr->MsgDataLength - MsgStart);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
TXMessageptr += (sockptr->MsgDataLength - MsgStart);
|
|
|
|
|
|
|
|
|
|
SendRaw(sockptr->AGWRXHeader.Port + 1, TXMessage, (int)(TXMessageptr-&TXMessage[0]));
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case 'X':
|
|
|
|
|
|
|
|
|
|
// Register Callsign
|
|
|
|
|
|
|
|
|
|
memset(&AGWTXHeader,0,36);
|
|
|
|
|
|
|
|
|
|
memset(RegCall,0,10);
|
|
|
|
|
memcpy(RegCall, sockptr->AGWRXHeader.callfrom, strlen(sockptr->AGWRXHeader.callfrom));
|
|
|
|
|
|
|
|
|
|
if (sockptr->CallSign1[0] == 0)
|
|
|
|
|
memcpy(sockptr->CallSign1, RegCall, 10);
|
|
|
|
|
else
|
|
|
|
|
memcpy(sockptr->CallSign2, RegCall, 10);
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataKind = 'X';
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = 1; // Length
|
|
|
|
|
|
|
|
|
|
AGWRegReply[0] = 1;
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, AGWRegReply);
|
|
|
|
|
|
|
|
|
|
ShowApps();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'Y':
|
|
|
|
|
|
|
|
|
|
// Session Status
|
|
|
|
|
|
|
|
|
|
// Create Session Key from port and callsign pair
|
|
|
|
|
|
|
|
|
|
AGWGetSessionKey(key, sockptr);
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
if (memcmp(AGWConnections[con].CallKey,key,21) == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&AGWTXHeader,&sockptr->AGWRXHeader,36);
|
|
|
|
|
|
|
|
|
|
AGWYReply = CountFramesQueuedOnStream(AGWConnections[con].BPQStream);
|
|
|
|
|
AGWTXHeader.DataLength = 4; // Length
|
|
|
|
|
SendtoSocket(sockptr->socket, (char *)&AGWYReply);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
|
|
//If Debugging Then Print #10, "Unknown Message "; Chr$(Sockets(Index).AGWRXHeader(4))
|
|
|
|
|
// Debug.Print "Unknown Message "; Chr$(Sockets(Index).AGWRXHeader(4))
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AGWGetSessionKey(char * key, struct AGWSocketConnectionInfo * sockptr)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Create Session Key from port and callsign pair
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
key[0] = sockptr->AGWRXHeader.Port + '1';
|
|
|
|
|
|
|
|
|
|
memset(&key[1],0,20);
|
|
|
|
|
strcpy(&key[1],sockptr->AGWRXHeader.callfrom);
|
|
|
|
|
strcpy(&key[11],sockptr->AGWRXHeader.callto);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
int SendDataToAppl(int Stream, byte * Buffer, int Length)
|
|
|
|
|
{
|
|
|
|
|
int con;
|
|
|
|
|
char * i;
|
|
|
|
|
char ConMsg[80];
|
|
|
|
|
char DisMsg[80];
|
|
|
|
|
char key[21];
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
|
|
|
|
|
//Dim i As Long, Length As Long, con As Long, key As String, hilen As Long, lolen As Long
|
|
|
|
|
//Dim Index As Integer, ConMsg As String, DisMsg As String
|
|
|
|
|
//Dim BytesSent As Long
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//' Find Connection number and call pair
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
if (AGWConnections[con].BPQStream == Stream)
|
|
|
|
|
{
|
|
|
|
|
memcpy(key,&AGWConnections[con].CallKey,21);
|
|
|
|
|
|
|
|
|
|
if (key[0] == 32)
|
|
|
|
|
{
|
|
|
|
|
//Debug.Print "Data on Unconnected Session"
|
|
|
|
|
|
|
|
|
|
Disconnect(Stream);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sockptr = AGWConnections[con].SocketIndex;
|
|
|
|
|
|
|
|
|
|
if (sockptr == 0)
|
|
|
|
|
{
|
|
|
|
|
// No connection, but have a key - wot's going on!!
|
|
|
|
|
// Probably best to clear out connection
|
|
|
|
|
|
|
|
|
|
Disconnect(Stream);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.Port = key[0] - 49;
|
|
|
|
|
|
|
|
|
|
memcpy(AGWTXHeader.callfrom,&key[11],10);
|
|
|
|
|
memcpy(AGWTXHeader.callto,&key[1],10);
|
|
|
|
|
|
|
|
|
|
if (AGWConnections[con].Connecting)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// See if *** Connected message
|
|
|
|
|
|
|
|
|
|
i = strstr(Buffer, "Connected to");
|
|
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
|
{
|
|
|
|
|
AGWConnections[con].Connecting = FALSE;
|
|
|
|
|
|
|
|
|
|
DisplaySessions();
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataKind = 'C';
|
|
|
|
|
AGWTXHeader.PID = 0;
|
|
|
|
|
|
|
|
|
|
strcpy(ConMsg,"*** CONNECTED With Station ");
|
|
|
|
|
strcat(ConMsg, AGWTXHeader.callfrom);
|
|
|
|
|
strcat(ConMsg,"\r");
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataLength = (int)strlen(ConMsg)+1;
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, ConMsg);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = strstr(Buffer, "Failure with");
|
|
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
|
{
|
|
|
|
|
AGWConnections[con].Connecting = FALSE;
|
|
|
|
|
|
|
|
|
|
strcpy(DisMsg,"*** DISCONNECTED RETRYOUT With ");
|
|
|
|
|
|
|
|
|
|
SendDisMsgtoAppl(DisMsg, sockptr);
|
|
|
|
|
|
|
|
|
|
DeleteConnection(&AGWConnections[con]);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = strstr(Buffer, "Busy from");
|
|
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
|
{
|
|
|
|
|
AGWConnections[con].Connecting = FALSE;
|
|
|
|
|
|
|
|
|
|
strcpy(DisMsg,"*** DISCONNECTED RETRYOUT With ");
|
|
|
|
|
|
|
|
|
|
SendDisMsgtoAppl(DisMsg, sockptr);
|
|
|
|
|
|
|
|
|
|
DeleteConnection(&AGWConnections[con]);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AGWTXHeader.DataKind = 'D';
|
|
|
|
|
AGWTXHeader.PID = 0xF0;
|
|
|
|
|
AGWTXHeader.DataLength = Length;
|
|
|
|
|
|
|
|
|
|
SendtoSocket(sockptr->socket, Buffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int AGWDataSocket_Disconnect(struct AGWSocketConnectionInfo * sockptr)
|
|
|
|
|
{
|
|
|
|
|
int con;
|
|
|
|
|
|
|
|
|
|
closesocket(sockptr->socket);
|
|
|
|
|
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
if (AGWConnections[con].SocketIndex == sockptr)
|
|
|
|
|
Disconnect(AGWConnections[con].BPQStream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sockptr->SocketActive = FALSE;
|
|
|
|
|
sockptr->RawFlag = FALSE;
|
|
|
|
|
sockptr->MonFlag = FALSE;
|
|
|
|
|
|
|
|
|
|
ShowApps();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SendRawPacket(struct AGWSocketConnectionInfo * sockptr, char *txmsg, int Length)
|
|
|
|
|
{
|
|
|
|
|
SendtoSocket(sockptr->socket, txmsg);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ShowApps()
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
int i;
|
|
|
|
|
char Msg[80];
|
|
|
|
|
char IPAddr[20];
|
|
|
|
|
|
|
|
|
|
if (ConnWnd == 0) return 0; // Not on display
|
|
|
|
|
|
|
|
|
|
SendDlgItemMessage(ConnWnd,IDC_CONNECTIONS_LIST,LB_RESETCONTENT,0,0);
|
|
|
|
|
|
|
|
|
|
for (i = 1; i <= CurrentSockets; i++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[i];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive)
|
|
|
|
|
{
|
|
|
|
|
sprintf(IPAddr,"%d.%d.%d.%d",
|
|
|
|
|
sockptr->sin.sin_addr.S_un.S_un_b.s_b1,
|
|
|
|
|
sockptr->sin.sin_addr.S_un.S_un_b.s_b2,
|
|
|
|
|
sockptr->sin.sin_addr.S_un.S_un_b.s_b3,
|
|
|
|
|
sockptr->sin.sin_addr.S_un.S_un_b.s_b4);
|
|
|
|
|
|
|
|
|
|
sprintf(Msg,"%2d %-16s %5d %-10s",i,IPAddr,htons(sockptr->sin.sin_port),&sockptr->CallSign);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sprintf(Msg,"%2d Idle",i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SendDlgItemMessage(ConnWnd,IDC_CONNECTIONS_LIST,LB_ADDSTRING,0,(LPARAM) Msg);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int LocalSessionState(int stream, int * state, int * change, BOOL ACK);
|
|
|
|
|
|
|
|
|
|
int AGWAPITerminate()
|
|
|
|
|
{
|
|
|
|
|
int con, State, Change, n;
|
|
|
|
|
struct BPQConnectionInfo * Connection;
|
|
|
|
|
struct AGWSocketConnectionInfo * sockptr;
|
|
|
|
|
//
|
|
|
|
|
// Release all streams
|
|
|
|
|
//
|
|
|
|
|
for (con = 0; con < CurrentConnections; con++)
|
|
|
|
|
{
|
|
|
|
|
Connection=&AGWConnections[con];
|
|
|
|
|
|
|
|
|
|
SetAppl(Connection->BPQStream, 0, 0);
|
|
|
|
|
|
|
|
|
|
Disconnect(Connection->BPQStream);
|
|
|
|
|
|
|
|
|
|
DeallocateStream(Connection->BPQStream);
|
|
|
|
|
|
|
|
|
|
LocalSessionState(Connection->BPQStream, &State, &Change, TRUE);
|
|
|
|
|
|
|
|
|
|
memset(Connection, 0, sizeof(struct AGWSocketConnectionInfo));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentConnections = 0;
|
|
|
|
|
|
|
|
|
|
// Close Listening socket and any connections
|
|
|
|
|
|
|
|
|
|
shutdown(agwsock, 2);
|
|
|
|
|
closesocket(agwsock);
|
|
|
|
|
|
|
|
|
|
for (n = 1; n <= MaxSockets; n++)
|
|
|
|
|
{
|
|
|
|
|
sockptr=&Sockets[n];
|
|
|
|
|
|
|
|
|
|
if (sockptr->SocketActive)
|
|
|
|
|
{
|
|
|
|
|
SOCKET sock = sockptr->socket;
|
|
|
|
|
|
|
|
|
|
shutdown(sock, 2);
|
|
|
|
|
closesocket(sock);
|
|
|
|
|
}
|
|
|
|
|
memset(sockptr, 0, sizeof(struct BPQConnectionInfo));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|