1721 lines
37 KiB
C
1721 lines
37 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
|
||
*/
|
||
|
||
/*
|
||
|
||
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
|
||
{
|
||
unsigned int Port;
|
||
unsigned char DataKind;
|
||
unsigned char filler2;
|
||
unsigned char PID;
|
||
unsigned char filler3;
|
||
unsigned char callfrom[10];
|
||
unsigned char callto[10];
|
||
unsigned int DataLength;
|
||
int reserved;
|
||
};
|
||
|
||
struct AGWSocketConnectionInfo
|
||
{
|
||
int Number; // Number of record - for AGWConnections display
|
||
SOCKET socket;
|
||
SOCKADDR_IN sin;
|
||
BOOL SocketActive;
|
||
BOOL RawFlag;
|
||
BOOL MonFlag;
|
||
BOOL useLocalTime;
|
||
BOOL doNodes;
|
||
unsigned char CallSign1[10];
|
||
unsigned char CallSign2[10];
|
||
BOOL GotHeader;
|
||
int MsgDataLength;
|
||
struct AGWHeader AGWRXHeader;
|
||
unsigned char * MsgData;
|
||
};
|
||
|
||
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];
|
||
|
||
static int VisiblePortToRealPort[MaxBPQPortNo + 1];
|
||
|
||
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);
|
||
int InternalAGWDecodeFrame(char * msg, char * buffer, time_t Stamp, int * FrameType, int useLocalTime, int doNodes);
|
||
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();
|
||
}
|
||
|
||
|
||
static SOCKADDR_IN local_sin; /* Local socket - internet style */
|
||
|
||
static PSOCKADDR_IN psin;
|
||
|
||
|
||
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)
|
||
{
|
||
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++)=';';
|
||
}
|
||
i++;
|
||
PORT=PORT->PORTPOINTER;
|
||
}
|
||
|
||
*(ptr)=0;
|
||
|
||
AGWMONVECPTR->HOSTAPPLFLAGS = 0x80; // Requext Monitoring
|
||
|
||
return TRUE;
|
||
}
|
||
int SetUpHostSessions()
|
||
{
|
||
int Stream, i;
|
||
|
||
if (AGWMask == 0) return 0;
|
||
|
||
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;
|
||
|
||
VOID SHOWAGW(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
|
||
{
|
||
// 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
|
||
|
||
char callsign[10];
|
||
int port;
|
||
int sesstype;
|
||
int paclen;
|
||
int maxframe;
|
||
int l4window;
|
||
|
||
|
||
keyptr=(byte *)&Con->CallKey;
|
||
|
||
// 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;
|
||
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;
|
||
int Frametype;
|
||
BOOL RXFlag;
|
||
time_t Stamp;
|
||
|
||
// 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;
|
||
}
|
||
|
||
Stamp = monbuff->Timestamp;
|
||
|
||
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;
|
||
}
|
||
|
||
// Can now have different mon flags per connection, so need to run decode for each socket
|
||
|
||
for (n = 1; n<= CurrentSockets; n++)
|
||
{
|
||
sockptr = &Sockets[n];
|
||
|
||
if (sockptr->SocketActive && sockptr->MonFlag && (RXFlag || LoopMonFlag))
|
||
{
|
||
Length = InternalAGWDecodeFrame(Buffer, AGWBuffer, Stamp, &Frametype, sockptr->useLocalTime, sockptr->doNodes);
|
||
|
||
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);
|
||
|
||
SendRawPacket(sockptr, AGWBuffer, Length);
|
||
}
|
||
}
|
||
}
|
||
|
||
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 <20>GM8BPQ-4 <20>%
|
||
'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;
|
||
struct AGWHeader * AGW = &sockptr->AGWRXHeader;
|
||
|
||
ioctlsocket(sock,FIONREAD,&DataLength);
|
||
|
||
if (DataLength == SOCKET_ERROR || DataLength == 0)
|
||
{
|
||
// Failed or closed - clear connection
|
||
|
||
AGWDataSocket_Disconnect(sockptr);
|
||
return 0;
|
||
}
|
||
|
||
if (DataLength < 36) // A header
|
||
{
|
||
// If we don't get a header within a few ms assume a rogue connection and close it
|
||
|
||
int n = 50;
|
||
|
||
while (n--)
|
||
{
|
||
Sleep(10);
|
||
ioctlsocket(sock,FIONREAD,&DataLength);
|
||
|
||
if (DataLength >= 36)
|
||
break;
|
||
}
|
||
|
||
if (n < 1)
|
||
{
|
||
Debugprintf("Corrupt AGW Packet Received");
|
||
AGWDataSocket_Disconnect(sockptr);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// Have a header
|
||
|
||
i=recv(sock,(char *)&sockptr->AGWRXHeader, 36, 0);
|
||
|
||
if (i == SOCKET_ERROR)
|
||
{
|
||
i=WSAGetLastError();
|
||
AGWDataSocket_Disconnect(sockptr);
|
||
}
|
||
|
||
sockptr->MsgDataLength = sockptr->AGWRXHeader.DataLength;
|
||
|
||
// Validate packet to protect against accidental (or malicious!) connects from a non-agw application
|
||
|
||
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
|
||
|
||
ioctlsocket(sock,FIONREAD,&DataLength); // See if more data
|
||
|
||
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
|
||
|
||
int n = 50;
|
||
|
||
while (n--)
|
||
{
|
||
Sleep(10);
|
||
ioctlsocket(sock,FIONREAD,&DataLength);
|
||
|
||
if (DataLength >= sockptr->MsgDataLength)
|
||
break;
|
||
}
|
||
|
||
if (n < 1)
|
||
{
|
||
Debugprintf("Corrupt AGW Packet Received");
|
||
AGWDataSocket_Disconnect(sockptr);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
if (DataLength >= sockptr->MsgDataLength)
|
||
{
|
||
// Read Data and Process Command
|
||
|
||
sockptr->MsgData = malloc(sockptr->MsgDataLength);
|
||
|
||
i = recv(sock, sockptr->MsgData, sockptr->MsgDataLength, 0);
|
||
|
||
ProcessAGWCommand (sockptr);
|
||
free(sockptr->MsgData);
|
||
sockptr->GotHeader = FALSE;
|
||
}
|
||
}
|
||
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
|
||
|
||
char * Digis = sockptr->MsgData;
|
||
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)
|
||
{
|
||
SendMsg(AGWConnections[con].BPQStream, sockptr->MsgData, sockptr->MsgDataLength);
|
||
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
|
||
|
||
SendRaw(sockptr->AGWRXHeader.Port+1,&sockptr->MsgData[1], sockptr->MsgDataLength - 1);
|
||
|
||
return 0;
|
||
|
||
case 'm':
|
||
|
||
// Toggle Monitor receive
|
||
|
||
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;
|
||
|
||
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
|
||
{
|
||
Digis = sockptr->MsgData[0]; // Number of digis
|
||
|
||
for (j = 1; j<= Digis; j++)
|
||
{
|
||
ConvToAX25(&sockptr->MsgData[(j - 1) * 10 + 1],&TXMessage[7+(j*7)]); // No "last" bit
|
||
}
|
||
|
||
// 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;
|
||
|
||
memcpy(TXMessageptr,&sockptr->MsgData[MsgStart], sockptr->MsgDataLength - MsgStart);
|
||
|
||
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;
|
||
}
|
||
|