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
|
|
|
|
*/
|
|
|
|
|
|
|
|
//
|
|
|
|
// DLL to provide interface to allow G8BPQ switch to use AGWPE as a Port Driver
|
|
|
|
// 32bit environment,
|
|
|
|
//
|
|
|
|
// Uses BPQ EXTERNAL interface
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
// Version 1.0 January 2005 - Initial Version
|
|
|
|
//
|
|
|
|
|
|
|
|
// Version 1.1 August 2005
|
|
|
|
//
|
|
|
|
// Treat NULL string in Registry as use current directory
|
|
|
|
|
|
|
|
// Version 1.2 January 2006
|
|
|
|
|
|
|
|
// Support multiple commections (not quire yet!)
|
|
|
|
// Fix memory leak when AGEPE not running
|
|
|
|
|
|
|
|
|
|
|
|
// Version 1.3 March 2006
|
|
|
|
|
|
|
|
// Support multiple connections
|
|
|
|
|
|
|
|
// Version 1.4 October 1006
|
|
|
|
|
|
|
|
// Write diagmnostics to BPQ console window instead of STDOUT
|
|
|
|
|
|
|
|
// Version 1.5 February 2008
|
|
|
|
|
|
|
|
// Changes for dynamic unload of bpq32.dll
|
|
|
|
|
|
|
|
// Version 1.5.1 September 2010
|
|
|
|
|
|
|
|
// Add option to get config from BPQ32.cfg
|
|
|
|
|
|
|
|
#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 VERSION_MAJOR 2
|
|
|
|
#define VERSION_MINOR 0
|
|
|
|
|
|
|
|
//uintptr_t _beginthread(void( *start_address )( int ), unsigned stack_size, int arglist);
|
|
|
|
|
|
|
|
//int ResetExtDriver(int num);
|
|
|
|
|
|
|
|
void ConnecttoAGWThread(void * portptr);
|
|
|
|
|
|
|
|
VOID __cdecl Consoleprintf(const char * format, ...);
|
|
|
|
|
|
|
|
void CreateMHWindow();
|
|
|
|
int Update_MH_List(struct in_addr ipad, char * call, char proto);
|
|
|
|
|
|
|
|
static BOOL ReadConfigFile(int Port);
|
2024-12-16 17:54:16 +00:00
|
|
|
int ConnecttoAGW(int port);
|
2022-08-28 09:35:46 +01:00
|
|
|
int ProcessReceivedData(int bpqport);
|
|
|
|
static int ProcessLine(char * buf, int Port, BOOL CheckPort);
|
|
|
|
|
|
|
|
|
|
|
|
extern UCHAR BPQDirectory[];
|
|
|
|
|
|
|
|
#pragma pack(1)
|
|
|
|
|
|
|
|
static struct AGWHEADER
|
|
|
|
{
|
|
|
|
byte Port;
|
|
|
|
byte filler1[3];
|
|
|
|
char DataKind;
|
|
|
|
byte filler2;
|
|
|
|
unsigned char PID;
|
|
|
|
byte filler3;
|
|
|
|
unsigned char callfrom[10];
|
|
|
|
unsigned char callto[10];
|
|
|
|
int DataLength;
|
|
|
|
int reserved;
|
|
|
|
|
|
|
|
} AGWHeader;
|
|
|
|
|
|
|
|
static struct AGWHEADER RXHeader;
|
|
|
|
|
|
|
|
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
#define MAXAGWPORTS 16
|
|
|
|
|
|
|
|
//LOGFONT LFTTYFONT ;
|
|
|
|
|
|
|
|
//HFONT hFont ;
|
|
|
|
|
|
|
|
static int AGWChannel[MAXBPQPORTS+1]; // BPQ Port to AGW Port
|
|
|
|
static int BPQPort[MAXAGWPORTS][MAXBPQPORTS+1]; // AGW Port and Connection to BPQ Port
|
|
|
|
static void * AGWtoBPQ_Q[MAXBPQPORTS+1]; // Frames for BPQ, indexed by BPQ Port
|
|
|
|
static void * BPQtoAGW_Q[MAXBPQPORTS+1]; // Frames for AGW. indexed by AGW port. Only used it TCP session is blocked
|
|
|
|
|
|
|
|
// Each port may be on a different machine. We only open one connection to each AGW instance
|
|
|
|
|
|
|
|
static SOCKET AGWSock[MAXBPQPORTS+1]; // Socket, indexed by BPQ Port
|
|
|
|
|
|
|
|
BOOL Alerted[MAXBPQPORTS+1]; // Error msg sent
|
|
|
|
|
|
|
|
static int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific AGW host
|
|
|
|
|
|
|
|
static char * AGWSignon[MAXBPQPORTS+1]; // Pointer to message for secure signin
|
|
|
|
|
|
|
|
static char * AGWHostName[MAXBPQPORTS+1]; // AGW Host - may be dotted decimal or DNS Name
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned int AGWInst = 0;
|
|
|
|
static int AttachedProcesses=0;
|
|
|
|
|
|
|
|
static HWND hResWnd,hMHWnd;
|
|
|
|
static BOOL GotMsg;
|
|
|
|
|
|
|
|
static HANDLE STDOUT=0;
|
|
|
|
|
|
|
|
//SOCKET sock;
|
|
|
|
|
|
|
|
static SOCKADDR_IN sinx;
|
|
|
|
static SOCKADDR_IN rxaddr;
|
|
|
|
static SOCKADDR_IN destaddr[MAXBPQPORTS+1];
|
|
|
|
|
|
|
|
static int addrlen=sizeof(sinx);
|
|
|
|
|
|
|
|
//static short AGWPort=0;
|
|
|
|
|
|
|
|
static time_t ltime,lasttime[MAXBPQPORTS+1];
|
|
|
|
|
|
|
|
static BOOL CONNECTED[MAXBPQPORTS+1];
|
|
|
|
static BOOL CONNECTING[MAXBPQPORTS+1];
|
|
|
|
|
|
|
|
//HANDLE hInstance;
|
|
|
|
|
|
|
|
|
|
|
|
static fd_set readfs;
|
|
|
|
static fd_set writefs;
|
|
|
|
static fd_set errorfs;
|
|
|
|
static struct timeval timeout;
|
|
|
|
|
|
|
|
|
|
|
|
static size_t ExtProc(int fn, int port, PMESSAGE buff)
|
|
|
|
{
|
|
|
|
int i,winerr;
|
|
|
|
int datalen;
|
|
|
|
PMSGWITHLEN buffptr;
|
|
|
|
char txbuff[500];
|
|
|
|
unsigned int bytes,txlen=0;
|
|
|
|
char ErrMsg[255];
|
|
|
|
|
|
|
|
switch (fn)
|
|
|
|
{
|
|
|
|
case 1: // poll
|
|
|
|
|
|
|
|
if (MasterPort[port] == port)
|
|
|
|
{
|
|
|
|
SOCKET sock = AGWSock[port];
|
|
|
|
|
|
|
|
// Only on first port using a host
|
|
|
|
|
|
|
|
if (CONNECTED[port] == FALSE && CONNECTING[port] == FALSE)
|
|
|
|
{
|
|
|
|
// See if time to reconnect
|
|
|
|
|
|
|
|
time( <ime );
|
|
|
|
if (ltime-lasttime[port] > 9 )
|
|
|
|
{
|
|
|
|
ConnecttoAGW(port);
|
|
|
|
lasttime[port]=ltime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FD_ZERO(&readfs);
|
|
|
|
|
|
|
|
if (CONNECTED[port]) FD_SET(sock,&readfs);
|
|
|
|
|
|
|
|
FD_ZERO(&writefs);
|
|
|
|
|
|
|
|
if (BPQtoAGW_Q[port]) FD_SET(sock,&writefs); // Need notification of busy clearing
|
|
|
|
|
|
|
|
FD_ZERO(&errorfs);
|
|
|
|
|
|
|
|
if (CONNECTED[port]) FD_SET(sock,&errorfs);
|
|
|
|
|
|
|
|
if (select((int)sock+1, &readfs, &writefs, &errorfs, &timeout) > 0)
|
|
|
|
{
|
|
|
|
// See what happened
|
|
|
|
|
|
|
|
if (FD_ISSET(sock, &readfs))
|
|
|
|
{
|
|
|
|
|
|
|
|
// data available
|
|
|
|
|
|
|
|
ProcessReceivedData(port);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(sock, &writefs))
|
|
|
|
{
|
|
|
|
if (BPQtoAGW_Q[port] == 0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Write block has cleared. Send rest of packet
|
|
|
|
|
|
|
|
buffptr = Q_REM(&BPQtoAGW_Q[port]);
|
|
|
|
|
|
|
|
txlen = buffptr->Len;
|
|
|
|
|
|
|
|
memcpy(txbuff, buffptr->Data, txlen);
|
|
|
|
|
|
|
|
bytes = send(AGWSock[port], (const char FAR *)&txbuff, txlen, 0);
|
|
|
|
|
|
|
|
ReleaseBuffer(buffptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD_ISSET(sock, &errorfs))
|
|
|
|
{
|
|
|
|
sprintf(ErrMsg, "AGW Connection lost for BPQ Port %d\n", port);
|
|
|
|
Alerted[port] = FALSE;
|
|
|
|
WritetoConsole(ErrMsg);
|
|
|
|
|
|
|
|
CONNECTED[port]=FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if any frames for this port
|
|
|
|
|
|
|
|
if (AGWtoBPQ_Q[port] !=0)
|
|
|
|
{
|
|
|
|
buffptr=Q_REM(&AGWtoBPQ_Q[port]);
|
|
|
|
|
|
|
|
datalen = buffptr->Len - 1;
|
|
|
|
|
|
|
|
memcpy(buff->DEST, &buffptr->Data[1] , datalen); // Data goes to +7, but we have an extra byte
|
|
|
|
datalen += MSGHDDRLEN;
|
|
|
|
buff->LENGTH = datalen;
|
|
|
|
|
|
|
|
ReleaseBuffer(buffptr);
|
|
|
|
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 2: // send
|
|
|
|
|
|
|
|
|
|
|
|
if (!CONNECTED[MasterPort[port]]) return 0; // Don't try if not connected
|
|
|
|
|
|
|
|
if (BPQtoAGW_Q[MasterPort[port]]) return 0; // Socket is blocked - just drop packets
|
|
|
|
// till it clears
|
|
|
|
|
|
|
|
// AGW has a control byte on front, so only subtract 6 from BPQ length
|
|
|
|
|
|
|
|
txlen = GetLengthfromBuffer((PDATAMESSAGE)buff);
|
|
|
|
txlen -= (MSGHDDRLEN - 1);
|
|
|
|
|
|
|
|
AGWHeader.Port=AGWChannel[port];
|
|
|
|
AGWHeader.DataKind='K'; // raw send
|
|
|
|
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
AGWHeader.DataLength = reverse(txlen);
|
|
|
|
#else
|
|
|
|
AGWHeader.DataLength = txlen;
|
|
|
|
#endif
|
|
|
|
memcpy(&txbuff,&AGWHeader,sizeof(AGWHeader));
|
|
|
|
memcpy(&txbuff[sizeof(AGWHeader) + 1], &buff->DEST, txlen);
|
|
|
|
txbuff[sizeof(AGWHeader)]=0;
|
|
|
|
|
|
|
|
txlen+=sizeof(AGWHeader);
|
|
|
|
|
|
|
|
bytes=send(AGWSock[MasterPort[port]],(const char FAR *)&txbuff, txlen, 0);
|
|
|
|
|
|
|
|
if (bytes != txlen)
|
|
|
|
{
|
|
|
|
|
|
|
|
// AGW doesn't seem to recover from a blocked write. For now just reset
|
|
|
|
|
|
|
|
winerr = WSAGetLastError();
|
|
|
|
|
|
|
|
i = sprintf(ErrMsg, "AGW Write Failed for port %d - error code = %d\n", port, winerr);
|
|
|
|
WritetoConsole(ErrMsg);
|
|
|
|
|
|
|
|
closesocket(AGWSock[MasterPort[port]]);
|
|
|
|
CONNECTED[MasterPort[port]] = FALSE;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
|
|
case 3: // CHECK IF OK TO SEND
|
|
|
|
|
|
|
|
return (0); // OK
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // reinit
|
|
|
|
|
|
|
|
// return(ReadConfigFile("BPQAXIP.CFG"));
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void * AGWExtInit(struct PORTCONTROL * PortEntry)
|
|
|
|
|
|
|
|
{
|
|
|
|
int i, port;
|
|
|
|
char Msg[255];
|
|
|
|
|
|
|
|
//
|
|
|
|
// Will be called once for each AGW port to be mapped to a BPQ Port
|
|
|
|
// The AGW port number is in CHANNEL - A=0, B=1 etc
|
|
|
|
//
|
|
|
|
// The Socket to connect to is in IOBASE
|
|
|
|
//
|
|
|
|
|
|
|
|
port=PortEntry->PORTNUMBER;
|
|
|
|
|
|
|
|
ReadConfigFile(port);
|
|
|
|
|
|
|
|
AGWChannel[port]=PortEntry->CHANNELNUM-65;
|
|
|
|
|
|
|
|
if (destaddr[port].sin_family == 0)
|
|
|
|
{
|
|
|
|
// not defined in config file
|
|
|
|
|
|
|
|
destaddr[port].sin_family = AF_INET;
|
|
|
|
destaddr[port].sin_port = htons(PortEntry->IOBASE);
|
|
|
|
|
|
|
|
AGWHostName[port]=malloc(10);
|
|
|
|
|
|
|
|
if (AGWHostName[port] != NULL)
|
|
|
|
strcpy(AGWHostName[port],"127.0.0.1");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
i=sprintf(Msg,"AGW Port %d Host %s %d\n",AGWChannel[port]+1,AGWHostName[port],htons(destaddr[port].sin_port));
|
|
|
|
WritetoConsole(Msg);
|
|
|
|
|
|
|
|
// See if we already have a port for this host
|
|
|
|
|
|
|
|
|
|
|
|
MasterPort[port]=port;
|
|
|
|
|
|
|
|
for (i=1;i<port;i++)
|
|
|
|
{
|
|
|
|
if (i == port) continue;
|
|
|
|
|
|
|
|
if (destaddr[i].sin_port == destaddr[port].sin_port &&
|
|
|
|
_stricmp(AGWHostName[i],AGWHostName[port]) == 0)
|
|
|
|
{
|
|
|
|
MasterPort[port]=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Alerted[port] = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
BPQPort[PortEntry->CHANNELNUM-65][MasterPort[port]]=PortEntry->PORTNUMBER;
|
|
|
|
|
|
|
|
if (MasterPort[port] == port)
|
|
|
|
ConnecttoAGW(port);
|
|
|
|
|
|
|
|
time(&lasttime[port]); // Get initial time value
|
|
|
|
|
|
|
|
|
|
|
|
return ExtProc;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
# Config file for BPQtoAGW
|
|
|
|
#
|
|
|
|
# For each AGW port defined in BPQCFG.TXT, Add a line here
|
|
|
|
# Format is BPQ Port, Host/IP Address, Port
|
|
|
|
|
|
|
|
#
|
|
|
|
# Any unspecified Ports will use 127.0.0.1 and port for BPQCFG.TXT IOADDR field
|
|
|
|
#
|
|
|
|
|
|
|
|
1 127.0.0.1 8000
|
|
|
|
2 127.0.0.1 8001
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
BOOL ReadConfigFile(int Port)
|
|
|
|
{
|
|
|
|
char buf[256],errbuf[256];
|
|
|
|
char * Config;
|
|
|
|
|
|
|
|
Config = PortConfig[Port];
|
|
|
|
|
|
|
|
if (Config)
|
|
|
|
{
|
|
|
|
// Using config from bpq32.cfg
|
|
|
|
|
|
|
|
char * ptr1 = Config, * ptr2;
|
|
|
|
|
|
|
|
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, FALSE))
|
|
|
|
{
|
|
|
|
WritetoConsole("BPQtoAGW - Bad config record ");
|
|
|
|
Consoleprintf(errbuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ProcessLine(char * buf, int Port, BOOL CheckPort)
|
|
|
|
{
|
|
|
|
char * ptr,* p_user,* p_password;
|
|
|
|
char * p_ipad;
|
|
|
|
char * p_udpport;
|
|
|
|
unsigned short AGWport;
|
|
|
|
int BPQport;
|
|
|
|
int len=510;
|
|
|
|
|
|
|
|
ptr = strtok(buf, " \t\n\r");
|
|
|
|
|
|
|
|
if(ptr == NULL) return (TRUE);
|
|
|
|
|
|
|
|
if(*ptr =='#') return (TRUE); // comment
|
|
|
|
|
|
|
|
if(*ptr ==';') return (TRUE); // comment
|
|
|
|
|
|
|
|
if (CheckPort)
|
|
|
|
{
|
|
|
|
p_ipad = strtok(NULL, " \t\n\r");
|
|
|
|
|
|
|
|
if (p_ipad == NULL) return (FALSE);
|
|
|
|
|
|
|
|
BPQport = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port != BPQport) return TRUE; // Not for us
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BPQport = Port;
|
|
|
|
p_ipad = ptr;
|
|
|
|
}
|
2023-06-21 08:21:04 +01:00
|
|
|
if(BPQport > 0 && BPQport < MAXBPQPORTS)
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
|
|
|
p_udpport = strtok(NULL, " \t\n\r");
|
|
|
|
|
|
|
|
if (p_udpport == NULL) return (FALSE);
|
|
|
|
|
|
|
|
AGWport = atoi(p_udpport);
|
|
|
|
|
|
|
|
destaddr[BPQport].sin_family = AF_INET;
|
|
|
|
destaddr[BPQport].sin_port = htons(AGWport);
|
|
|
|
|
|
|
|
AGWHostName[BPQport]=malloc(strlen(p_ipad)+1);
|
|
|
|
|
|
|
|
if (AGWHostName[BPQport] == NULL) return TRUE;
|
|
|
|
|
|
|
|
strcpy(AGWHostName[BPQport],p_ipad);
|
|
|
|
|
|
|
|
p_user = strtok(NULL, " \t\n\r");
|
|
|
|
|
|
|
|
if (p_user == NULL) return (TRUE);
|
|
|
|
|
|
|
|
p_password = strtok(NULL, " \t\n\r");
|
|
|
|
|
|
|
|
if (p_password == NULL) return (TRUE);
|
|
|
|
|
|
|
|
// Allocate buffer for signon message
|
|
|
|
|
|
|
|
AGWSignon[BPQport]=malloc(546);
|
|
|
|
|
|
|
|
if (AGWSignon[BPQport] == NULL) return TRUE;
|
|
|
|
|
|
|
|
memset(AGWSignon[BPQport],0,546);
|
|
|
|
|
|
|
|
AGWSignon[BPQport][4]='P';
|
|
|
|
|
|
|
|
memcpy(&AGWSignon[BPQport][28],&len,4);
|
|
|
|
|
|
|
|
strcpy(&AGWSignon[BPQport][36],p_user);
|
|
|
|
|
|
|
|
strcpy(&AGWSignon[BPQport][291],p_password);
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Bad line
|
|
|
|
//
|
|
|
|
return (FALSE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int ConnecttoAGW(int port)
|
|
|
|
{
|
|
|
|
_beginthread(ConnecttoAGWThread, 0, (void *)(size_t)port);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID ConnecttoAGWThread(void * portptr)
|
|
|
|
{
|
|
|
|
int port = (int)(size_t)portptr;
|
|
|
|
char Msg[255];
|
|
|
|
int err,i;
|
|
|
|
u_long param=1;
|
|
|
|
BOOL bcopt=TRUE;
|
|
|
|
struct hostent * HostEnt;
|
|
|
|
|
|
|
|
// Only called for the first BPQ port for a particular host/port combination
|
|
|
|
|
|
|
|
destaddr[port].sin_addr.s_addr = inet_addr(AGWHostName[port]);
|
|
|
|
|
|
|
|
if (destaddr[port].sin_addr.s_addr == INADDR_NONE)
|
|
|
|
{
|
|
|
|
// Resolve name to address
|
|
|
|
|
|
|
|
HostEnt = gethostbyname (AGWHostName[port]);
|
|
|
|
|
|
|
|
if (!HostEnt) return; // Resolve failed
|
|
|
|
|
|
|
|
memcpy(&destaddr[port].sin_addr.s_addr,HostEnt->h_addr,4);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
AGWSock[port]=socket(AF_INET,SOCK_STREAM,0);
|
|
|
|
|
|
|
|
if (AGWSock[port] == INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
i=sprintf(Msg, "Socket Failed for AGW socket - error code = %d\r\n", WSAGetLastError());
|
|
|
|
WritetoConsole(Msg);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
setsockopt (AGWSock[port],SOL_SOCKET,SO_REUSEADDR,(const char FAR *)&bcopt,4);
|
|
|
|
|
|
|
|
sinx.sin_family = AF_INET;
|
|
|
|
sinx.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
sinx.sin_port = 0;
|
|
|
|
|
|
|
|
if (bind(AGWSock[port], (LPSOCKADDR) &sinx, addrlen) != 0 )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Bind Failed
|
|
|
|
//
|
|
|
|
|
|
|
|
i=sprintf(Msg, "Bind Failed for AGW socket - error code = %d\r\n", WSAGetLastError());
|
|
|
|
WritetoConsole(Msg);
|
|
|
|
|
|
|
|
closesocket(AGWSock[port]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CONNECTING[port] = TRUE;
|
|
|
|
|
|
|
|
if (connect(AGWSock[port],(LPSOCKADDR) &destaddr[port],sizeof(destaddr[port])) == 0)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Connected successful
|
|
|
|
//
|
|
|
|
|
|
|
|
CONNECTED[port] = TRUE;
|
|
|
|
CONNECTING[port] = FALSE;
|
|
|
|
|
|
|
|
ioctlsocket (AGWSock[port],FIONBIO,¶m);
|
|
|
|
|
|
|
|
// If required, send signon
|
|
|
|
|
|
|
|
if (AGWSignon[port])
|
|
|
|
send(AGWSock[port],AGWSignon[port],546,0);
|
|
|
|
|
|
|
|
// Request Raw Frames
|
|
|
|
|
|
|
|
AGWHeader.Port=0;
|
|
|
|
AGWHeader.DataKind='k';
|
|
|
|
AGWHeader.DataLength=0;
|
|
|
|
|
|
|
|
send(AGWSock[port],(const char FAR *)&AGWHeader,sizeof(AGWHeader),0);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
err=WSAGetLastError();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Connect failed
|
|
|
|
//
|
|
|
|
|
|
|
|
if (Alerted[port] == FALSE)
|
|
|
|
{
|
|
|
|
sprintf(Msg, "Connect Failed for AGW Port %d - error code = %d\n", port, err);
|
|
|
|
WritetoConsole(Msg);
|
|
|
|
Alerted[port] = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
closesocket(AGWSock[port]);
|
|
|
|
CONNECTING[port] = FALSE;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ProcessReceivedData(int port)
|
|
|
|
{
|
|
|
|
unsigned int bytes;
|
|
|
|
int datalen,i;
|
|
|
|
char ErrMsg[255];
|
|
|
|
char Message[500];
|
|
|
|
PMSGWITHLEN buffptr;
|
|
|
|
|
|
|
|
// Need to extract messages from byte stream
|
|
|
|
|
|
|
|
// Use MSG_PEEK to ensure whole message is available
|
|
|
|
|
|
|
|
bytes = recv(AGWSock[port],(char *)&RXHeader,sizeof(RXHeader),MSG_PEEK);
|
|
|
|
|
|
|
|
if (bytes == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
i=sprintf(ErrMsg, "Read Failed for AGW socket - error code = %d\r\n", WSAGetLastError());
|
|
|
|
WritetoConsole(ErrMsg);
|
|
|
|
|
|
|
|
closesocket(AGWSock[port]);
|
|
|
|
|
|
|
|
CONNECTED[port]=FALSE;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytes == 0)
|
|
|
|
{
|
|
|
|
// zero bytes means connection closed
|
|
|
|
|
|
|
|
i=sprintf(ErrMsg, "AGW Connection closed for BPQ Port %d\r\n", port);
|
|
|
|
WritetoConsole(ErrMsg);
|
|
|
|
|
|
|
|
|
|
|
|
CONNECTED[port]=FALSE;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Have some data
|
|
|
|
|
|
|
|
if (bytes == sizeof(RXHeader))
|
|
|
|
{
|
|
|
|
// Have a header - see if we have any associated data
|
|
|
|
|
|
|
|
datalen=RXHeader.DataLength;
|
|
|
|
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
datalen = reverse(datalen);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (datalen > 0)
|
|
|
|
{
|
|
|
|
// Need data - See if enough there
|
|
|
|
|
|
|
|
bytes = recv(AGWSock[port],(char *)&Message,sizeof(RXHeader)+datalen,MSG_PEEK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytes == sizeof(RXHeader)+datalen)
|
|
|
|
{
|
|
|
|
bytes = recv(AGWSock[port],(char *)&RXHeader,sizeof(RXHeader),0);
|
|
|
|
|
|
|
|
if (datalen > 0)
|
|
|
|
{
|
|
|
|
bytes = recv(AGWSock[port],(char *)&Message,datalen,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Have header, and data if needed
|
|
|
|
|
|
|
|
// Only use frame type K
|
|
|
|
|
|
|
|
if (RXHeader.DataKind == 'K') // raw data
|
|
|
|
{
|
|
|
|
// Make sure it is for a port we want - we may not be using all AGW ports
|
|
|
|
|
|
|
|
if (BPQPort[RXHeader.Port][MasterPort[port]] == 0)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
// Get a buffer
|
|
|
|
|
|
|
|
buffptr = GetBuff();
|
|
|
|
|
|
|
|
if (buffptr == 0) return (0); // No buffers, so ignore
|
|
|
|
|
|
|
|
buffptr->Len = datalen;
|
|
|
|
memcpy(buffptr->Data, &Message, datalen);
|
|
|
|
|
|
|
|
C_Q_ADD(&AGWtoBPQ_Q[BPQPort[RXHeader.Port][MasterPort[port]]], buffptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Have header, but not sufficient data
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dont have at least header bytes
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|