bool tagDataBlockReadSet::GetBufferFromByteArray(CGUID& guid) { long size = 0; GetBuff((uchar*)&size,1); if(size == 0) { guid = CGUID::GUID_INVALID; return false; } else { GetBuff((uchar*)&guid,sizeof(CGUID)); return true; } return true; }
char* tagDataBlockReadSet::GetStringFromByteArray(char* pStr, long lMaxLen) { if(lMaxLen <= 1) return NULL; long len = GetLongFromByteArray(); if(len < 0) len = 0; len = min(len,lMaxLen-1); GetBuff((uchar*)pStr,len); pStr[len] = '\0'; return pStr; }
void* tagDataBlockReadSet::GetBufferFromByteArray(void* pBuf, long lLen) { GetBuff((uchar*)pBuf,lLen); return pBuf; }
/* <SOH>00cG8BPQ:1025 G8BPQ:24 0 8 T60R6W108E06<EOT> <SOH>00kG8BPQ:24 G8BPQ 4 85F9B<EOT> <SOH>00cG8BPQ:1025 GM8BPQ:24 0 7 T60R5W1051D5<EOT> (128, 5) ,<SOH>00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36<EOT> <SOH>00kG8BPQ:24 G8BPQ 5 89FCA<EOT> First no sees to be a connection counter. Next may be stream <SOH>08s___ABFC<EOT> <SOH>08tG8BPQ:73 xxx 33FA<EOT> <SOH>00tG8BPQ:73 yyy 99A3<EOT> <SOH>08dG8BPQ:90986C<EOT> <SOH>00bG8BPQ:911207<EOT> call:90 for dis 91 for dis ack 73<sp> for chat) <SOH>08pG8BPQ<SUB>?__645E<EOT> <SOH>00s_??4235<EOT> <SOH>08pG8BPQ<SUB>?__645E<EOT> <SOH>00s_??4235<EOT> 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 <SOH>00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36<EOT> <SOH>00kG8BPQ:24 G8BPQ 6 49A3A<EOT> <SOH>08s___ABFC<EOT> <SOH>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<SOH> <SOH>08!: Test Test Message ARQ::ETX F0F2<SOH> <SOH>08pG8BPQ<SUB>!__623E<EOT> <SOH>08pG8BPQ<SUB>!__623E<EOT> <SOH>08pG8BPQ<SUB>!__623E<EOT> */ static VOID ProcessFLDigiData(struct TNCINFO * TNC, UCHAR * Input, int Len, int Stream) { UINT * buffptr; struct STREAMINFO * STREAM = &TNC->Streams[Stream]; char CTRL = Input[0]; struct ARQINFO * ARQ = STREAM->ARQInfo; char Channel = Stream + 64; int SendLen; char Reply[80]; Input[Len] = 0; // 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; if (Stream) return; // Shouldn't have Stream on Connect Request 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; memcpy(Appl, APPL->APPLALIAS_TEXT, 10); ptr=strchr(Appl, ' '); if (ptr) *ptr = 0; if (_stricmp(call2, Appl) == 0) break; } if (App > 31) if (strcmp(TNC->NodeCall, call2) !=0) if (strcmp(call2, MYALIASLOPPED) !=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 > ARQ_CONNECTING) { // We have already received a connect request - just ACK it goto AckConnectRequest; } // Get a Session Stream = 1; while(Stream <= MAXARQ) { if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0) goto GotStream; Stream++; } // No free streams - send Disconnect return; GotStream: STREAM = &TNC->Streams[Stream]; ProcessIncommingConnect(TNC, call1, Stream, FALSE); SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; strcpy(STREAM->MyCall, call2); STREAM->ConnectTime = time(NULL); STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = STREAM->BytesResent = 0; if (WL2K) strcpy(SESS->RMSCall, WL2K->RMSCall); ARQ = STREAM->ARQInfo; 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 = Stream + 64; 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[1] = MsgLen; memcpy(buffptr+2, 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 = 1; // To force CTEXT to be Queued if (App == 32) { // Connect to Node - send CTEXT if (HFCTEXTLEN > 1) { buffptr = GetBuff(); if (buffptr) { buffptr[1] = HFCTEXTLEN; memcpy(&buffptr[2], HFCTEXT, HFCTEXTLEN); SendARQData(TNC, buffptr, Stream); } } } if (STREAM->NeedDisc) { // Send Not Avail buffptr = GetBuff(); if (buffptr) { buffptr[1] = sprintf((char *)&buffptr[2], "Application Not Available\r"); SendARQData(TNC, buffptr, Stream); } } SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); SetWindowText(STREAM->xIDC_DESTCALL, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_STATUS, "ConPending"); SetWindowText(STREAM->xIDC_DIRN, "In"); AckConnectRequest: SendLen = sprintf(Reply, "k%s:24 %s %c 7", call2, call1, ARQ->OurStream); SaveAndSend(TNC, ARQ, TNC->WINMORDataSock, 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; sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", STREAM->MyCall, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); SetWindowText(STREAM->xIDC_DESTCALL, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_DIRN, "Out"); 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[1] = ReplyLen; memcpy(buffptr+2, Reply, ReplyLen); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(STREAM->xIDC_STATUS, "Connected"); 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->WINMORDataSock, 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, Stream, 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 Debugprintf("Sending Poll Resp TX NOGaps High %d %d %d", ARQ->TXSeq, ARQ->RXNoGaps, ARQ->RXHighest); 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->WINMORDataSock, 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->WINMORDataSock, Reply, SendLen); return; } if (CTRL == 'i') { // Ident return; } if (CTRL == 't') { // Talk - not sure what to do with these 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, "Disconncted"); SetWindowText(STREAM->xIDC_MYCALL, ""); SetWindowText(STREAM->xIDC_DESTCALL, ""); SetWindowText(STREAM->xIDC_DIRN, ""); SetWindowText(STREAM->xIDC_STATUS, ""); ARQ->ARQState = 0; SendLen = sprintf(Reply, "b%s:91", STREAM->MyCall); ARQ->ARQTimerState = ARQ_WAITACK; SaveAndSend(TNC, ARQ, TNC->WINMORDataSock, 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 STREAM->Disconnecting = FALSE; strcpy(TNC->WEB_PROTOSTATE, "Disconncted"); SetWindowText(STREAM->xIDC_MYCALL, ""); SetWindowText(STREAM->xIDC_DESTCALL, ""); SetWindowText(STREAM->xIDC_DIRN, ""); SetWindowText(STREAM->xIDC_STATUS, ""); 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; // Sould never run out, but cant do much else // Remove any DLE transparency Len -= 1; buffptr[1] = Len; memcpy(&buffptr[2], &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]); // ReleaseBuffer(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; } } }
static VOID ARQTimer(struct TNCINFO * TNC) { UINT * buffptr; struct STREAMINFO * STREAM; struct ARQINFO * ARQ; int SendLen; char Reply[80]; int Stream; //Send frames, unless held by TurnroundTimer or Window int Outstanding; for (Stream = 0; Stream <MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; ARQ = STREAM->ARQInfo; // 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) continue; SendPacket(TNC, STREAM, 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 + STREAM->BPQtoPACTOR_Q; // Save for Appl Level Queued Frames if (Outstanding >= ARQ->TXWindow) break; buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q); SendARQData(TNC, buffptr, Stream); } ARQ->ARQTimer--; if (ARQ->ARQTimer > 0) continue; // Timer Still Running // No more data available - send poll SendLen = sprintf(Reply, "p%s", STREAM->MyCall); ARQ->ARQTimerState = ARQ_WAITACK; // This is one message that should not be queued so it is sent straiget after data Debugprintf("Sending Poll After Data"); memcpy(ARQ->LastMsg, Reply, SendLen + 1); ARQ->LastLen = SendLen; SendPacket(TNC, STREAM, Reply, SendLen); ARQ->ARQTimer = TNC->Timeout; ARQ->Retries = TNC->Retries; strcpy(TNC->WEB_PROTOSTATE, "Wait ACK"); SetWindowText(STREAM->xIDC_STATUS, "Wait ACK"); continue; } // TrunroundTimer is used to allow time for far end to revert to RX if (ARQ->TurnroundTimer) ARQ->TurnroundTimer--; if (ARQ->TurnroundTimer == 0) { while (STREAM->BPQtoPACTOR_Q) { Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + 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, Stream); } } if (ARQ->ARQTimer) { // Only decrement if running send poll timer // if (ARQ->ARQTimerState != ARQ_WAITDATA) // return; ARQ->ARQTimer--; { if (ARQ->ARQTimer) continue; // Timer Still Running } ARQ->Retries--; if (ARQ->Retries) { // Retry Current Message SendPacket(TNC, STREAM, ARQ->LastMsg, ARQ->LastLen); ARQ->ARQTimer = TNC->Timeout + (rand() % 30); continue; } // Retried out. switch (ARQ->ARQTimerState) { case ARQ_WAITDATA: // No more data available - send poll SendLen = sprintf(Reply, "p%s", STREAM->MyCall); Debugprintf("Sending Poll After Timeout??"); 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, STREAM, Reply, SendLen); ARQ->ARQTimer = TNC->Timeout; ARQ->Retries = TNC->Retries; strcpy(TNC->WEB_PROTOSTATE, "Wait ACK"); SetWindowText(STREAM->xIDC_STATUS, "Wait ACK"); continue; case ARQ_CONNECTING: // Report Connect Failed, and drop back to command mode buffptr = GetBuff(); if (buffptr) { buffptr[1] = sprintf((UCHAR *)&buffptr[2], "UIARQ} 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, Stream); 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"); strcpy(TNC->WEB_PROTOSTATE, "Disconncted"); SetWindowText(STREAM->xIDC_MYCALL, ""); SetWindowText(STREAM->xIDC_DESTCALL, ""); SetWindowText(STREAM->xIDC_DIRN, ""); SetWindowText(STREAM->xIDC_STATUS, ""); break; } } } }
static int ExtProc(int fn, int port,unsigned char * buff) { UINT * buffptr; unsigned int txlen=0; struct TNCINFO * TNC = TNCInfo[port]; int Stream = 0; struct STREAMINFO * STREAM; if (TNC == NULL) return 0; // Port not defined // Look for attach on any call for (Stream = 0; Stream <= MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0) { // New Attach int calllen; STREAM->Attached = TRUE; calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall); STREAM->MyCall[calllen] = 0; STREAM->FramesOutstanding = 0; SetWindowText(STREAM->xIDC_STATUS, "Attached"); SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); } } switch (fn) { case 7: // 100 mS Timer. for (Stream = 0; Stream <= MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; if (STREAM->NeedDisc) { STREAM->NeedDisc--; if (STREAM->NeedDisc == 0) { // Send the DISCONNECT TidyClose(TNC, Stream); } } } ARQTimer(TNC); return 0; case 1: // poll // See if any frames for this port for (Stream = 0; Stream <= MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; if (STREAM->Attached) CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete); if (STREAM->ReportDISC) { STREAM->ReportDISC = FALSE; buff[4] = Stream; return -1; } 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=buffptr[1]; buff[4] = Stream; buff[7] = 0xf0; memcpy(&buff[8],buffptr+2,datalen); // Data goes to +7, but we have an extra byte datalen+=8; PutLengthinBuffer(buff, datalen); 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 && STREAM->Attached == FALSE) // Be sensible! { // >00uG8BPQ:72 TestA SendLen = sprintf(Reply, "u%s:72 %s", TNC->NodeCall, UIMsg); SendPacket(TNC, STREAM, Reply, SendLen); } ReleaseBuffer(buffptr); } return (0); case 2: // send Stream = buff[4]; STREAM = &TNC->Streams[Stream]; // txlen=(buff[6]<<8) + buff[5] - 8; txlen = GetLengthfromBuffer(buff) - 8; if (STREAM->Connected) { buffptr = GetBuff(); if (buffptr == 0) return (0); // No buffers, so ignore buffptr[1] = txlen; memcpy(buffptr+2, &buff[8], txlen); C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); return (0); } else { buff[8 + txlen] = 0; _strupr(&buff[8]); if (_memicmp(&buff[8], "D\r", 2) == 0) { if (STREAM->Connected) TidyClose(TNC, buff[4]); STREAM->ReportDISC = TRUE; // Tell Node return 0; } // See if a Connect Command. if (toupper(buff[8]) == 'C' && buff[9] == ' ' && txlen > 2) // Connect { char * ptr; char * context; struct ARQINFO * ARQ = STREAM->ARQInfo; int SendLen; char Reply[80]; _strupr(&buff[8]); buff[8 + txlen] = 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 = Stream + 64; ARQ->FarStream = 64; // Not yet defined memset(STREAM->RemoteCall, 0, 10); ptr = strtok_s(&buff[10], " ,\r", &context); strcpy(STREAM->RemoteCall, ptr); //<SOH>00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36<EOT> SendLen = sprintf(Reply, "c%s:42 %s:24 %c 7 T60R5W10", STREAM->MyCall, STREAM->RemoteCall, ARQ->OurStream); ARQ->ARQState = ARQ_ACTIVE; ARQ->ARQTimerState = ARQ_CONNECTING; SaveAndSend(TNC, ARQ, TNC->WINMORDataSock, Reply, SendLen); SetWindowText(STREAM->xIDC_STATUS, "Connecting"); SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); SetWindowText(STREAM->xIDC_DESTCALL, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_DIRN, "Out"); STREAM->Connecting = TRUE; return 0; } } return (0); case 3: Stream = (int)buff; STREAM = &TNC->Streams[Stream]; { // Busy if TX Window reached struct ARQINFO * ARQ = STREAM->ARQInfo; int Outstanding; 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) return (1 | 1 << 8 | STREAM->Disconnecting << 15); // 3rd Nibble is frames unacked else return 1 << 8 | STREAM->Disconnecting << 15; } return 1 << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting case 4: // reinit return (0); case 5: // Close return 0; } return 0; }
DllExport UINT APIENTRY SoundCardInterface(int CardNo, int Function, UINT Param1, UINT Param2) { UINT * buffptr; L1FRAME * rxf; switch (Function) { case INIT: SoundCardList[CardNo].PID = Param1; Debugprintf("SoundCard %d PID %d", CardNo, Param1); break; case CHECKCHAN: Debugprintf("CheckChan %d %d = %d", CardNo, Param1, SoundCardList[CardNo].Channellist[Param1].BPQPort); return SoundCardList[CardNo].Channellist[Param1].BPQPort; // Nonzero if port is configured case GETBUFFER: return (UINT)GetBuff(); case POLL: // See if anything on the TXQ SoundCardList[CardNo].State = Param1; // PTT and DCD State bits buffptr = Q_REM(&SoundCardList[CardNo].TXQ); if (buffptr) { memcpy((void *)Param2, buffptr, buffptr[1] + 12); ReleaseBuffer(buffptr); return 1; } return 0; case RXPACKET: // A received Packet. Param1 is buffer, Param2 the channel buffptr = GetBuff(); if (buffptr) { rxf = (L1FRAME *)Param1; buffptr[1] = rxf->len; memcpy(buffptr+2, rxf->frame, rxf->len); C_Q_ADD(&RXQ[SoundCardList[CardNo].Channellist[Param2].BPQPort], buffptr); } break; case CLOSING: SoundCardList[CardNo].ProcessMonitor = 250; // Restart in 5 secs break; } return 0; }
static int ExtProc(int fn, int port, unsigned char * buff) { int len = 0, txlen=0; struct CHANNELINFO * PORT = Portlist[port]; struct PORTCONTROL * PORTVEC = PORT->PORTVEC; struct SOUNDTNCINFO * TNC = PortToTNC[port]; int State = TNC->State; UINT * buffptr; switch (fn) { case 1: // poll TNC->ProcessMonitor++; if (TNC->ProcessMonitor > 300) { TNC->ProcessMonitor = 0; if (TNC->PID) { HANDLE hProc; hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TNC->PID); if (hProc) { DWORD ExitCode = 0; GetExitCodeProcess(hProc, &ExitCode); if (ExitCode != STILL_ACTIVE) RestartSoundTNC(TNC); CloseHandle(hProc); } } else RestartSoundTNC(TNC); } if (State & 0x20) PORTVEC->SENDING++; if (State & 0x10) PORTVEC->ACTIVE++; buffptr = Q_REM(&RXQ[port]); if (buffptr) { len = buffptr[1]; memcpy(&buff[7], &buffptr[2], len); len+=7; buff[5]=(len & 0xff); buff[6]=(len >> 8); ReleaseBuffer(buffptr); return len; } return 0; case 2: // send buffptr = GetBuff(); if (buffptr == 0) return (0); // No buffers, so ignore txlen = (buff[6] <<8 ) + buff[5] - 7; buffptr[1] = txlen; buffptr[2] = PortToChannel[port]; // Channel on this Soundcard memcpy(buffptr+3, &buff[7], txlen); C_Q_ADD(&TNC->TXQ, buffptr); return 0; case 3: // CHECK IF OK TO SEND return (0); // OK case 4: // reinit return (0); // OK case 5: // Close if (TNC->PID) { KillSoundTNC(TNC); if (AUTOSAVE == 1) SaveNodes(); Sleep(1000); } return (0); } return 0; }