📄 cpfpackets.cpp
字号:
/*____________________________________________________________________________
Copyright (C) 1996-1999 Network Associates, Inc.
All rights reserved.
$Id: CPFPackets.cpp,v 1.6 1999/03/10 02:35:19 heller Exp $
____________________________________________________________________________*/
//////////////////////////////////////////////////////////////////////
// This module implements an asynchronous reliable and unreliable
// datagram service that routes packets among the various threads
// above it and the transport layer below it.
//////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "CPFPackets.h"
#include "CControlThread.h"
#include "CCounterEncryptor.h"
#include "CPriorityQueue.h"
#include "CPacketWatch.h"
#include "CPFTransport.h"
#include "CPFWindow.h"
#include "CSoundInput.h"
#include "CSoundOutput.h"
#include "CRC.h"
#include "CStatusPane.h"
#include "PGPFoneUtils.h"
#ifdef PGPXFER
#include "CXferThread.h"
#endif
#ifdef PGP_MACINTOSH
#include "CPFTAppleTalk.h"
#include <UEnvironment.h>
#endif
#define BANDWIDTHIP 150000 // default bandwidth estimates
#define BANDWIDTHSERIAL9600 960
#define BANDWIDTHSERIAL14400 1370
#define BANDWIDTHSERIAL28800 2700
#define RELIABLESTART _hpt_Control
#define LASTPACKETTYPE _hpt_File
#define HPPPACKETDELIM 0x7E // At start and end of each packet
#define HPPPACKETESCAPE 0x7D // Prefix for escaped characters
#define HPPNEEDSESCAPE(c) ((((c) - HPPPACKETESCAPE) & 0xff) < 2)
#define HPPESCAPE(c) ((c) ^ 0x20)// transforms an escaped character
#define HPPUNESCAPE(c) HPPESCAPE(c)// transform is self-inverse
HPPReliablePacket *sControlReliables, *sFileReliables;
LMutexSemaphore *sInOutMutex;
ulong sRTTSequence, sRTTBase, sIntervalms, // milliseconds btwn snd sound pkts
sRFileSequence, sSFileSequence, sRControlSequence, sSControlSequence,
sLastRRR, // last rcvd reception report time
sLastSRR; // last sent reception report time
long sBandwidthcps, sBandwidthpp, sACKWaitAverage, sACKWaitTime,
sJitter, // jitter for rcvd packets
sJVariance, // arrival variance
sSkew, // clock skew
sMTU; // Maximum Transfer Unit
#ifdef PGP_MACINTOSH
#include <OpenTransport.h>
// On Macs with OT installed, we use a more precise measurement
// which gives us accurate milliseconds
OTTimeStamp sOTRTTBase;
#endif
CPFPacketsIn::CPFPacketsIn(Boolean packetMode,
CPFWindow *window,
CSoundOutput *soundOutput,
CPFTransport *transport,
CMessageQueue *controlQueue,
CMessageQueue *outQueue,
CMessageQueue *soundOut,
void **outResult)
#ifndef PGP_WIN32
: LThread(0, thread_DefaultStack, threadOption_UsePool, outResult)
#else
: LThread(outResult)
#endif // PGP_WIN32
{
sInOutMutex = new LMutexSemaphore;
mPFWindow = window;
mTransport = transport;
mSoundOutput = soundOutput;
mControlQueue = controlQueue;
mSoundOutQueue = soundOut;
mXferQueue = NIL;
mOutQueue = outQueue;
mPacketMode = packetMode;
mDecryptor = NIL;
mNoCrypto = FALSE;
mInputHead =
mInputTail = mInputBuffer;
mAbort = FALSE;
mSequence =
sSControlSequence =
sRControlSequence =
sSFileSequence =
sRFileSequence = 0;
sBandwidthcps = BANDWIDTHIP;
sMTU = 1040;
if(gPGFOpts.popt.connection == _cme_Serial)
{
switch(gPGFOpts.sopt.maxBaud)
{
case 0:
sBandwidthcps = BANDWIDTHSERIAL9600;
sMTU = 256;
break;
case 1:
sBandwidthcps = BANDWIDTHSERIAL14400;
sMTU = 256;
break;
case 2:
sBandwidthcps = BANDWIDTHSERIAL28800;
sMTU = 512;
break;
}
}
#ifdef PGP_MACINTOSH
else if(gPGFOpts.popt.connection == _cme_AppleTalk)
{
sMTU = MAXPGPFDDPSIZE;
}
#endif
sIntervalms = 200;
sJitter = 0;
sJVariance = 0;
sSkew = 0;
mJitterCount = 0;
sLastSRR = sLastRRR = 0;
mLateTrack = 0;
mSavedOOPkts = NIL;
mNumSavedOOPkts = 0;
sACKWaitTime = sACKWaitAverage = DEFAULTACKWAITTIME;
#ifdef PGP_WIN32
//windows 95 bug so we do this all the time
mAbortEvent_foo = CreateEvent(NULL, TRUE, FALSE, NULL);
if (mAbortEvent_foo == INVALID_HANDLE_VALUE)
pgp_errstring("error creating abort event");
mAbortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (mAbortEvent == INVALID_HANDLE_VALUE)
pgp_errstring("error creating abort event");
#endif // PGP_WIN32
}
CPFPacketsIn::~CPFPacketsIn()
{
SavedOOPacket *soop, *lsoop;
HPPReliablePacket *hppr;
if(mDecryptor)
delete mDecryptor;
for(soop=mSavedOOPkts;soop;)
{
// Delete any remaining reliable out of order packets
lsoop=soop;
soop=soop->next;
safe_free(lsoop->data);
safe_free(lsoop);
}
#ifdef PGP_WIN32
if(mAbortEvent != INVALID_HANDLE_VALUE)
CloseHandle(mAbortEvent);
if(mAbortEvent_foo != INVALID_HANDLE_VALUE)
CloseHandle(mAbortEvent_foo);
#endif // PGP_WIN32
for(hppr = sControlReliables;hppr;)
{
sControlReliables = sControlReliables->next;
if(hppr->data)
safe_free(hppr->data);
safe_free(hppr);
hppr = sControlReliables;
}
for(hppr = sFileReliables;hppr;)
{
sFileReliables = sFileReliables->next;
if(hppr->data)
safe_free(hppr->data);
safe_free(hppr);
hppr = sFileReliables;
}
delete sInOutMutex;
}
CPFPacketsOut::CPFPacketsOut(Boolean packetMode,
CPFWindow *window,
CPFTransport *transport,
CSoundInput *soundIn,
CMessageQueue *controlQueue,
CMessageQueue *soundQueue,
void **outResult)
#ifndef PGP_WIN32
: LThread(0, thread_DefaultStack, threadOption_UsePool, outResult)
#else
: LThread(outResult)
#endif // PGP_WIN32
{
short inx;
mPFWindow = window;
mTransport = transport;
mSoundQueue = soundQueue;
mControlQueue = controlQueue;
mXferThread = NIL;
mSoundInput = soundIn;
mPacketMode = packetMode;
mEncryptor = NIL;
mAbort = FALSE;
mSendingSound = FALSE;
for(inx = 0;inx<NUMHPPASYNCS;inx++)
mTransport->NewAsync(&mAsyncs[inx]);
mNextAsync = 0;
sControlReliables = sFileReliables = NIL;
mSequence = 0;
mReceiverWindow = MAXSAVEDOOPACKETS;
sRTTSequence = 0;
sRTTBase = pgp_getticks();
#ifdef PGP_WIN32
mAbortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (mAbortEvent == INVALID_HANDLE_VALUE)
pgp_errstring("error creating abort event");
#endif // PGP_WIN32
}
CPFPacketsOut::~CPFPacketsOut()
{
for(short inx = 0;inx<NUMHPPASYNCS;inx++)
mTransport->DeleteAsync(&mAsyncs[inx]);
if(mEncryptor)
delete mEncryptor;
#ifdef PGP_WIN32
if (mAbortEvent != INVALID_HANDLE_VALUE)
CloseHandle(mAbortEvent);
#endif // PGP_WIN32
}
// Package and send a packet.
// A packet is surrounded by HPPPACKETDELIM characters, and contains the
// following:
// Packet type (1 byte)
// Sequence Number (1 byte)
// Packet data (variable length)
// CRC (2 bytes, 4 bytes if reliable packet)
//
// If either of the bytes HPPPACKETDELIM or HPPPACKETESCAPE appear
// anywhere in the packet, they are escaped by replacing them
// with HPPPACKETESCAPE followed by an escaped form of the character.
// The escaping is done by XORing 0x20 with the character.
void
CPFPacketsOut::StreamSendPacket(enum HPPPacketType type, ulong seq, long len,
uchar *data, Boolean lastPacket)
{
HPPReliablePacket *hppr, *walk;
uchar *buffer, *p, c, *r, fb;
uchar iv[6], crcs[4];
ushort crc = 0xffff;
ulong crc32 = 0xffffffff;
short inx;
Boolean reliable;
pgpAssert(len <= HPPMAXPKTLEN);
r=data;
fb = *data;
if((type != _hpt_Control) && (type != _hpt_ACK))
{
mTXKeyChangeMutex.Wait();
// Setup the counter for counter mode
// Counter format:
// Byte 1 Packet Type
// Byte 2 Packet Counter, mod 2^40
// Bytes 7-8 Cipher block counter
iv[0] = (uchar)type;
iv[1] = 0;
LONG_TO_BUFFER(seq, &iv[2]);
if(mEncryptor)
mEncryptor->Encrypt(data, len, iv);
mTXKeyChangeMutex.Signal();
}
mTransport->WaitAsync(&mAsyncs[mNextAsync]);
mAsyncs[mNextAsync].buffer = p = buffer = (uchar *)safe_malloc(HPPBUFFERSIZE);
if(type >= RELIABLESTART)
reliable = TRUE;
else
reliable = FALSE;
*p++ = HPPPACKETDELIM; // Ensure packet starts with a delimiter
// escape and CRC the type byte
c = type;
if(reliable)
crc32 = updatecrc32(c, crc32);
else
crc = updatecrc16(c, crc);
if(HPPNEEDSESCAPE(c))
{
*p++ = HPPPACKETESCAPE;
c = HPPESCAPE(c);
}
*p++ = c;
// escape and CRC the sequence number
c = (uchar)seq;
if(reliable)
crc32 = updatecrc32(c, crc32);
else
crc = updatecrc16(c, crc);
if(HPPNEEDSESCAPE(c))
{
*p++ = HPPPACKETESCAPE;
c = HPPESCAPE(c);
}
*p++ = c;
// escape and CRC the packet data
for(;;)
{
c = *r++;
len--;
if(reliable)
crc32 = updatecrc32(c, crc32);
else
crc = updatecrc16(c, crc);
if(HPPNEEDSESCAPE(c))
{
*p++ = HPPPACKETESCAPE;
c = HPPESCAPE(c);
}
*p++ = c;
if(!len)
break;
}
// Now escape the CRC
if(reliable)
{
crc32 = ~crc32;
for(inx=0;inx<4;inx++)
{
// CRC-32 is implemented as little-endian, so we have to make
// sure that the bytes get inserted in little endian order
// here.
crcs[inx] = (unsigned char) crc32 & 0xff;
crc32>>=8;
}
for(inx=0;inx<4;inx++)
{
c = crcs[inx];
if(HPPNEEDSESCAPE(c))
{
*p++ = HPPPACKETESCAPE;
c = HPPESCAPE(c);
}
*p++ = c;
}
}
else
{
c = (crc >> 8) & 0xff;
if(HPPNEEDSESCAPE(c))
{
*p++ = HPPPACKETESCAPE;
c = HPPESCAPE(c);
}
*p++ = c;
c = crc & 0xff;
if(HPPNEEDSESCAPE(c))
{
*p++ = HPPPACKETESCAPE;
c = HPPESCAPE(c);
}
*p++ = c;
}
// If no more packets are expected for a while, add a delimiter
if(lastPacket)
*p++ = HPPPACKETDELIM;
// We're finished. Send it.
len = p-buffer;
if(type >= RELIABLESTART)
{
hppr = (HPPReliablePacket *)safe_malloc(sizeof(HPPReliablePacket));
memset(hppr, 0, sizeof(HPPReliablePacket));
sInOutMutex->Wait();
if(type == _hpt_File)
{
if(sFileReliables)
{
for(walk = sFileReliables;walk->next;walk=walk->next)
;
walk->next = hppr;
}
else
sFileReliables = hppr;
}
else
{
if(sControlReliables)
{
for(walk = sControlReliables;walk->next;walk=walk->next)
;
walk->next = hppr;
}
else
sControlReliables = hppr;
}
hppr->type = type;
hppr->seq = seq;
hppr->subType=fb;
hppr->firstXmitTime = hppr->lastXmitTime = pgp_getticks();
hppr->data = buffer;
safe_increaseCount(buffer);
hppr->len = (short) len;
sInOutMutex->Signal();
}
// send the data to be encrypted or to the modem
mTransport->WriteAsync(len, _pfc_Control, &mAsyncs[mNextAsync++]);
mNextAsync %= NUMHPPASYNCS;
if(gPacketWatch)
gPacketWatch->SentPacket();
}
// This is organized as a state machine, with GOTOs between states.
// If the mAbort flag is set, anything will jump to the abort state,
// which returns failure. (Checked before each I/O and before returning.)
// Otherwise, all jumps are backwards, with the expected flow being
// downwards through the code to the bottom. The states are:
//
// packetfind: Search for a packet delimiter in the input stream
// packetstart: Just past a packet delimiter, expecting a packet type
// followed by a packet body. If a packet delimiter is found in an
// unexpected place, jump straight back to packetstart.
// When an ending delimiter is found, check the length and CRC.
// If they're good, return the packet. Since the ending delimiter
// can also be the starting delimiter of the next packet, the input
// is backed up one character to make the next invocation work.
// If the CRC is not valid, go to packetstart.
Boolean
CPFPacketsIn::StreamGetPacket(enum HPPPacketType *type, uchar **buffer, short *len,
ulong *seq)
{
ushort inlen, outlen, crc;
uchar iv[6];
uchar c, seqbyte, *p;
ulong sequence, crc32;
Boolean crypted=FALSE, reliable;
*buffer = (uchar *)safe_malloc(HPPMAXPKTLEN+2);
if(!*buffer)
{
*len = 0;
return crypted;
}
// Skip bytes until the next packet header
packetfind:
// Ensure that we have some data to examine
if(mInputHead >= mInputTail && GetData() < 0)
goto abort;
// Scan for the start of a packet
for (;;)
{
inlen = mInputTail - mInputHead;
mInputHead = (uchar*)memchr(mInputHead, HPPPACKETDELIM, inlen);
if(mInputHead)
break;
if(GetData() < 0)
goto abort;
}
mInputHead++; // Skip packet start delimiter
packetstart:
// We have a valid packet start - get type
if(mInputHead >= mInputTail && GetData() < 0)
goto abort;
c = *mInputHead++;
if(HPPNEEDSESCAPE(c))
{
if(c == HPPPACKETDELIM)
goto packetstart; // Zero-length "packet" - totally ignore
// Okay, so it starts with an escaped byte
if(mInputHead >= mInputTail && GetData() < 0)
goto abort;
c = *mInputHead++;
if(c == HPPPACKETDELIM)
{
if(gPacketWatch)
gPacketWatch->GotPacket(FALSE); // Bad packet
goto packetstart;
}
c = HPPUNESCAPE(c);
}
*type = (enum HPPPacketType)c;
if(*type >= RELIABLESTART)
reliable = TRUE;
else
reliable = FALSE;
// Start CRC computation
if(reliable)
crc32 = updatecrc32(c, 0xffffffff);
else
crc = updatecrc16(c, 0xffff);
// Get Sequence number
if(mInputHead >= mInputTail && GetData() < 0)
goto abort;
c = *mInputHead++;
if(HPPNEEDSESCAPE(c))
{
if(c == HPPPACKETDELIM)
{
if(gPacketWatch)
gPacketWatch->GotPacket(FALSE); // Bad packet
goto packetstart;
}
// Okay, so it starts with an escaped byte
if(mInputHead >= mInputTail && GetData() < 0)
goto abort;
c = *mInputHead++;
if(c == HPPPACKETDELIM)
{
if(gPacketWatch)
gPacketWatch->GotPacket(FALSE); // Bad packet
goto packetstart;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -