📄 ccontrolthread.cpp
字号:
/*____________________________________________________________________________
Copyright (C) 1996-1999 Network Associates, Inc.
All rights reserved.
$Id: CControlThread.cpp,v 1.4 1999/03/10 02:32:21 heller Exp $
____________________________________________________________________________*/
#include "CControlThread.h"
#include "CPFTSerial.h"
#include "CPFWindow.h"
#include "CStatusPane.h"
#include "CPFPackets.h"
#include "CMessageQueue.h"
#include "CSoundInput.h"
#include "CSoundOutput.h"
#include "CPacketWatch.h"
#include "CEncryptionStream.h"
#include "HashWordList.h"
#include "SHA.h"
#include "dh.h"
#include "bn.h"
#include "fastpool.h"
#include "CPFTInternet.h"
#ifdef PGPXFER
#include "CXferWindow.h"
#include "CXferThread.h"
#endif
#ifdef PGP_MACINTOSH
#include "CPFTAppleTalk.h"
#endif
#include <stdio.h>
#include <string.h>
/* CONFIGCALL enables us to "turn off" configuration packets
This can be helpful in testing for many reasons including
trying to determine whether a problem lies in configuration
or elsewhere */
#define CONFIGCALL
/* DIRECTCONNECT implements a debug mode where ControlThread
assumes that a modem connection is already established just
by creating a transport object and vice versa. */
#define noDIRECTCONNECT
#define noDEBUGCONFIG
const uchar pgpfMajorProtocolVersion = 0;
const uchar pgpfMinorProtocolVersion = 0;
CControlThread::CControlThread(CMessageQueue *msgQueue,
CPFWindow *cpfWindow,
CSoundInput *soundInput,
CSoundOutput *soundOutput,
void **outResult)
#ifndef PGP_WIN32
: LThread(FALSE, thread_DefaultStack, threadOption_UsePool, outResult)
#else
: LThread(outResult)
#endif // PGP_WIN32
{
mControlState = _con_None;
mDone = FALSE;
mMsgQueue = msgQueue;
mPFWindow = cpfWindow;
mSoundInput = soundInput;
mSoundOutput = soundOutput;
mStatusPane = CStatusPane::GetStatusPane();
mXferWindow = NIL;
mTransport = NIL;
mInHPP = NIL;
mOutHPP = NIL;
mXfer = NIL;
mXferQueue = NIL;
mXferResult = mInHPPResult = mOutHPPResult = 1L;
mSoundOutQ = mControlOutQ = NIL;
mFullDuplex = FALSE;
mAuthenticated = FALSE;
mDHPublic = mDHPrivate = NIL;
mCoders = NIL;
mNumCoders = 0;
mRemotePublicName[0]=0;
SetSpeaker(TRUE);
byteFifoInit(&mSharedSecret);
byteFifoInit(&mOAuthentication);
byteFifoInit(&mAAuthentication);
}
CControlThread::~CControlThread()
{
if(mDHPublic)
pgp_free(mDHPublic);
if(mDHPrivate)
pgp_free(mDHPrivate);
if(mCoders)
pgp_free(mCoders);
}
void *
CControlThread::Run(void)
{
short done = 0, err;
Boolean exit = FALSE;
PFMessage *msg, *hACK;
ContactEntry *contact;
uchar *p, *e, alen[4];
long codec, authwrit;
short reply;
#ifdef DEBUGCONFIG
uchar s[80];
#endif
while(!exit)
{
err = 0;
msg = mMsgQueue->Recv();
if(!msg)
continue;
switch(msg->type)
{
case _mt_quit:
exit = mDone = TRUE;
case _mt_remoteAbort:
case _mt_abort:
mControlState = _con_Disconnecting;
mPFWindow->ShowStatus();
if(msg->type != _mt_quit)
{
mPFWindow->SetDecoder(0);
mPFWindow->SetEncoder(0);
mPFWindow->SetEncryption(0,0);
mPFWindow->HideAuthParams();
mPFWindow->ClearDecoderList();
mPFWindow->ClearEncoderList();
mPFWindow->SetKeyExchange("");
mPFWindow->AllowXfers(FALSE);
}
mSoundInput->Record(FALSE);
mSoundOutput->Play(FALSE);
mAuthenticated = FALSE;
#ifdef PGPXFER
if(mXfer)
{
mInHPP->SetXferQueue(NIL);
if(mXferWindow)
mXferWindow->SetXferThread(NIL);
mXferQueue->Send(_mt_abort);
while(!mXferResult)
(Yield)();
delete mXferQueue;
mXferQueue = NIL;
mXfer = NIL;
}
#endif
if(mControlOutQ)
{
mSoundOutQ->FreeType(_mt_voicePacket);
mTransport->Flush();
if((msg->type == _mt_abort || msg->type == _mt_quit))
{
if((p = (uchar *)pgp_malloc(1)) != NULL)
{
// Send out a hangup request after clearing the queue
// and wait 4.1 seconds for a reply
*p = _ctp_Hangup;
mControlOutQ->Send(_mt_controlPacket, p, 1);
hACK = mMsgQueue->Recv(4100);
//pgpAssert(!hACK || hACK->type == _mt_ack);
}
}
mSoundInput->SetPacketThread(NIL);
mControlOutQ->Send(_mt_abort);
while(!mOutHPPResult)
(Yield)();
mInHPP->AbortSync();
while(!mInHPPResult)
(Yield)();
delete mControlOutQ;
mControlOutQ = NIL;
if(gPacketWatch)
gPacketWatch->SetHPPQueue(NIL);
delete mSoundOutQ;
mSoundOutQ = NIL;
}
if(mTransport)
{
if(mTransport->GetState() == _cs_connected)
mTransport->Disconnect();
if(!mDone && gPGFOpts.popt.alwaysListen)
mMsgQueue->SendUnique(_mt_waitCall);
else
{
delete mTransport;
mTransport = NIL;
}
}
byteFifoDestroy(&mSharedSecret); //destroy all records of key
byteFifoDestroy(&mOAuthentication); //material for this call
byteFifoDestroy(&mAAuthentication);
memset(mRemotePublicName, 0, 64); //destroy record of remote party
mControlState = _con_None;
break;
case _mt_answer:
case _mt_waitCall:
if(mControlState != _con_None)
break;
SetupTransport(gPGFOpts.popt.connection);
if(mTransport)
{
#ifndef DIRECTCONNECT
if(mTransport->Reset())
{
delete mTransport;
mTransport = NIL;
}
else if(!(err = mTransport->Listen(msg->type == _mt_answer)) &&
(mTransport->GetState() == _cs_connected))
{
mOriginator = FALSE;
StartPhone();
}
else if(err != _pge_InternalAbort)
{
if(gPGFOpts.popt.alwaysListen && !mDone)
mMsgQueue->SendUnique(_mt_waitCall);
else
{
delete mTransport;
mTransport = NIL;
}
}
#else
mPFWindow->SetState(_cs_connected);
mOriginator = FALSE;
StartPhone();
#endif
}
break;
case _mt_call:
contact = (ContactEntry *)msg->data;
reply = _cr_NoReply;
SetupTransport(contact->method);
if(mTransport)
{
#ifndef DIRECTCONNECT
pgpAssert(contact);
if(mTransport->Reset())
{
delete mTransport;
mTransport = NIL;
}
else if(mTransport->Connect(contact, &reply))
{
delete mTransport;
mTransport = NIL;
}
else if(reply == _cr_Connect)
{
mOriginator = TRUE;
StartPhone();
}
else if(gPGFOpts.popt.alwaysListen && !mDone)
mMsgQueue->SendUnique(_mt_waitCall);
#else
mPFWindow->SetState(_cs_connected);
mOriginator = TRUE;
StartPhone();
#endif
}
break;
case _mt_talk: // outgoing talk request initiated by us
if(!mFlipInProgress && mControlOutQ && mTransport)
{
if(!mFullDuplex)
{
if((p = (uchar *)pgp_malloc(1)) != NULL)
{
*p = _ctp_Talk;
mControlOutQ->Send(_mt_controlPacket, p, 1);
mFlipInProgress = TRUE;
}
}
else if(!mHaveChannel)
{
SetSpeaker(TRUE);
mSoundInput->Record(TRUE);
}
}
break;
case _mt_listen: // outgoing listen request initiated by us
if(!mFlipInProgress && mControlOutQ && mTransport)
{
if(!mFullDuplex)
{
if((p = (uchar *)pgp_malloc(1)) != NULL)
{
*p = _ctp_Listen;
mControlOutQ->Send(_mt_controlPacket, p, 1);
mFlipInProgress = TRUE;
}
}
else if(mHaveChannel)
{
mSoundInput->Record(FALSE);
SetSpeaker(FALSE);
}
}
break;
case _mt_ack:
switch((uchar)msg->data)
{
case _ctp_Talk:
if(!mHaveChannel && mFlipInProgress)
{
SetSpeaker(TRUE);
mSoundInput->Record(TRUE);
}
mFlipInProgress = FALSE;
break;
case _ctp_Listen:
if(mHaveChannel && mFlipInProgress)
{
mSoundInput->Record(FALSE);
SetSpeaker(FALSE);
}
mFlipInProgress = FALSE;
break;
case _ctp_OpenVoice:
if(mChangingEnc)
mSoundInput->Pause(FALSE);
mChangingEnc = FALSE;
break;
case _ctp_VoiceSwitch:
if(mChangingDec)
mSoundOutput->Pause(FALSE);
mChangingDec = FALSE;
break;
}
msg->data = NIL;
break;
case _mt_resetTransport:
if(mTransport)
{
delete mTransport;
mTransport = NIL;
}
if(gPGFOpts.popt.alwaysListen)
mMsgQueue->SendUnique(_mt_waitCall);
break;
case _mt_changeDecoder:
codec = (long)msg->data;
if(mChangingDec)
{
// The user has become overzealous about
// changing coders. Lets set the display back
// to what was requested a couple seconds
// ago.
//+++++todo
}
else if(!mChangingDec && ((p = e = (uchar *)pgp_malloc(5)) != NULL))
{
mSoundOutput->Pause(TRUE);
*e++ = _ctp_VoiceSwitch;
LONG_TO_BUFFER(codec, e); e+=4;
mControlOutQ->Send(_mt_controlPacket, p, e-p);
mSoundOutput->SetCodec(codec);
mChangingDec = TRUE;
}
msg->data = NIL;
break;
case _mt_changeEncoder:
if(mChangingEnc)
{
// The user has become overzealous about
// changing coders. Lets set the display back
// to what was requested a couple seconds
// ago.
//+++++todo
}
else if(!mChangingEnc && ((p = e = (uchar *)pgp_malloc(5)) != NULL))
{
mSoundInput->Pause(TRUE);
*e++ = _ctp_OpenVoice;
codec = (long)msg->data;
LONG_TO_BUFFER(codec, e); e+=4;
mControlOutQ->Send(_mt_controlPacket, p, e-p);
mSoundInput->SetCodec(codec);
mChangingEnc = TRUE;
}
msg->data = NIL;
break;
case _mt_controlPacket:
switch(*(p=(uchar *)msg->data))
{
case _ctp_Hello:
if(mControlState == _con_Configuring &&
mConfigState == _cts_Hello)
{
SHORT_TO_BUFFER(msg->len, alen);
authwrit = byteFifoWrite(mOriginator? &mAAuthentication : &mOAuthentication, alen, 2);
pgpAssert(authwrit == 2);
authwrit = byteFifoWrite(mOriginator? &mAAuthentication : &mOAuthentication, p, msg->len);
pgpAssert(authwrit == msg->len);
if(ReceiveHello(++p, msg->len - 1))
{
if(mPrime &&
memcmp(mEncryptor, sCryptorHash[_enc_none], 4))
{
mConfigState = _cts_DHHash;
SendDHHash();
}
else
{ //non-encrypted call
mPrime = NIL;
mStatusPane->AddStatus(0,
"Unencrypted connection negotiated.");
PlayInsecureWarning();
mInHPP->SetNoCryptoMode();
mConfigState = _cts_Info;
SendInfo();
}
}
else
{
mStatusPane->AddStatus(0,
"Bad Hello received. Aborting call.");
mMsgQueue->Send(_mt_abort);
}
}
break;
case _ctp_DHHash:
if(mControlState == _con_Configuring &&
mConfigState == _cts_DHHash)
{
SHORT_TO_BUFFER(msg->len, alen);
authwrit = byteFifoWrite(mOriginator? &mAAuthentication : &mOAuthentication, alen, 2);
pgpAssert(authwrit == 2);
authwrit = byteFifoWrite(mOriginator? &mAAuthentication : &mOAuthentication, p, msg->len);
pgpAssert(authwrit == msg->len);
if(ReceiveDHHash(++p, msg->len - 1))
{
mConfigState = _cts_DHPublic;
SendDHPublic();
}
else
{
mStatusPane->AddStatus(0,
"Bad DHHash received. Aborting call.");
mMsgQueue->Send(_mt_abort);
}
}
break;
case _ctp_DHPublic:
if(mControlState == _con_Configuring &&
mConfigState == _cts_DHPublic)
{
SHORT_TO_BUFFER(msg->len, alen);
authwrit = byteFifoWrite(mOriginator? &mAAuthentication : &mOAuthentication, alen, 2);
pgpAssert(authwrit == 2);
authwrit = byteFifoWrite(mOriginator? &mAAuthentication : &mOAuthentication, p, msg->len);
pgpAssert(authwrit == msg->len);
if(ReceiveDHPublic(++p, msg->len - 1))
{
mConfigState = _cts_Info;
SendInfo();
}
else
{
mStatusPane->AddStatus(0,
"Bad DHPublic received. Aborting call.");
mMsgQueue->Send(_mt_abort);
}
}
break;
case _ctp_Info:
if(mControlState == _con_Configuring &&
mConfigState == _cts_Info)
{
if(ReceiveInfo(++p, msg->len - 1))
ConfigComplete();
}
break;
case _ctp_Hangup:
mControlState = _con_Disconnecting;
mStatusPane->AddStatus(0,"Remote disconnected.");
Sleep(1000); // Try to allow time for the ACK to go out
mMsgQueue->Send(_mt_remoteAbort);
break;
case _ctp_OpenVoice:
p++;
BUFFER_TO_LONG(p, codec);
mPFWindow->SetDecoder(codec);
mSoundOutput->Pause(TRUE);
mSoundOutput->SetCodec(codec);
mSoundOutput->Pause(FALSE);
#ifdef DEBUGCONFIG
pgp_memcpy(s,p,4);
s[4]=0;
mStatusPane->AddStatus(0,"_ctp_OpenVoice(O): %s",s);
#endif
break;
case _ctp_VoiceSwitch:
p++;
BUFFER_TO_LONG(p, codec);
mPFWindow->SetEncoder(codec);
mSoundInput->Pause(TRUE);
mSoundInput->SetCodec(codec);
mSoundInput->Pause(FALSE);
#ifdef DEBUGCONFIG
pgp_memcpy(s,p,4);
s[4]=0;
mStatusPane->AddStatus(0,"_ctp_VoiceSwitch(I): %s",s);
#endif
break;
case _ctp_Talk: // other side wishes to speak
if(!mFullDuplex && (!mFlipInProgress || !mOriginator))
{
mSoundInput->Record(FALSE);
SetSpeaker(FALSE);
mFlipInProgress = FALSE;
}
break;
case _ctp_Listen: // other side wishes to listen
if(!mFullDuplex && (!mFlipInProgress || !mOriginator))
{
SetSpeaker(TRUE); // disable further playing of
// incoming packets
mSoundOutput->ChannelSwitch();
mSoundInput->Record(TRUE);
mFlipInProgress = FALSE;
}
break;
default:
mStatusPane->AddStatus(0,"Unknown control packet received.");
break;
}
break;
}
mMsgQueue->Free(msg);
}
return (void *)1L;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -