/* 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 */ // // FLARQ Emulator/FLDIGI Interface for BPQ32 // #define _CRT_SECURE_NO_DEPRECATE #include "CHeaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); extern int (WINAPI FAR *EnumProcessesPtr)(); #include #include #include "tncinfo.h" #include "bpq32.h" #define VERSION_MAJOR 2 #define VERSION_MINOR 0 #define SD_RECEIVE 0x00 #define SD_SEND 0x01 #define SD_BOTH 0x02 #define DLE 0x10 #define SOH 1 #define STX 2 #define EOT 4 #define FEND 0xC0 #define FESC 0xDB #define TFEND 0xDC #define TFESC 0xDD #define TIMESTAMP 352 #define CONTIMEOUT 1200 #define AGWHDDRLEN sizeof(struct AGWHEADER) extern int (WINAPI FAR *GetModuleFileNameExPtr)(); //int ResetExtDriver(int num); ; int SemHeldByAPI; static void ConnecttoFLDigiThread(void * portptr); void CreateMHWindow(); int Update_MH_List(struct in_addr ipad, char * call, char proto); static int ConnecttoFLDigi(); static int ProcessReceivedData(int bpqport); static int ProcessLine(char * buf, int Port); int KillTNC(struct TNCINFO * TNC); static int RestartTNC(struct TNCINFO * TNC); VOID ProcessFLDigiPacket(struct TNCINFO * TNC, char * Message, int Len); VOID ProcessFLDigiKISSPacket(struct TNCINFO * TNC, char * Message, int Len); struct TNCINFO * GetSessionKey(char * key, struct TNCINFO * TNC); VOID SendARQData(struct TNCINFO * TNC, PMSGWITHLEN Buffer); static VOID DoMonitorHddr(struct TNCINFO * TNC, struct AGWHEADER * RXHeader, UCHAR * Msg); VOID SendRPBeacon(struct TNCINFO * TNC); VOID FLReleaseTNC(struct TNCINFO * TNC); unsigned int CalcCRC(UCHAR * ptr, int Len); VOID ARQTimer(struct TNCINFO * TNC); VOID QueueAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen); VOID SaveAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen); VOID ProcessARQStatus(struct TNCINFO * TNC, struct ARQINFO * ARQ, char *Input); VOID SendXMLPoll(struct TNCINFO * TNC); static int ProcessXMLData(int port); VOID CheckFLDigiData(struct TNCINFO * TNC); VOID SendPacket(struct TNCINFO * TNC, UCHAR * Msg, int MsgLen); int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len); VOID SendXMLCommand(struct TNCINFO * TNC, char * Command, char * Value, char ParamType); VOID FLSlowTimer(struct TNCINFO * TNC); VOID SendKISSCommand(struct TNCINFO * TNC, char * Msg); int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); VOID SuspendOtherPorts(struct TNCINFO * ThisTNC); VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC); VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len); char * strlop(char * buf, char delim); extern UCHAR BPQDirectory[]; #define MAXMPSKPORTS 16 //LOGFONT LFTTYFONT ; //HFONT hFont ; static int MPSKChannel[MAXBPQPORTS+1]; // BPQ Port to MPSK Port static int BPQPort[MAXMPSKPORTS][MAXBPQPORTS+1]; // MPSK Port and Connection to BPQ Port //static int MPSKtoBPQ_Q[MAXBPQPORTS+1]; // Frames for BPQ, indexed by BPQ Port //static int BPQtoMPSK_Q[MAXBPQPORTS+1]; // Frames for MPSK. indexed by MPSK port. Only used it TCP session is blocked // Each port may be on a different machine. We only open one connection to each MPSK instance static char * MPSKSignon[MAXBPQPORTS+1]; // Pointer to message for secure signin static unsigned int MPSKInst = 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 MPSKPort=0; static time_t ltime,lasttime[MAXBPQPORTS+1]; static BOOL CONNECTING[MAXBPQPORTS+1]; static BOOL CONNECTED[MAXBPQPORTS+1]; //HANDLE hInstance; static char WindowTitle[] = "FLDIGI"; static char ClassName[] = "FLDIGISTATUS"; static int RigControlRow = 165; static fd_set readfs; static fd_set writefs; static fd_set errorfs; static struct timeval timeout; int Blocksizes[10] = {0,2,4,8,16,32,64,128,256,512}; static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) { PMSGWITHLEN buffptr; char txbuff[500]; unsigned int txlen=0; struct TNCINFO * TNC = TNCInfo[port]; int Stream = 0; struct STREAMINFO * STREAM; int TNCOK; size_t Param; if (TNC == NULL) return 0; // Port not defined // Look for attach on any call // for (Stream = 0; Stream <= 1; Stream++) { STREAM = &TNC->Streams[Stream]; if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0) { char Cmd[80]; // New Attach int calllen; STREAM->Attached = TRUE; TNC->FLInfo->RAW = FALSE; calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall); STREAM->MyCall[calllen] = 0; STREAM->FramesOutstanding = 0; SuspendOtherPorts(TNC); // Dont allow connects on interlocked ports // Stop Scanning sprintf(Cmd, "%d SCANSTOP", TNC->Port); Rig_Command( (TRANSPORTENTRY *) -1, Cmd); sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); /* len = sprintf(Cmd, "%cSTOP_BEACON_ARQ_FAE\x1b", '\x1a'); if (TNC->MPSKInfo->TX) TNC->CmdSet = TNC->CmdSave = _strdup(Cmd); // Savde till not transmitting else SendPacket(TNC->TCPDataSock, Cmd, len, 0); */ } } switch (fn) { case 7: // 100 mS Timer. // G7TAJ's code to record activity for stats display if ( TNC->BusyFlags && CDBusy ) TNC->PortRecord->PORTCONTROL.ACTIVE += 2; if ( TNC->PTTState ) TNC->PortRecord->PORTCONTROL.SENDING += 2; // See if waiting for busy to clear before sending a connect if (TNC->BusyDelay) { // Still Busy? if (InterlockedCheckBusy(TNC) == FALSE) { // No, so send connect struct ARQINFO * ARQ = TNC->ARQInfo; int SendLen; char Reply[80]; SendLen = sprintf(Reply, "c%s:42 %s:24 %c 7 T60R5W10", STREAM->MyCall, STREAM->RemoteCall, ARQ->OurStream); strcpy(TNC->WEB_PROTOSTATE, "Connecting"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); ARQ->ARQState = ARQ_ACTIVE; ARQ->ARQTimerState = ARQ_CONNECTING; SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); STREAM->Connecting = TRUE; sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", STREAM->MyCall, STREAM->RemoteCall); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); strcpy(TNC->WEB_PROTOSTATE, "Connecting"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); TNC->BusyDelay = 0; } else { // Wait Longer TNC->BusyDelay--; if (TNC->BusyDelay == 0) { // Timed out - Send Error Response PMSGWITHLEN buffptr = GetBuff(); if (buffptr == 0) return (0); // No buffers, so ignore buffptr->Len=39; memcpy(buffptr+2,"Sorry, Can't Connect - Channel is busy\r", 39); C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); free(TNC->ConnectCmd); sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); } } } if (STREAM->NeedDisc) { STREAM->NeedDisc--; if (STREAM->NeedDisc == 0) { // Send the DISCONNECT TidyClose(TNC, 0); } } ARQTimer(TNC); SendXMLPoll(TNC); TNC->SlowTimer--; if (TNC->SlowTimer < 0) { TNC->SlowTimer = 100; FLSlowTimer(TNC); // 10 Secs } return 0; case 1: // poll if (TNC->CONNECTED == FALSE && TNC->CONNECTING == FALSE && TNC->FLInfo->KISSMODE == FALSE) { // See if time to reconnect time( <ime ); if (ltime-lasttime[port] >9 ) { ConnecttoFLDigi(port); lasttime[port]=ltime; } } pollloop: FD_ZERO(&readfs); if (TNC->CONNECTED) if (TNC->TCPSock) FD_SET(TNC->TCPSock,&readfs); if (TNC->CONNECTED || TNC->FLInfo->KISSMODE) FD_SET(TNC->TCPDataSock,&readfs); // FD_ZERO(&writefs); // if (TNC->BPQtoWINMOR_Q) FD_SET(TNC->TCPDataSock,&writefs); // Need notification of busy clearing FD_ZERO(&errorfs); if (TNC->CONNECTED) if (TNC->TCPSock) FD_SET(TNC->TCPSock,&errorfs); if (TNC->CONNECTED || TNC->FLInfo->KISSMODE) FD_SET(TNC->TCPDataSock,&errorfs); if (select((int)TNC->TCPDataSock + 1, &readfs, &writefs, &errorfs, &timeout) > 0) { // See what happened if (FD_ISSET(TNC->TCPDataSock,&readfs)) { // data available ProcessReceivedData(port); goto pollloop; } if (FD_ISSET(TNC->TCPSock,&readfs)) { // data available ProcessXMLData(port); } if (FD_ISSET(TNC->TCPDataSock,&writefs)) { // Connect success TNC->CONNECTED = TRUE; TNC->CONNECTING = FALSE; sprintf(TNC->WEB_COMMSSTATE, "Connected to FLDIGI"); SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); // If required, send signon // SendPacket(TNC->TCPDataSock,"\x1a", 1, 0); // SendPacket(TNC->TCPDataSock,"DIGITAL MODE ?", 14, 0); // SendPacket(TNC->TCPDataSock,"\x1b", 1, 0); // EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC); } if (FD_ISSET(TNC->TCPDataSock,&errorfs) || FD_ISSET(TNC->TCPSock,&errorfs)) { // if connecting, then failed, if connected then has just disconnected // if (CONNECTED[port]) // if (!CONNECTING[port]) // { // i=sprintf(ErrMsg, "MPSK Connection lost for BPQ Port %d\r\n", port); // WritetoConsole(ErrMsg); // } CONNECTING[port]=FALSE; CONNECTED[port]=FALSE; } } // See if any frames for this port for (Stream = 0; Stream <= 1; Stream++) { STREAM = &TNC->Streams[Stream]; if (STREAM->Attached) CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete); if (STREAM->ReportDISC) { STREAM->ReportDISC = FALSE; buff->PORT = Stream; return -1; } // if Busy, send buffer status poll if (STREAM->PACTORtoBPQ_Q == 0) { if (STREAM->DiscWhenAllSent) { STREAM->DiscWhenAllSent--; if (STREAM->DiscWhenAllSent == 0) STREAM->ReportDISC = TRUE; // Dont want to leave session attached. Causes too much confusion } } else { int datalen; buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q); datalen = (int)buffptr->Len; buff->PORT = Stream; // Compatibility with Kam Driver buff->PID = 0xf0; memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte datalen += (MSGHDDRLEN + 1); PutLengthinBuffer(buff, datalen); WritetoTrace(TNC, &buffptr->Data[0], datalen - (MSGHDDRLEN + 1)); ReleaseBuffer(buffptr); return (1); } } if (TNC->PortRecord->UI_Q) { struct _MESSAGE * buffptr; int SendLen; char Reply[256]; int UILen; char * UIMsg; buffptr = Q_REM(&TNC->PortRecord->UI_Q); UILen = buffptr->LENGTH; UILen -= 23; UIMsg = buffptr->L2DATA; UIMsg[UILen] = 0; if (UILen < 129 && TNC->Streams[0].Attached == FALSE) // Be sensible! { // >00uG8BPQ:72 TestA SendLen = sprintf(Reply, "u%s:72 %s", TNC->NodeCall, UIMsg); SendPacket(TNC, Reply, SendLen); } ReleaseBuffer(buffptr); } return (0); case 2: // send if (!TNC->CONNECTED) return 0; // Don't try if not connected to TNC Stream = buff->PORT; STREAM = &TNC->Streams[Stream]; // txlen=(buff[6]<<8) + buff[5] - 8; txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - (MSGHDDRLEN + 1); // 1 as no PID; if (STREAM->Connected) { buffptr = GetBuff(); if (buffptr == 0) return (0); // No buffers, so ignore buffptr->Len = txlen; memcpy(buffptr->Data, buff->L2DATA, txlen); WritetoTrace(TNC, buffptr->Data, txlen); C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); return (0); } else { buff->L2DATA[txlen] = 0; _strupr(&buff->L2DATA[0]); if (_memicmp(&buff->L2DATA[0], "D\r", 2) == 0) { if (STREAM->Connected) TidyClose(TNC, buff->PORT); STREAM->ReportDISC = TRUE; // Tell Node TNC->FLInfo->MCASTMODE = FALSE; return 0; } // See if Local command (eg RADIO) if (_memicmp(&buff->L2DATA[0], "RADIO ", 6) == 0) { sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &buff->L2DATA[6]); if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &buff->L2DATA[0])) { } else { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr == 0) return 1; // No buffers, so ignore buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "%s", &buff->L2DATA[0]); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); } return 1; } if (_memicmp(&buff->L2DATA[0], "MODEM ", 6) == 0) { buff->L2DATA[txlen -1] = 0; _strupr(&buff->L2DATA[0]); // If in KISS mode, send as a KISS command Frame if (TNC->FLInfo->KISSMODE) { sprintf(txbuff, "MODEM:%s MODEM:", &buff->L2DATA[6]); SendKISSCommand(TNC, txbuff); } else { SendXMLCommand(TNC, "modem.set_by_name", &buff->L2DATA[6], 'S'); } TNC->InternalCmd = TRUE; return 1; } if (_memicmp(buff->L2DATA, "FREQ ", 5) == 0) { buff->L2DATA[txlen - 1] = 0; _strupr(&buff->L2DATA[0]); // If in KISS mode, send as a KISS command Frame if (TNC->FLInfo->KISSMODE) { sprintf(txbuff, "WFF:%s WFF:", &buff->L2DATA[5]); SendKISSCommand(TNC, txbuff); } else { SendXMLCommand(TNC, "modem.set_carrier", (char *)atoi(&buff->L2DATA[5]), 'I'); } TNC->InternalCmd = TRUE; return 1; } if (_memicmp(buff->L2DATA, "SQUELCH ", 8) == 0) { buff->L2DATA[txlen - 1] = 0; _strupr(&buff->L2DATA[0]); // Only works in KISS if (TNC->FLInfo->KISSMODE) { if (_memicmp(&buff->L2DATA[8], "ON", 2) == 0) sprintf(txbuff, "KPSQL:ON KPSQL:"); else if (_memicmp(&buff->L2DATA[8], "OFF", 3) == 0) sprintf(txbuff, "KPSQL:OFF KPSQL:"); else txlen = sprintf(txbuff, "KPSQLS:%s KPSQLS:", &buff->L2DATA[8]); SendKISSCommand(TNC, txbuff); TNC->InternalCmd = TRUE; } return 1; } if (_memicmp(buff->L2DATA, "KPSATT ", 7) == 0) { buff->L2DATA[txlen - 1] = 0; _strupr(&buff->L2DATA[0]); // If in KISS mode, send as a KISS command Frame if (TNC->FLInfo->KISSMODE) { sprintf(txbuff, "KPSATT:%s KPSATT:", &buff->L2DATA[7]); SendKISSCommand(TNC, txbuff); TNC->InternalCmd = TRUE; } return 1; } if (STREAM->Connecting && _memicmp(buff->L2DATA, "ABORT", 5) == 0) { // len = sprintf(Command,"%cSTOP_SELECTIVE_CALL_ARQ_FAE\x1b", '\x1a'); // if (TNC->MPSKInfo->TX) // TNC->CmdSet = TNC->CmdSave = _strdup(Command); // Save till not transmitting // else // SendPacket(TNC->TCPDataSock, Command, len, 0); // TNC->InternalCmd = TRUE; return (0); } if (_memicmp(&buff->L2DATA[0], "MODE", 4) == 0) { PMSGWITHLEN buffptr = GetBuff(); buff->L2DATA[txlen - 1] = 0; // Remove CR if (strstr(&buff->L2DATA[0], "RAW")) TNC->FLInfo->RAW = TRUE; else if (strstr(&buff->L2DATA[0], "KISS")) TNC->FLInfo->RAW = FALSE; else { buffptr->Len = sprintf(&buffptr->Data[0], "FLDigi} Error - Invalid Mode\r"); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); return 1; } buffptr->Len = sprintf(&buffptr->Data[0], "FLDigi} Ok - Mode is %s\r", (TNC->FLInfo->RAW)?"RAW":"KISS"); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); return 1; } if (_memicmp(&buff->L2DATA[0], "MCAST", 5) == 0) { PMSGWITHLEN buffptr = GetBuff(); TNC->FLInfo->MCASTMODE = TRUE; buffptr->Len = sprintf(buffptr->Data, "FLDigi} Ok\r"); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); return 1; } if (_memicmp(&buff->L2DATA[0], "INUSE?", 6) == 0) { // Return Error if in use, OK if not PMSGWITHLEN buffptr = GetBuff(); int s = 0; while(s <= 1) { if (s != Stream) { if (TNC->PortRecord->ATTACHEDSESSIONS[s]) { buffptr->Len = sprintf(buffptr->Data, "FLDig} Error - In use\r"); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); return 1; // Busy } } s++; } buffptr->Len = sprintf(buffptr->Data, "FLDigi} Ok - Not in use\r"); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); return 1; } // See if a Connect Command. if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect { char * ptr; char * context; struct ARQINFO * ARQ = TNC->ARQInfo; int SendLen; char Reply[80]; buff->L2DATA[txlen] = 0; _strupr(&buff->L2DATA[0]); memset(ARQ, 0, sizeof(struct ARQINFO)); // Reset ARQ State ARQ->TXSeq = ARQ->TXLastACK = 63; // Last Sent ARQ->RXHighest = ARQ->RXNoGaps = 63; // Last Received ARQ->OurStream = (rand() % 78) + 49; // To give some protection against other stuff on channel ARQ->FarStream = 48; // Not yet defined TNC->FLInfo->FLARQ = FALSE; memset(STREAM->RemoteCall, 0, 10); ptr = strtok_s(&buff->L2DATA[2], " ,\r", &context); if (ptr == 0) { PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr) { buffptr->Len = sprintf(buffptr->Data, "FLDigi} Error - Call missing from C command\r"); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } STREAM->DiscWhenAllSent = 10; return 0; } strcpy(STREAM->RemoteCall, ptr); // See if Busy if (InterlockedCheckBusy(TNC)) { // Channel Busy. Unless override set, wait if (TNC->OverrideBusy == 0) { // Save Command, and wait up to 10 secs sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel"); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); TNC->BusyDelay = TNC->BusyWait * 10; // BusyWait secs return 0; } } TNC->OverrideBusy = FALSE; //00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36 SendLen = sprintf(Reply, "c%s:42 %s:24 %c 7 T60R5W10", STREAM->MyCall, STREAM->RemoteCall, ARQ->OurStream); strcpy(TNC->WEB_PROTOSTATE, "Connecting"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); ARQ->ARQState = ARQ_ACTIVE; ARQ->ARQTimerState = ARQ_CONNECTING; SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); Debugprintf("FLDIGI Connection %s", Reply); STREAM->Connecting = TRUE; sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", STREAM->MyCall, STREAM->RemoteCall); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); strcpy(TNC->WEB_PROTOSTATE, "Connecting"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); return 0; } // Send any other command to FLDIGI buff->L2DATA[txlen - 1] = 0; _strupr(&buff->L2DATA[0]); // If in KISS mode, send as a KISS command Frame if (TNC->FLInfo->KISSMODE) { char outbuff[1000]; int newlen; buff->L2DATA[-1] = 6; // KISS Control newlen = KissEncode(&buff->L2DATA[-1], outbuff, txlen); sendto(TNC->TCPDataSock, outbuff, newlen, 0, (struct sockaddr *)&TNC->Datadestaddr, sizeof(struct sockaddr)); } else { SendXMLCommand(TNC, "modem.set_by_name", &buff->L2DATA[0], 'S'); } TNC->InternalCmd = TRUE; } return (0); case 3: Stream = (int)(size_t)buff; TNCOK = TNC->CONNECTED; STREAM = &TNC->Streams[Stream]; { // Busy if TX Window reached struct ARQINFO * ARQ = TNC->ARQInfo; int Outstanding; Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&TNC->Streams[0].BPQtoPACTOR_Q); // Save for Appl Level Queued Frames if (Outstanding > ARQ->TXWindow) return (1 | TNCOK << 8 | STREAM->Disconnecting << 15); // 3rd Nibble is frames unacked else return TNCOK << 8 | STREAM->Disconnecting << 15; } return TNCOK << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting case 4: // reinit shutdown(TNC->TCPSock, SD_BOTH); shutdown(TNC->TCPDataSock, SD_BOTH); Sleep(100); closesocket(TNC->TCPSock); closesocket(TNC->TCPDataSock); TNC->CONNECTED = FALSE; if (TNC->WeStartedTNC) { KillTNC(TNC); RestartTNC(TNC); } return (0); case 5: // Close shutdown(TNC->TCPSock, SD_BOTH); shutdown(TNC->TCPDataSock, SD_BOTH); Sleep(100); closesocket(TNC->TCPSock); closesocket(TNC->TCPDataSock); if (TNC->WeStartedTNC) { KillTNC(TNC); } return 0; case 6: // Scan Stop Interface Param = (size_t)buff; if (Param == 2) // Check Permission (shouldn't happen) { Debugprintf("Scan Check Permission called on FLDIGI"); return 1; // OK to change } if (!TNC->CONNECTED) return 0; // No connection so no interlock if (Param == 1) // Request Permission { if (TNC->ConnectPending == 0) { TNC->FLInfo->CONOK = FALSE; TNC->GavePermission = TRUE; return 0; // OK to Change } if (TNC->ConnectPending) TNC->ConnectPending--; // Time out if set too long if (!TNC->ConnectPending) return 0; // OK to Change return TRUE; } if (Param == 3) // Release Permission { if (TNC->GavePermission) { TNC->FLInfo->CONOK = TRUE; TNC->GavePermission = FALSE; } return 0; } } return 0; } #ifndef LINBPQ int FindFLDIGI(char * Path) { HANDLE hProc; char ExeName[256] = ""; char FLDIGIName[256]; DWORD Pid = 0; DWORD Processes[1024], Needed, Count; unsigned int i; if (EnumProcessesPtr == NULL) return 0; // Cant get PID if (!EnumProcessesPtr(Processes, sizeof(Processes), &Needed)) return TRUE; // Path is to .bat, so need to strip extension of both names strcpy(FLDIGIName, Path); strlop(FLDIGIName, '.'); // Calculate how many process identifiers were returned. Count = Needed / sizeof(DWORD); for (i = 0; i < Count; i++) { if (Processes[i] != 0) { hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, Processes[i]); if (hProc) { GetModuleFileNameExPtr(hProc, 0, ExeName, 255); CloseHandle(hProc); strlop(ExeName, '.'); if (_stricmp(ExeName, FLDIGIName) == 0) return Processes[i]; } } } return 0; } static KillTNC(struct TNCINFO * TNC) { HANDLE hProc; if (TNC->PTTMode) Rig_PTT(TNC, FALSE); // Make sure PTT is down if (TNC->ProgramPath) TNC->PID = FindFLDIGI(TNC->ProgramPath); if (TNC->PID == 0) return 0; hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TNC->PID); if (hProc) { TerminateProcess(hProc, 0); CloseHandle(hProc); } TNC->WeStartedTNC = 0; // So we don't try again return 0; } #endif static int RestartTNC(struct TNCINFO * TNC) { if (TNC->ProgramPath == NULL) return 0; _strlwr(TNC->ProgramPath); if (_memicmp(TNC->ProgramPath, "REMOTE:", 7) == 0) { int n; // Try to start TNC on a remote host SOCKET sock = socket(AF_INET,SOCK_DGRAM,0); struct sockaddr_in destaddr; Debugprintf("trying to restart FLDIGI %s", TNC->ProgramPath); if (sock == INVALID_SOCKET) return 0; destaddr.sin_family = AF_INET; destaddr.sin_addr.s_addr = inet_addr(TNC->HostName); destaddr.sin_port = htons(8500); if (destaddr.sin_addr.s_addr == INADDR_NONE) { // Resolve name to address struct hostent * HostEnt = gethostbyname (TNC->HostName); if (!HostEnt) return 0; // Resolve failed memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); } n = sendto(sock, TNC->ProgramPath, (int)strlen(TNC->ProgramPath), 0, (struct sockaddr *)&destaddr, sizeof(destaddr)); Debugprintf("Restart FLDIGI - sento returned %d", n); Sleep(100); closesocket(sock); return 1; // Cant tell if it worked, but assume ok } #ifndef LINBPQ { STARTUPINFO SInfo; // pointer to STARTUPINFO PROCESS_INFORMATION PInfo; // pointer to PROCESS_INFORMATION char HomeDir[MAX_PATH]; int i, ret; SInfo.cb=sizeof(SInfo); SInfo.lpReserved=NULL; SInfo.lpDesktop=NULL; SInfo.lpTitle=NULL; SInfo.dwFlags=0; SInfo.cbReserved2=0; SInfo.lpReserved2=NULL; if (TNC->ProgramPath) { strcpy(HomeDir, TNC->ProgramPath); i = strlen(HomeDir); while(--i) { if (HomeDir[i] == '/' || HomeDir[i] == '\\') { HomeDir[i] = 0; break; } } // for some reason the program name must be lower case _strlwr(TNC->ProgramPath); ret = CreateProcess(TNC->ProgramPath, NULL, NULL, NULL, FALSE,0 ,NULL , NULL, &SInfo, &PInfo); return ret; } } #endif return 0; } static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) { int Len = sprintf(Buff, "" "" "FLDigi Status" "

FLDIGI Status

"); Len += sprintf(&Buff[Len], ""); Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); Len += sprintf(&Buff[Len], "", TNC->WEB_CHANSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_PROTOSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); // Len += sprintf(&Buff[Len], "", TNC->WEB_RESTARTS); Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Channel State%s
Proto State%s
Traffic%s
TNC Restarts
"); Len += sprintf(&Buff[Len], "", TNC->WebBuffer); Len = DoScanLine(TNC, Buff, Len); return Len; } VOID FLDIGISuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC) { TNC->FLInfo->CONOK = FALSE; } VOID FLDIGIReleasePort(struct TNCINFO * TNC) { TNC->FLInfo->CONOK = TRUE; } VOID SendKISSCommand(struct TNCINFO * TNC, char * Msg) { int txlen, rc; char txbuff[256]; char outbuff[256]; txlen = sprintf(txbuff, "%c%s", 6, Msg); txlen = KissEncode(txbuff, outbuff, txlen); rc = sendto(TNC->TCPDataSock, outbuff, txlen, 0, (struct sockaddr *)&TNC->Datadestaddr, sizeof(struct sockaddr)); } VOID * FLDigiExtInit(EXTPORTDATA * PortEntry) { int i, port; char Msg[255]; struct TNCINFO * TNC; char * ptr; // // The Socket to connect to is in IOBASE // srand((unsigned int)time(NULL)); port = PortEntry->PORTCONTROL.PORTNUMBER; ReadConfigFile(port, ProcessLine); TNC = TNCInfo[port]; if (TNC == NULL) { // Not defined in Config file sprintf(Msg," ** Error - no info in BPQ32.cfg for this port\n"); WritetoConsole(Msg); return ExtProc; } TNC->Port = port; TNC->PortRecord = PortEntry; if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) memcpy(TNC->NodeCall, MYNODECALL, 10); else ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0) TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK; PortEntry->PORTCONTROL.PROTOCOL = 10; PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream PortEntry->PORTCONTROL.UICAPABLE = 1; // Can send beacons PortEntry->PORTCONTROL.PORTQUALITY = 0; PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - None TNC->FLInfo->CONOK = TRUE; if (PortEntry->PORTCONTROL.PORTPACLEN == 0) PortEntry->PORTCONTROL.PORTPACLEN = 250; TNC->SuspendPortProc = FLDIGISuspendPort; TNC->ReleasePortProc = FLDIGIReleasePort; ptr=strchr(TNC->NodeCall, ' '); if (ptr) *(ptr) = 0; // Null Terminate TNC->Hardware = H_FLDIGI; if (TNC->BusyWait == 0) TNC->BusyWait = 10; MPSKChannel[port] = PortEntry->PORTCONTROL.CHANNELNUM-65; PortEntry->MAXHOSTMODESESSIONS = 1; i=sprintf(Msg,"FLDigi Host %s Port %d \n", TNC->HostName, TNC->TCPPort); WritetoConsole(Msg); #ifndef LINBPQ if (TNC->ProgramPath) TNC->PID = FindFLDIGI(TNC->ProgramPath); if (TNC->PID == 0) // Not running #endif TNC->WeStartedTNC = RestartTNC(TNC); // Always try if Linux if (TNC->FLInfo->KISSMODE) { // Open Datagram port SOCKET sock; u_long param=1; BOOL bcopt=TRUE; struct sockaddr_in sinx; struct hostent * HostEnt = NULL; TNC->FLInfo->CmdControl = 5; //Send params immediately TNC->Datadestaddr.sin_addr.s_addr = inet_addr(TNC->HostName); if (TNC->Datadestaddr.sin_addr.s_addr == INADDR_NONE) { // Resolve name to address HostEnt = gethostbyname (TNC->HostName); if (HostEnt) { memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4); } } TNC->TCPDataSock = sock = socket(AF_INET,SOCK_DGRAM,0); ioctl(sock, FIONBIO, ¶m); setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char FAR *)&bcopt,4); sinx.sin_family = AF_INET; sinx.sin_addr.s_addr = INADDR_ANY; sinx.sin_port = htons(TNC->TCPPort + 1); if (bind(sock, (struct sockaddr *) &sinx, sizeof(sinx)) != 0 ) { // Bind Failed int err = WSAGetLastError(); Consoleprintf("Bind Failed for UDP port %d - error code = %d", TNC->TCPPort, err); } TNC->Datadestaddr.sin_family = AF_INET; TNC->Datadestaddr.sin_port = htons(TNC->TCPPort); } else ConnecttoFLDigi(port); time(&lasttime[port]); // Get initial time value PortEntry->PORTCONTROL.TNC = TNC; TNC->WebWindowProc = WebProc; TNC->WebWinX = 520; TNC->WebWinY = 500; TNC->WebBuffer = zalloc(5000); TNC->WEB_COMMSSTATE = zalloc(100); TNC->WEB_TNCSTATE = zalloc(100); TNC->WEB_CHANSTATE = zalloc(100); TNC->WEB_BUFFERS = zalloc(100); TNC->WEB_PROTOSTATE = zalloc(100); TNC->WEB_RESTARTTIME = zalloc(100); TNC->WEB_RESTARTS = zalloc(100); TNC->WEB_MODE = zalloc(50); TNC->WEB_TRAFFIC = zalloc(100); #ifndef LINBPQ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 450, ForcedClose); CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Mode/CF", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Proto State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0 Resent 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL); TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL, 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL); TNC->ClientHeight = 450; TNC->ClientWidth = 500; TNC->hMenu = CreatePopupMenu(); AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill FLDigi"); AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart FLDigi"); AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session"); MoveWindows(TNC); #endif return ExtProc; } static int ProcessLine(char * buf, int Port) { UCHAR * ptr,* p_cmd; char * p_ipad = 0; char * p_port = 0; unsigned short WINMORport = 0; int BPQport; int len=510; struct TNCINFO * TNC; struct ARQINFO * ARQ; struct FLINFO * FL; char errbuf[256]; strcpy(errbuf, buf); ptr = strtok(buf, " \t\n\r"); if(ptr == NULL) return (TRUE); if(*ptr =='#') return (TRUE); // comment if(*ptr ==';') return (TRUE); // comment if (_stricmp(buf, "ADDR")) return FALSE; // Must start with ADDR ptr = strtok(NULL, " \t\n\r"); BPQport = Port; p_ipad = ptr; TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO)); ARQ = TNC->ARQInfo = zalloc(sizeof(struct ARQINFO)); FL = TNC->FLInfo = zalloc(sizeof(struct FLINFO)); TNC->Timeout = 50; // Default retry = 5 seconds TNC->Retries = 6; // Default Retries TNC->Window = 16; TNC->FLInfo->KISSMODE = TRUE; // Default to KISS TNC->InitScript = malloc(1000); TNC->InitScript[0] = 0; if (p_ipad == NULL) p_ipad = strtok(NULL, " \t\n\r"); if (p_ipad == NULL) return (FALSE); p_port = strtok(NULL, " \t\n\r"); if (p_port == NULL) return (FALSE); TNC->TCPPort = atoi(p_port); TNC->destaddr.sin_family = AF_INET; TNC->destaddr.sin_port = htons(TNC->TCPPort + 40); // Defaults XML 7362 ARQ 7322 TNC->Datadestaddr.sin_family = AF_INET; TNC->Datadestaddr.sin_port = htons(TNC->TCPPort); TNC->HostName = malloc(strlen(p_ipad)+1); if (TNC->HostName == NULL) return TRUE; strcpy(TNC->HostName,p_ipad); ptr = strtok(NULL, " \t\n\r"); if (ptr) { if (_memicmp(ptr, "PATH", 4) == 0) { p_cmd = strtok(NULL, "\n\r"); if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); } } // Read Initialisation lines while(TRUE) { if (GetLine(buf) == 0) return TRUE; strcpy(errbuf, buf); if (memcmp(buf, "****", 4) == 0) return TRUE; ptr = strchr(buf, ';'); if (ptr) { *ptr++ = 13; *ptr = 0; } if (_memicmp(buf, "TIMEOUT", 7) == 0) TNC->Timeout = atoi(&buf[8]) * 10; else if (_memicmp(buf, "RETRIES", 7) == 0) TNC->Retries = atoi(&buf[8]); else if (_memicmp(buf, "WINDOW", 6) == 0) TNC->Window = atoi(&buf[7]); else if (_memicmp(buf, "ARQMODE", 7) == 0) TNC->FLInfo->KISSMODE = FALSE; else if (_memicmp(buf, "DEFAULTMODEM", 12) == 0) // Send Beacon after each session { // Check that freq is also specified char * Freq = strchr(&buf[13], '/'); if (Freq) { *(Freq++) = 0; strcpy(TNC->FLInfo->DefaultMode, &buf[13]); TNC->FLInfo->DefaultFreq = atoi(Freq); } } else strcat (TNC->InitScript, buf); } return (TRUE); } static int ConnecttoFLDigi(int port) { _beginthread(ConnecttoFLDigiThread, 0, (void *)(size_t)port); return 0; } static VOID ConnecttoFLDigiThread(void * portptr) { int port = (int)(size_t)portptr; char Msg[255]; int err,i; u_long param=1; BOOL bcopt=TRUE; struct hostent * HostEnt = NULL; struct TNCINFO * TNC = TNCInfo[port]; Sleep(5000); // Allow init to complete TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName); TNC->Datadestaddr.sin_addr.s_addr = inet_addr(TNC->HostName); if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE) { // Resolve name to address HostEnt = gethostbyname (TNC->HostName); if (!HostEnt) return; // Resolve failed memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4); memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4); } if (TNC->TCPSock) { Debugprintf("FLDIGI Closing Sock %d", TNC->TCPSock); closesocket(TNC->TCPSock); } TNC->TCPSock = 0; TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0); if (TNC->TCPSock == INVALID_SOCKET) { i=sprintf(Msg, "Socket Failed for FLDigi Control socket - error code = %d\n", WSAGetLastError()); WritetoConsole(Msg); return; } setsockopt (TNC->TCPSock, 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; TNC->CONNECTING = TRUE; if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0) { // // Connected successful // } else { if (TNC->Alerted == FALSE) { err=WSAGetLastError(); i=sprintf(Msg, "Connect Failed for FLDigi Control socket - error code = %d\n", err); WritetoConsole(Msg); sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); TNC->Alerted = TRUE; } closesocket(TNC->TCPSock); TNC->TCPSock = 0; TNC->CONNECTING = FALSE; return; } TNC->LastFreq = 0; if (TNC->TCPDataSock) closesocket(TNC->TCPDataSock); TNC->TCPDataSock = 0; TNC->TCPDataSock=socket(AF_INET,SOCK_STREAM,0); setsockopt (TNC->TCPDataSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4); if (TNC->TCPDataSock == INVALID_SOCKET) { i=sprintf(Msg, "Socket Failed for FLDigi socket - error code = %d\r\n", WSAGetLastError()); WritetoConsole(Msg); closesocket(TNC->TCPSock); closesocket(TNC->TCPDataSock); TNC->TCPSock = 0; TNC->CONNECTING = FALSE; return; } if (bind(TNC->TCPDataSock, (LPSOCKADDR) &sinx, addrlen) != 0 ) { // // Bind Failed // i=sprintf(Msg, "Bind Failed for FLDigi Data socket - error code = %d\r\n", WSAGetLastError()); WritetoConsole(Msg); closesocket(TNC->TCPSock); closesocket(TNC->TCPDataSock); TNC->TCPSock = 0; TNC->TCPDataSock = 0; TNC->CONNECTING = FALSE; return; } if (connect(TNC->TCPDataSock,(LPSOCKADDR) &TNC->Datadestaddr,sizeof(TNC->Datadestaddr)) == 0) { ioctlsocket (TNC->TCPDataSock,FIONBIO,¶m); // Set nonblocking TNC->CONNECTED = TRUE; TNC->CONNECTING = FALSE; TNC->Alerted = TRUE; sprintf(TNC->WEB_COMMSSTATE, "Connected to FLDIGI"); SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); } else { sprintf(Msg, "Connect Failed for FLDigi Data socket Port %d - error code = %d\r\n", port, WSAGetLastError()); WritetoConsole(Msg); closesocket(TNC->TCPSock); closesocket(TNC->TCPDataSock); TNC->TCPSock = 0; TNC->TCPDataSock = 0; TNC->CONNECTING = FALSE; } return; } VOID UpdateStatsLine(struct TNCINFO * TNC, struct STREAMINFO * STREAM) { sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %d Resent %d Queued %d", STREAM->BytesRXed, STREAM->BytesTXed, STREAM->BytesAcked, STREAM->BytesResent, STREAM->BytesOutstanding); SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC); } VOID SendPacket(struct TNCINFO * TNC, UCHAR * Msg, int MsgLen) { if (TNC->FLInfo->KISSMODE) { char KissMsg[1000]; char outbuff[1000]; int newlen; if (TNC->FLInfo->RAW) { // KISS RAW // Add CRC and Send unsigned short CRC; char crcstring[6]; KissMsg[0] = 7; // KISS Raw KissMsg[1] = 1; // SOH KissMsg[2] = '0'; // Version KissMsg[3] = TNC->ARQInfo->FarStream; Msg[MsgLen] = 0; memcpy(&KissMsg[4], Msg, MsgLen +1 ); // Get terminating NULL CRC = CalcCRC(KissMsg + 1, MsgLen + 3); sprintf(crcstring, "%04X%c", CRC, 4); strcat(KissMsg, crcstring); MsgLen += 9; } else { // Normal KISS KissMsg[0] = 0; // KISS Control KissMsg[1] = TNC->ARQInfo->FarStream; memcpy(&KissMsg[2], Msg, MsgLen); MsgLen += 2; } newlen = KissEncode(KissMsg, outbuff, MsgLen); sendto(TNC->TCPDataSock, outbuff, newlen, 0, (struct sockaddr *)&TNC->Datadestaddr, sizeof(struct sockaddr)); SendKISSCommand(TNC, "TXBUF:"); } else { // ARQ Scoket // Add Header, CRC and Send unsigned short CRC; char crcstring[6]; char outbuff[1000]; outbuff[0] = 1; // SOH outbuff[1] = '0'; // Version outbuff[2] = TNC->ARQInfo->FarStream; Msg[MsgLen] = 0; memcpy(&outbuff[3], Msg, MsgLen + 1); CRC = CalcCRC(outbuff , MsgLen + 3); sprintf(crcstring, "%04X%c", CRC, 4); strcat(outbuff, crcstring); MsgLen += 8; send(TNC->TCPDataSock, outbuff, MsgLen, 0); } } VOID ProcessFLDigiData(struct TNCINFO * TNC, UCHAR * Input, int Len, char Channel, BOOL RAW); static int ProcessReceivedData(int port) { int bytes, used, bytesleft; int i; char ErrMsg[255]; unsigned char MessageBuff[1500]; unsigned char * Message = MessageBuff; unsigned char * MessageBase = MessageBuff; struct TNCINFO * TNC = TNCInfo[port]; struct FLINFO * FL = TNC->FLInfo; struct STREAMINFO * STREAM = &TNC->Streams[0]; // If using KISS/UDP interface use recvfrom if (FL->KISSMODE) { struct sockaddr_in rxaddr; int addrlen = sizeof(struct sockaddr_in); unsigned char * KissEnd; bytesleft = recvfrom(TNC->TCPDataSock, Message, 1500, 0, (struct sockaddr *)&rxaddr, &addrlen); if (bytesleft < 0) { int err = WSAGetLastError(); // if (err != 11) // printf("KISS Error %d %d\n", nLength, err); bytes = 0; } while (bytesleft > 0) { unsigned char * in; unsigned char * out; unsigned char c; if (bytesleft < 3) return 0; if (Message[0] != FEND) return 0; // Duff Message = MessageBase; in = out = &Message[2]; // We may have more than one KISS message in a packet KissEnd = memchr(&Message[2], FEND, bytesleft ); if (KissEnd == 0) return 0; // Duff *(KissEnd) = 0; used = (int)(KissEnd - Message + 1); bytesleft -= used; bytes = used; MessageBase += used; if (Message[1] == 6) // KISS Command { UCHAR * ptr = strchr(&Message[2], FEND); if (ptr) *ptr = 0; // Null Terminate if (bytes > 250) Message[250] = 0; FL->Responding = 5; if (TNC->TNCOK == 0) { TNC->TNCOK = TRUE; TNC->CONNECTED = TRUE; sprintf(TNC->WEB_COMMSSTATE, "Connected to FLDIGI"); SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); } // Trap BUSY fiest - there are lots of them, and they are likely to be confused // with tesponses to Interactive commands if (memcmp(&Message[2], "BUSY", 4) == 0) { BOOL Changed = FALSE; if (Message[7] == 'T' && FL->Busy == FALSE) { TNC->Busy = FL->Busy = TRUE; Changed = TRUE; } else { if (Message[7] == 'F' && FL->Busy == TRUE) { TNC->Busy = FL->Busy = FALSE; Changed = TRUE; } } if (Changed) { if (FL->TX) strcpy(TNC->WEB_CHANSTATE, "TX"); else if (FL->Busy) strcpy(TNC->WEB_CHANSTATE, "Busy"); else strcpy(TNC->WEB_CHANSTATE, "Idle"); SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE); } continue; } if (TNC->InternalCmd) { PMSGWITHLEN buffptr = GetBuff(); TNC->InternalCmd = FALSE; if (buffptr) { buffptr->Len = sprintf(buffptr->Data, "FLDIGI} Ok %s\r", &Message[2]); C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); } // Drop through in case need to extract info from command } // Auto Command // Debugprintf("%d %s", TNC->PortRecord->PORTCONTROL.PORTNUMBER, &Message[2]); if (memcmp(&Message[2], "FLSTAT", 4) == 0) { if (strstr(&Message[2], "FLSTAT:INIT")) { // FLDIGI Reloaded - set parmas SendKISSCommand(TNC, "RSIDBCAST:ON TRXSBCAST:ON TXBEBCAST:ON KISSRAW:ON"); } continue; } if (memcmp(&Message[2], "TRXS", 4) == 0) { char * ptr1, * context; BOOL Changed = FALSE; ptr1 = strtok_s(&Message[7], ",", &context); if (strstr(ptr1, "TX")) { if (TNC->FLInfo->TX == FALSE) { TNC->FLInfo->TX = TRUE; Changed = TRUE; } } else { if (TNC->FLInfo->TX) { TNC->FLInfo->TX = FALSE; Changed = TRUE; } } if (Changed) { if (FL->TX) strcpy(TNC->WEB_CHANSTATE, "TX"); else if (FL->Busy) strcpy(TNC->WEB_CHANSTATE, "Busy"); else strcpy(TNC->WEB_CHANSTATE, "Idle"); SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE); } continue; } if (memcmp(&Message[2], "TXBUF:", 6) == 0) { char * ptr1, * context; ptr1 = strtok_s(&Message[8], ",", &context); STREAM->BytesOutstanding = atoi(ptr1); UpdateStatsLine(TNC, STREAM); continue; } if (memcmp(&Message[2], "TXBE:", 5) == 0) { STREAM->BytesOutstanding = 0; UpdateStatsLine(TNC, STREAM); continue; } if (memcmp(&Message[2], "RSIDN:", 6) == 0) { char * ptr1, * context; ptr1 = strtok_s(&Message[8], ",", &context); TNC->FLInfo->CenterFreq = atoi(ptr1); ptr1 = strtok_s(NULL, ",", &context); if (strlen(ptr1) > 19) ptr1[19] = 0; strcpy(TNC->FLInfo->CurrentMode, ptr1); TNC->ConnectPending = 3; // Lock Scan for 3 } if (memcmp(&Message[2], "MODEM:", 6) == 0) { char * ptr1, * context; ptr1 = strtok_s(&Message[8], ",", &context); if (strlen(ptr1) > 19) ptr1[19] = 0; strcpy(TNC->FLInfo->CurrentMode, ptr1); } if (memcmp(&Message[2], "WFF:", 4) == 0) { char * ptr1, * context; ptr1 = strtok_s(&Message[6], ",", &context); TNC->FLInfo->CenterFreq = atoi(ptr1); } sprintf(TNC->WEB_MODE, "%s/%d", TNC->FLInfo->CurrentMode, TNC->FLInfo->CenterFreq); SetWindowText(TNC->xIDC_MODE, TNC->WEB_MODE); continue; } if (Message[1] == 7) // Not Normal Data { // "RAW" Mode. Just process as if received from TCP Socket Interface // Debugprintf("7 %d %s", TNC->PortRecord->PORTCONTROL.PORTNUMBER, &Message[2]); ProcessFLDigiPacket(TNC, &Message[2] , bytes - 3); // Data may be for another port continue; } bytes -= 3; // Two FEND and Control // Debugprintf("0 %d %s", TNC->PortRecord->PORTCONTROL.PORTNUMBER, &Message[2]); // Undo KISS while (bytes) { bytes--; c = *(in++); if (c == FESC) { c = *(in++); bytes--; if (c == TFESC) c = FESC; else if (c == TFEND) c = FEND; } *(out++) = c; } ProcessFLDigiData(TNC, &Message[3], (int)(out - &Message[3]), Message[2], FALSE); // KISS not RAW } return 0; } // Need to extract messages from byte stream bytes = recv(TNC->TCPDataSock, Message, 500, 0); if (bytes == SOCKET_ERROR) { // i=sprintf(ErrMsg, "Read Failed for MPSK socket - error code = %d\r\n", WSAGetLastError()); // WritetoConsole(ErrMsg); closesocket(TNC->TCPDataSock); TNC->CONNECTED = FALSE; if (TNC->Streams[0].Attached) TNC->Streams[0].ReportDISC = TRUE; return (0); } if (bytes == 0) { // zero bytes means connection closed i=sprintf(ErrMsg, "FlDigi Connection closed for BPQ Port %d\n", port); WritetoConsole(ErrMsg); TNC->CONNECTED = FALSE; if (TNC->Streams[0].Attached) TNC->Streams[0].ReportDISC = TRUE; return (0); } // Have some data ProcessFLDigiPacket(TNC, Message, bytes); // Data may be for another port return (0); } VOID ProcessFLDigiPacket(struct TNCINFO * TNC, char * Message, int Len) { char * MPTR = Message; char c; struct FLINFO * FL = TNC->FLInfo; if (TNC->FLInfo->MCASTMODE) { if (TNC->Streams[0].Attached == 0) return; while(Len) { c = *(MPTR++); if (TNC->InPacket) { TNC->DataBuffer[TNC->DataLen++] = c; // Sanity Check if (TNC->DataLen == 6) { char * ptr = &TNC->DataBuffer[1]; if (memcmp(ptr, "DATA ", 5) == 0 || memcmp(ptr, "PROG ", 5) == 0 || memcmp(ptr, "FILE ", 5) == 0 || memcmp(ptr, "SIZE ", 5) == 0 || memcmp(ptr, "DESC ", 5) == 0 || memcmp(ptr, "CNTL ", 5) == 0 || memcmp(ptr, "ID ", 3) == 0) { } else { // False Trigger, try again TNC->InPacket = FALSE; } } else { if (TNC->InData) { if (--TNC->MCASTLen == 0) { // Got a packet PMSGWITHLEN buffptr; int Stream = 0; struct STREAMINFO * STREAM = &TNC->Streams[0]; buffptr = GetBuff(); if (buffptr) { TNC->DataBuffer[TNC->DataLen++] = 13; // Keep Tidy buffptr->Len = TNC->DataLen; memcpy(&buffptr[2], &TNC->DataBuffer[0], TNC->DataLen); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } TNC->InPacket = FALSE; } } else { // Looking for > if (TNC->DataLen == 16) { // Not found it TNC->InPacket = FALSE; } else { if (c == '>') { // Got Header - extract Length char * ptr; int len; ptr = strchr(TNC->DataBuffer, ' '); if (ptr) { len = atoi(ptr); if (len) { TNC->InData = TRUE; TNC->MCASTLen = len; } } } } } } if (TNC->DataLen > 520) TNC->DataLen--; // Protect Buffer } else { // Look for '<' if (c == '<') { TNC->DataBuffer[0] = c; TNC->DataLen = 1; TNC->InPacket = TRUE; TNC->InData = FALSE; } } Len--; } return; } // Look for SOH/EOT delimiters. May Have several SOH before EOTTNC->FL while(Len) { c = *(MPTR++); switch (c) { case 01: // New Packet if (TNC->InPacket) CheckFLDigiData(TNC); TNC->DataBuffer[0] = 1; TNC->DataLen = 1; TNC->InPacket = TRUE; break; case 04: if (TNC->InPacket) CheckFLDigiData(TNC); TNC->DataLen = 0; TNC->InPacket = FALSE; break; default: if (TNC->InPacket) { if (TNC->DataLen == 1) { if (c != '0' && c != '1') { // Drop if not Protocol '0' or '1' - this should eliminate almost all noise packets TNC->InPacket = 0; break; } } TNC->DataBuffer[TNC->DataLen++] = c; } if (TNC->DataLen > 520) TNC->DataLen--; // Protect Buffer } Len--; } } VOID CheckFLDigiData(struct TNCINFO * TNC) { UCHAR * Input = &TNC->DataBuffer[0]; int Len = TNC->DataLen - 4; // Not including CRC unsigned short CRC; char crcstring[6]; if (Len < 0) return; TNC->DataBuffer[TNC->DataLen] = 0; // RAW format message, either from ARQ Scoket or RAW KISS // Check Checksum CRC = CalcCRC(Input , Len); sprintf(crcstring, "%04X", CRC); if (memcmp(&Input[Len], crcstring, 4) !=0) { // CRC Error - could just be noise // Debugprintf("%s %s", crcstring, Input); return; } ProcessFLDigiData(TNC, &Input[3], Len - 3, Input[2], TRUE); // From RAW } /* VOID ProcessARQPacket(struct PORTCONTROL * PORT, MESSAGE * Buffer) { // ARQ Packet from KISS-Like Hardware struct TNCINFO * TNC = TNCInfo[PORT->PORTNUMBER]; UCHAR * Input; int Len; if (TNC == NULL) { // Set up TNC info TNC = TNCInfo[PORT->PORTNUMBER] = zalloc(sizeof(struct TNCINFO)); TNC->ARQInfo = zalloc(sizeof(struct ARQINFO)); TNC->FLInfo = zalloc(sizeof(struct FLINFO)); TNC->Timeout = 50; // Default retry = 10 seconds TNC->Retries = 6; // Default Retries TNC->Window = 16; } Input = &Buffer->DEST[0]; Len = Buffer->LENGTH - 7; // Not including CRC // Look for attach on any call ProcessFLDigiData(TNC, Input, Len); } */ static int Stuff(UCHAR * inbuff, UCHAR * outbuff, int len) { int i, txptr = 0; UCHAR c; UCHAR * ptr = inbuff; // DLE Escape DLE, SOH, EOT for (i = 0; i < len; i++) { c = *(ptr++); // if (c == 0 || c == DLE || c == SOH || c == EOT) if (c < 32 && c != 10 && c != 13 && c != 8) { outbuff[txptr++] = DLE; // if between 0 and 0x1F, Add 40, // if > x80 and less than 0xa0 subtract 20 c += 0x40; } outbuff[txptr++]=c; } return txptr; } static int UnStuff(UCHAR * inbuff, int len) { int i, txptr = 0; UCHAR c; UCHAR * outbuff = inbuff; UCHAR * ptr = inbuff; // This unstuffs into the input buffer for (i = 0; i < len; i++) { c = *(ptr++); if (c == DLE) { c = *(ptr++); i++; // if between 0x40 and 0x5F, subtract 0x40, // else add 0x20 (so we can send chars 80-9f without a double DLE) if (c < 0x60) c -= 0x40; else c += 0x20; } outbuff[txptr++] = c; } return txptr; } unsigned int crcval = 0xFFFF; void update(char c) { int i; crcval ^= c & 255; for (i = 0; i < 8; ++i) { if (crcval & 1) crcval = (crcval >> 1) ^ 0xA001; else crcval = (crcval >> 1); } } unsigned int CalcCRC(UCHAR * ptr, int Len) { int i; crcval = 0xFFFF; for (i = 0; i < Len; i++) { update(*ptr++); } return crcval; } /* 00cG8BPQ:1025 G8BPQ:24 0 8 T60R6W108E06 00kG8BPQ:24 G8BPQ 4 85F9B 00cG8BPQ:1025 GM8BPQ:24 0 7 T60R5W1051D5 (128, 5) ,00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36 00kG8BPQ:24 G8BPQ 5 89FCA First no sees to be a connection counter. Next may be stream 08s___ABFC 08tG8BPQ:73 xxx 33FA 00tG8BPQ:73 yyy 99A3 08dG8BPQ:90986C 00bG8BPQ:911207 call:90 for dis 91 for dis ack 73 for chat) 08pG8BPQ?__645E 00s_??4235 08pG8BPQ?__645E 00s_??4235 i Ident c Connect k Connect Ack r Connect NAK d Disconnect req s Data Ack/ Retransmit Req )status) p Poll f Format Fail b dis ack t talk a Abort o Abort ACK 00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36 00kG8BPQ:24 G8BPQ 6 49A3A 08s___ABFC 08 ARQ:FILE::flarqmail-1.eml ARQ:EMAIL:: ARQ:SIZE::90 ARQ::STX //FLARQ COMPOSER Date: 09/01/2014 23:24:42 To: gm8bpq From: SubjectA0E0 08!: Test Test Message ARQ::ETX F0F2 08pG8BPQ!__623E 08pG8BPQ!__623E 08pG8BPQ!__623E */ VOID ProcessFLDigiData(struct TNCINFO * TNC, UCHAR * Input, int Len, char Channel, BOOL RAW) { PMSGWITHLEN buffptr; int Stream = 0; struct STREAMINFO * STREAM = &TNC->Streams[0]; char CTRL = Input[0]; struct ARQINFO * ARQ = TNC->ARQInfo; struct FLINFO * FL = TNC->FLInfo; int SendLen; char Reply[80]; // Process Message // This processes eitrher message from the KISS or RAW interfaces. // Headers and RAW checksum have been removed, so packet starts with Control Byte // Only a connect request is allowed with no session, so check first if (CTRL == 'c') { // Connect Request char * call1; char * call2; char * port1; char * port2; char * ptr; char * context; char FarStream = 0; int BlockSize = 6; // 64 default int Window = TNC->Window; APPLCALLS * APPL; char * ApplPtr = APPLS; int App; char Appl[10]; struct WL2KInfo * WL2K = TNC->WL2K; TRANSPORTENTRY * SESS; TNC->ConnectPending = 0; if (FL->CONOK == FALSE) return; call1 = strtok_s(&Input[1], " ", &context); call2 = strtok_s(NULL, " ", &context); port1 = strlop(call1, ':'); port2 = strlop(call2, ':'); // See if for us for (App = 0; App < 32; App++) { APPL=&APPLCALLTABLE[App]; memcpy(Appl, APPL->APPLCALL_TEXT, 10); ptr=strchr(Appl, ' '); if (ptr) *ptr = 0; if (_stricmp(call2, Appl) == 0) break; } if (App > 31) if (strcmp(TNC->NodeCall, call2) !=0) return; // Not Appl or Port/Node Call ptr = strtok_s(NULL, " ", &context); FarStream = *ptr; ptr = strtok_s(NULL, " ", &context); BlockSize = atoi(ptr); if (ARQ->ARQState) { // We have already received a connect request - just ACK it goto AckConnectRequest; } // Get a Session SuspendOtherPorts(TNC); ProcessIncommingConnect(TNC, call1, 0, TRUE); SESS = TNC->PortRecord->ATTACHEDSESSIONS[0]; strcpy(STREAM->MyCall, call2); STREAM->ConnectTime = time(NULL); STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = STREAM->BytesResent = 0; if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT")) { sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, call2, TNC->RIG->Valchar); SESS->Frequency = (atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq SESS->Mode = TNC->WL2KMode; } else { sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, call2); if (WL2K) { SESS->Frequency = WL2K->Freq; SESS->Mode = WL2K->mode; } } if (WL2K) strcpy(SESS->RMSCall, WL2K->RMSCall); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); strcpy(TNC->WEB_PROTOSTATE, "Connect Pending"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); memset(ARQ, 0, sizeof(struct ARQINFO)); // Reset ARQ State ARQ->FarStream = FarStream; ARQ->TXSeq = ARQ->TXLastACK = 63; // Last Sent ARQ->RXHighest = ARQ->RXNoGaps = 63; // Last Received ARQ->ARQState = ARQ_ACTIVE; ARQ->OurStream = (rand() % 78) + 49; // To give some protection against other stuff on channel ARQ->FarStream = FarStream; // Not Yet defined if (strcmp(port1, "1025") == 0) { FL->FLARQ = TRUE; // From FLARQ ARQ->OurStream = '8'; // FLARQ Ignores what we send } else FL->FLARQ = FALSE; // From other app (eg BPQ) FL->RAW = RAW; STREAM->NeedDisc = 0; if (App < 32) { char AppName[13]; memcpy(AppName, &ApplPtr[App * sizeof(CMDX)], 12); AppName[12] = 0; // Make sure app is available if (CheckAppl(TNC, AppName)) { char Buffer[32]; int MsgLen = sprintf(Buffer, "%s\r", AppName); buffptr = GetBuff(); if (buffptr == 0) { return; // No buffers, so ignore } buffptr->Len = MsgLen; memcpy(buffptr->Data, Buffer, MsgLen); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); TNC->SwallowSignon = TRUE; // Save Appl Call in case needed for } else { STREAM->NeedDisc = 50; // 1 sec } } ARQ->TXWindow = Window; if (BlockSize < 4) BlockSize = 4; if (BlockSize < 9) BlockSize = 9; ARQ->MaxBlock = Blocksizes[BlockSize]; ARQ->ARQTimer = 10; // To force CTEXT to be Queued if (STREAM->NeedDisc) { // Send Not Avail buffptr = GetBuff(); if (buffptr) { buffptr->Len = sprintf(buffptr->Data, "Application Not Available\n"); SendARQData(TNC, buffptr); } } AckConnectRequest: SendLen = sprintf(Reply, "k%s:24 %s %c 7", call2, call1, ARQ->OurStream); SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); ARQ->ARQTimerState = ARQ_CONNECTACK; return; } // All others need a session // if (!STREAM->Connected && !STREAM->Connecting) // return; if (CTRL == 'k') { // Connect ACK char * call1; char * call2; char * port1; char * port2; char * ptr; char * context; char FarStream = 0; int BlockSize = 6; // 64 default int Window = 16; char Reply[80]; int ReplyLen; call1 = strtok_s(&Input[1], " ", &context); call2 = strtok_s(NULL, " ", &context); port1 = strlop(call1, ':'); port2 = strlop(call2, ':'); if (strcmp(call1, STREAM->RemoteCall) != 0) return; if (Channel != ARQ->OurStream) return; // Wrong Session ptr = strtok_s(NULL, " ", &context); if (ptr) FarStream = *ptr; ptr = strtok_s(NULL, " ", &context); if (ptr) BlockSize = atoi(ptr); if (STREAM->Connected) goto SendKReply; // Repeated ACK STREAM->ConnectTime = time(NULL); STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = STREAM->BytesResent = 0; STREAM->Connected = TRUE; ARQ->ARQTimerState = 0; ARQ->ARQTimer = 0; if (TNC->RIG) sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", STREAM->MyCall, STREAM->RemoteCall, TNC->RIG->Valchar); else sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", STREAM->MyCall, STREAM->RemoteCall); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); UpdateMH(TNC, STREAM->RemoteCall, '+', 'Z'); ARQ->ARQTimerState = 0; ARQ->FarStream = FarStream; ARQ->TXWindow = TNC->Window; ARQ->MaxBlock = Blocksizes[BlockSize]; ARQ->ARQState = ARQ_ACTIVE; STREAM->NeedDisc = 0; buffptr = GetBuff(); if (buffptr) { ReplyLen = sprintf(Reply, "*** Connected to %s\r", STREAM->RemoteCall); buffptr->Len = ReplyLen; memcpy(buffptr->Data, Reply, ReplyLen); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); SendKReply: // Reply with status SendLen = sprintf(Reply, "s%c%c%c", ARQ->TXSeq + 32, ARQ->RXNoGaps + 32, ARQ->RXHighest + 32); if (ARQ->RXHighest != ARQ->RXNoGaps) { int n = ARQ->RXNoGaps + 1; n &= 63; while (n != ARQ->RXHighest) { if (ARQ->RXHOLDQ[n] == 0) // Dont have it SendLen += sprintf(&Reply[SendLen], "%c", n + 32); n++; n &= 63; } } QueueAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); return; } // All others need a session //if (!STREAM->Connected) // return; if (CTRL == 's') { // Status if (Channel != ARQ->OurStream) return; // Wrong Session ARQ->ARQTimer = 0; // Stop retry timer Input[Len] = 0; ProcessARQStatus(TNC, ARQ, &Input[1]); return; } if (CTRL == 'p') { // Poll char * call1; char * context; call1 = strtok_s(&Input[1], " \x1A", &context); if (strcmp(call1, STREAM->RemoteCall) != 0) return; if (Channel != ARQ->OurStream) return; // Wrong Session SendLen = sprintf(Reply, "s%c%c%c", ARQ->TXSeq + 32, ARQ->RXNoGaps + 32, ARQ->RXHighest + 32); if (ARQ->RXHighest != ARQ->RXNoGaps) { int n = ARQ->RXNoGaps + 1; n &= 63; while (n != ARQ->RXHighest) { if (ARQ->RXHOLDQ[n] == 0) // Dont have it SendLen += sprintf(&Reply[SendLen], "%c", n + 32); n++; n &= 63; } } else ARQ->TurnroundTimer = 15; // Allow us to send it all acked QueueAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); return; } if (CTRL == 'a') { // Abort. Send Abort ACK - same as char * call1; char * context; call1 = strtok_s(&Input[1], " :", &context); if (strcmp(call1, STREAM->RemoteCall) != 0) return; if (Channel != ARQ->OurStream) return; // Wrong Session SendLen = sprintf(Reply, "o%c%c%c", ARQ->TXSeq + 32, ARQ->RXNoGaps + 32, ARQ->RXHighest + 32); if (ARQ->RXHighest != ARQ->RXNoGaps) { int n = ARQ->RXNoGaps + 1; n &= 63; while (n != ARQ->RXHighest) { if (ARQ->RXHOLDQ[n] == 0) // Dont have it SendLen += sprintf(&Reply[SendLen], "%c", n + 32); n++; n &= 63; } } QueueAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); return; } if (CTRL == 'i') { // Ident return; } if (CTRL == 't') { // Talk - pass to node char * call1; char * context; char * ptr; PMSGWITHLEN buffptr; Input[Len] = 0; // Removes checksum call1 = strtok_s(&Input[1], " ", &context); strlop(call1, ':'); if (strcmp(STREAM->RemoteCall, call1)) return; if (Channel != ARQ->OurStream) return; // Wrong Session buffptr = (PMSGWITHLEN)GetBuff(); if (buffptr == 0) return; // No buffers, so ignore while (ptr = strchr(context, 10)) *ptr = 13; buffptr->Len = strlen(context); strcpy(buffptr->Data, context); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); return; } if (CTRL == 'd') { // Disconnect Request char * call1; char * context; call1 = strtok_s(&Input[1], " ", &context); strlop(call1, ':'); if (strcmp(STREAM->RemoteCall, call1)) return; if (Channel != ARQ->OurStream) return; // Wrong Session // As the Disc ACK isn't repeated, we have to clear session now STREAM->Connected = FALSE; STREAM->Connecting = FALSE; STREAM->ReportDISC = TRUE; strcpy(TNC->WEB_PROTOSTATE, "Disconnected"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); ARQ->ARQState = 0; SendLen = sprintf(Reply, "b%s:91", STREAM->MyCall); ARQ->ARQTimerState = ARQ_WAITACK; SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); ARQ->Retries = 2; return; } if (CTRL == 'b') { // Disconnect ACK char * call1; char * context; call1 = strtok_s(&Input[1], " ", &context); strlop(call1, ':'); if (strcmp(STREAM->RemoteCall, call1)) return; if (Channel != ARQ->OurStream) return; // Wrong Session ARQ->ARQTimer = 0; ARQ->ARQTimerState = 0; ARQ->ARQState = 0; if (STREAM->Connected) { // Create a traffic record char logmsg[120]; time_t Duration; Duration = time(NULL) - STREAM->ConnectTime; if (Duration == 0) Duration = 1; sprintf(logmsg,"Port %2d %9s Bytes Sent %d BPS %d Bytes Received %d BPS %d Time %d Seconds", TNC->Port, STREAM->RemoteCall, STREAM->BytesTXed, (int)(STREAM->BytesTXed/Duration), STREAM->BytesRXed, (int)(STREAM->BytesRXed/Duration), (int)Duration); Debugprintf(logmsg); } STREAM->Connecting = FALSE; STREAM->Connected = FALSE; // Back to Command Mode STREAM->ReportDISC = TRUE; // Tell Node if (STREAM->Disconnecting) // FLReleaseTNC(TNC); STREAM->Disconnecting = FALSE; strcpy(TNC->WEB_PROTOSTATE, "Disconnected"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); return; } if (CTRL == 'u') { // Beacon //>00uGM8BPQ:72 GM8BPQ TestingAD67 char * Call = &Input[1]; strlop(Call, ':'); UpdateMH(TNC, Call, '!', 0); return; } if (STREAM->Connected) { if (Channel != ARQ->OurStream) return; // Wrong Session if (CTRL >= ' ' && CTRL < 96) { // ARQ Data int Seq = CTRL - 32; int Work; // if (rand() % 5 == 2) // { // Debugprintf("Dropping %d", Seq); // return; // } buffptr = GetBuff(); if (buffptr == NULL) return; // Should never run out, but cant do much else // Remove any DLE transparency if (TNC->FLInfo->KISSMODE) Len -= 1; else Len = UnStuff(&Input[1], Len - 1); buffptr->Len = Len; memcpy(buffptr->Data, &Input[1], Len); STREAM->BytesRXed += Len; UpdateStatsLine(TNC, STREAM); // Safest always to save, then see what we can process if (ARQ->RXHOLDQ[Seq]) { // Wot! Shouldn't happen ReleaseBuffer(ARQ->RXHOLDQ[Seq]); // Debugprintf("ARQ Seq %d Duplicate"); } ARQ->RXHOLDQ[Seq] = buffptr; // Debugprintf("ARQ saving %d", Seq); // If this is higher that highest received, save. But beware of wrap' // Hi = 2, Seq = 60 dont save s=h = 58 // Hi = 10 Seq = 12 save s-h = 2 // Hi = 14 Seq = 10 dont save s-h = -4 // Hi = 60 Seq = 2 save s-h = -58 Work = Seq - ARQ->RXHighest; if ((Work > 0 && Work < 32) || Work < -32) ARQ->RXHighest = Seq; // We may now be able to process some Work = (ARQ->RXNoGaps + 1) & 63; // The next one we need while (ARQ->RXHOLDQ[Work]) { // We have it C_Q_ADD(&STREAM->PACTORtoBPQ_Q, ARQ->RXHOLDQ[Work]); ARQ->RXHOLDQ[Work] = NULL; // Debugprintf("Processing %d from Q", Work); ARQ->RXNoGaps = Work; Work = (Work + 1) & 63; // The next one we need } ARQ->TurnroundTimer = 200; // Delay before allowing reply. Will normally be reset by the poll following data return; } } } VOID SendARQData(struct TNCINFO * TNC, PMSGWITHLEN Buffer) { // Send Data, saving a copy until acked. struct ARQINFO * ARQ = TNC->ARQInfo; struct FLINFO * FL = TNC->FLInfo; struct STREAMINFO * STREAM = &TNC->Streams[0]; UCHAR TXBuffer[300]; SOCKET sock = TNC->TCPDataSock; int SendLen; UCHAR * ptr; int Origlen = Buffer->Len; int Stuffedlen; ARQ->TXSeq++; ARQ->TXSeq &= 63; SendLen = sprintf(TXBuffer, "%c", ARQ->TXSeq + 32); ptr = (UCHAR *)&Buffer->Data; // Start of data; ptr[Buffer->Len] = 0; if (memcmp(ptr, "ARQ:", 4) == 0) { // FLARQ Mail/FIle transfer. Turn off CR > LF translate (used for terminal mode) FL->FLARQ = FALSE; } if (FL->FLARQ) { // Terminal Mode. Need to convert CR to LF so it displays in FLARQ Window ptr = strchr(ptr, 13); while (ptr) { *(ptr++) = 10; // Replace CR with LF ptr = strchr(ptr, 13); } } if (TNC->FLInfo->KISSMODE) { memcpy(&TXBuffer[SendLen], (UCHAR *)&Buffer->Data, Origlen); SendLen += Origlen; } else { Stuffedlen = Stuff((UCHAR *)&Buffer->Data, &TXBuffer[SendLen], Origlen); SendLen += Stuffedlen; } TXBuffer[SendLen] = 0; // if (rand() % 5 == 2) // Debugprintf("Dropping %d", ARQ->TXSeq); // else ARQ->TXHOLDQ[ARQ->TXSeq] = Buffer; STREAM->BytesTXed += Origlen; UpdateStatsLine(TNC, STREAM); // if waiting for ack, don't send, just queue. Will be sent when ack received if (ARQ->ARQTimer == 0 || ARQ->ARQTimerState == ARQ_WAITDATA) { SendPacket(TNC, TXBuffer, SendLen); ARQ->ARQTimer = 15; // wait up to 1.5 sec for more data before polling ARQ->Retries = 1; ARQ->ARQTimerState = ARQ_WAITDATA; } else STREAM->BytesResent -= Origlen; // So wont be included in resent bytes } VOID TidyClose(struct TNCINFO * TNC, int Stream) { char Reply[80]; int SendLen; struct ARQINFO * ARQ = TNC->ARQInfo; SendLen = sprintf(Reply, "d%s:90", TNC->Streams[0].MyCall); SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); ARQ->ARQTimerState = ARQ_DISC; strcpy(TNC->WEB_PROTOSTATE, "Disconnecting"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); } VOID ForcedClose(struct TNCINFO * TNC, int Stream) { TidyClose(TNC, Stream); // I don't think Hostmode has a DD } VOID CloseComplete(struct TNCINFO * TNC, int Stream) { FLReleaseTNC(TNC); } VOID FLReleaseTNC(struct TNCINFO * TNC) { // Set mycall back to Node or Port Call, and Start Scanner UCHAR TXMsg[1000]; strcpy(TNC->WEB_TNCSTATE, "Free"); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); // if a default Modem is defined, select it if (TNC->FLInfo->DefaultMode[0]) { char txbuff[80]; if (TNC->FLInfo->KISSMODE) { sprintf(txbuff, "WFF:%d MODEM:%s MODEM: WFF:", TNC->FLInfo->DefaultFreq, TNC->FLInfo->DefaultMode); SendKISSCommand(TNC, txbuff); } else { SendXMLCommand(TNC, "modem.set_by_name", TNC->FLInfo->DefaultMode, 'S'); SendXMLCommand(TNC, "modem.set_carrier", (char *)TNC->FLInfo->DefaultFreq, 'I'); } } // Start Scanner sprintf(TXMsg, "%d SCANSTART 15", TNC->Port); Rig_Command( (TRANSPORTENTRY *) -1, TXMsg); ReleaseOtherPorts(TNC); } VOID QueueAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen) { // Queue to be sent after TXDELAY memcpy(ARQ->TXMsg, Msg, MsgLen + 1); ARQ->TXLen = MsgLen; ARQ->TXDelay = 15; // Try 1500 ms } VOID SaveAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen) { // Used for Messages that need a reply. Save, send and set timeout memcpy(ARQ->LastMsg, Msg, MsgLen + 1); // Include Null ARQ->LastLen = MsgLen; // Delay the send for a short while Just use the timeout code // SendPacket(sock, Msg, MsgLen, 0); ARQ->ARQTimer = 1; // Try 500 ms ARQ->Retries = TNC->Retries + 1; // First timout is rthe real send return; } VOID ARQTimer(struct TNCINFO * TNC) { struct ARQINFO * ARQ = TNC->ARQInfo; PMSGWITHLEN buffptr; struct STREAMINFO * STREAM = &TNC->Streams[0]; int SendLen; char Reply[80]; struct FLINFO * FL = TNC->FLInfo; //Send frames, unless held by TurnroundTimer or Window int Outstanding; // Use new BUSY: poll to detect busy state if (FL->TX == FALSE) if (TNC->FLInfo->KISSMODE) SendKISSCommand(TNC, "BUSY:"); // Send every poll for now - may need to optimize later /* // Use Received chars as a rough channel active indicator FL->BusyTimer++; if (FL->BusyTimer > 4) { FL->BusyTimer = 0; if (FL->BusyCounter > 2) // 2 chars in last .3 secs FL->Busy = TRUE; else FL->Busy = FALSE; if (FL->TX) strcpy(TNC->WEB_CHANSTATE, "TX"); else if (FL->Busy) strcpy(TNC->WEB_CHANSTATE, "Busy"); else strcpy(TNC->WEB_CHANSTATE, "Idle"); FL->BusyCounter = 0; SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE); } */ // TXDelay is used as a turn round delay for frames that don't have to be retried. It doesn't // need to check for busy (or anything else (I think!) if (ARQ->TXDelay) { ARQ->TXDelay--; if (ARQ->TXDelay) return; SendPacket(TNC, ARQ->TXMsg, ARQ->TXLen); } // if We are alredy sending (State = ARQ_WAITDATA) we should allow it to send more (and the Poll at end) if (ARQ->ARQTimerState == ARQ_WAITDATA) { while (STREAM->BPQtoPACTOR_Q) { Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&STREAM->BPQtoPACTOR_Q); // Save for Appl Level Queued Frames if (Outstanding > ARQ->TXWindow) break; buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q); SendARQData(TNC, buffptr); } ARQ->ARQTimer--; if (ARQ->ARQTimer > 0) return; // Timer Still Running // No more data available - send poll SendLen = sprintf(Reply, "p%s", TNC->Streams[0].MyCall); ARQ->ARQTimerState = ARQ_WAITACK; // This is one message that should not be queued so it is sent straiget after data // Debugprintf("Sending Poll"); memcpy(ARQ->LastMsg, Reply, SendLen + 1); ARQ->LastLen = SendLen; SendPacket(TNC, Reply, SendLen); ARQ->ARQTimer = TNC->Timeout; ARQ->Retries = TNC->Retries; strcpy(TNC->WEB_PROTOSTATE, "Wait ACK"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); return; } // TrunroundTimer is used to allow time for far end to revert to RX if (ARQ->TurnroundTimer && !FL->Busy) ARQ->TurnroundTimer--; if (ARQ->TurnroundTimer == 0) { while (STREAM->BPQtoPACTOR_Q) { if (ARQ->ARQState != ARQ_ACTIVE) break; if (ARQ->ARQTimerState == ARQ_CONNECTACK) break; Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&STREAM->BPQtoPACTOR_Q) + 1; // Make sure busy is reported to BBS if (Outstanding > ARQ->TXWindow) break; buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q); SendARQData(TNC, buffptr); } } if (ARQ->ARQTimer) { if (FL->TX || FL->Busy) { // Only decrement if running send poll timer if (ARQ->ARQTimerState != ARQ_WAITDATA) return; } ARQ->ARQTimer--; { if (ARQ->ARQTimer) return; // Timer Still Running } ARQ->Retries--; if (ARQ->Retries) { // Retry Current Message SendPacket(TNC, ARQ->LastMsg, ARQ->LastLen); ARQ->ARQTimer = TNC->Timeout + (rand() % 30); return; } // Retried out. switch (ARQ->ARQTimerState) { case ARQ_WAITDATA: // No more data available - send poll SendLen = sprintf(Reply, "p%s", TNC->Streams[0].MyCall); ARQ->ARQTimerState = ARQ_WAITACK; // This is one message that should not be queued so it is sent straiget after data memcpy(ARQ->LastMsg, Reply, SendLen + 1); ARQ->LastLen = SendLen; SendPacket(TNC, Reply, SendLen); ARQ->ARQTimer = TNC->Timeout; ARQ->Retries = TNC->Retries; strcpy(TNC->WEB_PROTOSTATE, "Wait ACK"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); return; case ARQ_CONNECTING: // Report Connect Failed, and drop back to command mode buffptr = GetBuff(); if (buffptr) { buffptr->Len = sprintf(buffptr->Data, "FLDigi} Failure with %s\r", STREAM->RemoteCall); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } // Send Disc to TNC in case it got the Connects, but we missed the ACKs TidyClose(TNC, 0); ARQ->Retries = 2; // First timout is the real send, only send once STREAM->Connecting = FALSE; // Back to Command Mode ARQ->ARQState = FALSE; break; case ARQ_WAITACK: case ARQ_CONNECTACK: case ARQ_DISC: STREAM->Connected = FALSE; // Back to Command Mode STREAM->ReportDISC = TRUE; ARQ->ARQState = FALSE; while (STREAM->PACTORtoBPQ_Q) ReleaseBuffer(Q_REM(&STREAM->PACTORtoBPQ_Q)); while (STREAM->BPQtoPACTOR_Q) ReleaseBuffer(Q_REM(&STREAM->BPQtoPACTOR_Q)); strcpy(TNC->WEB_TNCSTATE, "Free"); SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); strcpy(TNC->WEB_PROTOSTATE, "Disconncted"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); break; } } } VOID ProcessARQStatus(struct TNCINFO * TNC, struct ARQINFO * ARQ, char * Input) { // Release any acked frames and resend any outstanding int LastInSeq = Input[1] - 32; int LastRXed = Input[2] - 32; int FirstUnAcked = ARQ->TXLastACK; int n = (int)strlen(Input) - 3; char * ptr; int NexttoResend; int First, Last, Outstanding; PMSGWITHLEN Buffer; struct STREAMINFO * STREAM = &TNC->Streams[0]; int Acked = 0; // First status is an ack of Connect ACK if (ARQ->ARQTimerState == ARQ_CONNECTACK) { ARQ->Retries = 0; ARQ->ARQTimer = 0; ARQ->ARQTimerState = 0; strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); } // Release all up to LastInSeq while (FirstUnAcked != LastInSeq) { FirstUnAcked++; FirstUnAcked &= 63; Buffer = ARQ->TXHOLDQ[FirstUnAcked]; if (Buffer) { // Debugprintf("Acked %d", FirstUnAcked); STREAM->BytesAcked += Buffer->Len; ReleaseBuffer(Buffer); ARQ->TXHOLDQ[FirstUnAcked] = NULL; Acked++; } } ARQ->TXLastACK = FirstUnAcked; Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&STREAM->BPQtoPACTOR_Q); // Save for Appl Level Queued Frames if (FirstUnAcked == ARQ->TXSeq) { UpdateStatsLine(TNC, STREAM); ARQ->NoAckRetries = 0; strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE); return; // All Acked } // Release any not in retry list up to LastRXed. ptr = &Input[3]; while (n) { NexttoResend = *(ptr++) - 32; FirstUnAcked++; FirstUnAcked &= 63; while (FirstUnAcked != NexttoResend) { Buffer = ARQ->TXHOLDQ[FirstUnAcked]; if (Buffer) { // Debugprintf("Acked %d", FirstUnAcked); STREAM->BytesAcked += Buffer->Len; ReleaseBuffer(Buffer); ARQ->TXHOLDQ[FirstUnAcked] = NULL; Acked++; } FirstUnAcked++; FirstUnAcked &= 63; } // We don't ACK this one. Process any more resend values, then release up to LastRXed. n--; } // Release rest up to LastRXed while (FirstUnAcked != LastRXed) { FirstUnAcked++; FirstUnAcked &= 63; Buffer = ARQ->TXHOLDQ[FirstUnAcked]; if (Buffer) { // Debugprintf("Acked %d", FirstUnAcked); STREAM->BytesAcked += Buffer->Len; ReleaseBuffer(Buffer); ARQ->TXHOLDQ[FirstUnAcked] = NULL; Acked++; } } // Resend anything in TX Buffer (From LastACK to TXSeq Last = ARQ->TXSeq + 1; Last &= 63; First = LastInSeq; while (First != Last) { First++; First &= 63; if(ARQ->TXHOLDQ[First]) { PMSGWITHLEN Buffer = ARQ->TXHOLDQ[First]; UCHAR TXBuffer[300]; SOCKET sock = TNC->TCPDataSock; int SendLen; // Debugprintf("Resend %d", First); STREAM->BytesResent += Buffer->Len; SendLen = sprintf(TXBuffer, "%c", First + 32); if (TNC->FLInfo->KISSMODE) { memcpy(&TXBuffer[SendLen], (UCHAR *)&Buffer->Data, Buffer->Len); SendLen += Buffer->Len; } else SendLen += Stuff((UCHAR *)&Buffer->Data, &TXBuffer[SendLen], Buffer->Len); TXBuffer[SendLen] = 0; SendPacket(TNC, TXBuffer, SendLen); ARQ->ARQTimer = 10; // wait up to 1 sec for more data before polling ARQ->Retries = 1; ARQ->ARQTimerState = ARQ_WAITDATA; if (Acked == 0) { // Nothing acked by this statis message Acked = 0; // Dont count more thna once ARQ->NoAckRetries++; if (ARQ->NoAckRetries > TNC->Retries) { // Too many retries - just disconnect TidyClose(TNC, 0); return; } } } } UpdateStatsLine(TNC, STREAM); } VOID FLSlowTimer(struct TNCINFO * TNC) { struct FLINFO * FL = TNC->FLInfo; // Entered every 10 secs // if in MCAST mode, clear KILL timer (MCAST RX can run for a long time if (TNC->FLInfo->MCASTMODE) { TRANSPORTENTRY * SESS = TNC->PortRecord->ATTACHEDSESSIONS[0]; if (SESS) SESS->L4KILLTIMER = 0; } if (FL->KISSMODE) { if (FL->Responding) FL->Responding--; if (FL->Responding == 0) { TNC->TNCOK = FALSE; TNC->CONNECTED = FALSE; sprintf(TNC->WEB_COMMSSTATE, "Connection to FLDIGI lost"); SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); // Set basic params till it responds } FL->CmdControl++; if (FL->CmdControl > 5) // Every Minute { FL->CmdControl = 0; SendKISSCommand(TNC, "FLSTAT: MODEM: WFF:"); } SendKISSCommand(TNC, "TRXS: TXBUF:"); // In case TX/RX report is missed } } static int ProcessXMLData(int port) { unsigned int bytes; int i; char ErrMsg[255]; char Message[500]; struct TNCINFO * TNC = TNCInfo[port]; struct FLINFO * FL = TNC->FLInfo; char * ptr1, * ptr2, *ptr3; // Need to extract messages from byte stream bytes = recv(TNC->TCPSock,(char *)&Message, 500, 0); if (bytes == SOCKET_ERROR) { // i=sprintf(ErrMsg, "Read Failed for FLDigi socket - error code = %d\r\n", WSAGetLastError()); // WritetoConsole(ErrMsg); closesocket(TNC->TCPSock); TNC->CONNECTED = FALSE; if (TNC->Streams[0].Attached) TNC->Streams[0].ReportDISC = TRUE; return (0); } if (bytes == 0) { // zero bytes means connection closed i=sprintf(ErrMsg, "FlDigi Connection closed for BPQ Port %d\n", port); WritetoConsole(ErrMsg); TNC->CONNECTED = FALSE; if (TNC->Streams[0].Attached) TNC->Streams[0].ReportDISC = TRUE; return (0); } // Have some data. Assume for now we get a whole packet if (TNC->InternalCmd) { PMSGWITHLEN buffptr = GetBuff(); TNC->InternalCmd = FALSE; ptr1 = strstr(Message, ""); if (ptr1) { ptr1 += 7; ptr2 = strstr(ptr1, ""); if (ptr2) *ptr2 = 0; ptr3 = strstr(ptr1, ""); if (ptr3) { ptr1 = ptr3 + 4; ptr2 = strstr(ptr1, ""); if (ptr2) *ptr2 = 0; } if (buffptr) { buffptr->Len = sprintf(buffptr->Data, "FLDIGI} Ok Was %s\r", ptr1); C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); } } return 0; } ptr1 = strstr(Message, ""); if (ptr1) { ptr1 += 7; ptr2 = strstr(ptr1, ""); if (ptr2) *ptr2 = 0; ptr2 = strstr(ptr1, ""); if (ptr2) { ptr2 += 8; ptr1 = ptr2; ptr2 = strstr(ptr1, ""); if (ptr2) *ptr2 = 0; } if (strcmp(FL->LastXML, "modem.get_name") == 0) { strcpy(TNC->WEB_MODE, ptr1); SetWindowText(TNC->xIDC_MODE, ptr1); } else if (strcmp(FL->LastXML, "main.get_trx_state") == 0) { if (strcmp(ptr1, "TX") == 0) FL->TX = TRUE; else FL->TX = FALSE; if (FL->TX) strcpy(TNC->WEB_CHANSTATE, "TX"); else if (FL->Busy) strcpy(TNC->WEB_CHANSTATE, "Busy"); else strcpy(TNC->WEB_CHANSTATE, "Idle"); SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE); } else if (strcmp(FL->LastXML, "main.get_squelch") == 0) { /* if (_memicmp(Buffer, "BUSY TRUE", 9) == 0) { TNC->BusyFlags |= CDBusy; TNC->Busy = TNC->BusyHold * 10; // BusyHold delay SetWindowText(TNC->xIDC_CHANSTATE, "Busy"); strcpy(TNC->WEB_CHANSTATE, "Busy"); TNC->WinmorRestartCodecTimer = time(NULL); */ return 0; } /* if (_memicmp(Buffer, "BUSY FALSE", 10) == 0) { TNC->BusyFlags &= ~CDBusy; if (TNC->BusyHold) strcpy(TNC->WEB_CHANSTATE, "BusyHold"); else strcpy(TNC->WEB_CHANSTATE, "Clear"); SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE); TNC->WinmorRestartCodecTimer = time(NULL); return; } */ } return (0); } char MsgHddr[] = "POST /RPC2 HTTP/1.1\r\n" "User-Agent: XMLRPC++ 0.8\r\n" "Host: 127.0.0.1:7362\r\n" "Content-Type: text/xml\r\n" "Content-length: %d\r\n" "\r\n%s"; char Req[] = "\r\n" "%s\r\n" "%s" "\r\n"; VOID SendXMLCommand(struct TNCINFO * TNC, char * Command, char * Value, char ParamType) { int Len; char ReqBuf[512]; char SendBuff[512]; struct FLINFO * FL = TNC->FLInfo; struct ARQINFO * ARQ = TNC->ARQInfo; char ValueString[256] =""; if (!TNC->CONNECTED || TNC->FLInfo->KISSMODE) return; if (Value) if (ParamType == 'S') sprintf(ValueString, "%s", Value); else sprintf(ValueString, "%d", Value); strcpy(FL->LastXML, Command); Len = sprintf(ReqBuf, Req, FL->LastXML, ValueString); Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf); send(TNC->TCPSock, SendBuff, Len, 0); return; } VOID SendXMLPoll(struct TNCINFO * TNC) { int Len; char ReqBuf[256]; char SendBuff[256]; struct FLINFO * FL = TNC->FLInfo; struct ARQINFO * ARQ = TNC->ARQInfo; if (!TNC->CONNECTED) return; if (TNC->FLInfo->KISSMODE) return; if (ARQ->ARQTimer) { // if timer is running, poll fot TX State strcpy(FL->LastXML, "main.get_trx_state"); Len = sprintf(ReqBuf, Req, FL->LastXML, ""); Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf); send(TNC->TCPSock, SendBuff, Len, 0); return; } FL->XMLControl++; if (FL->XMLControl > 9) { FL->XMLControl = 0; strcpy(FL->LastXML, "modem.get_name"); } else { if (FL->XMLControl == 5) strcpy(FL->LastXML, "main.get_trx_state"); else return; } Len = sprintf(ReqBuf, Req, FL->LastXML, ""); Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf); send(TNC->TCPSock, SendBuff, Len, 0); } // sudo add-apt-repository ppa:kamalmostafa/fldigi