#include "IrLSAPConn.h"
#include "IrGlue.h"
#include "IrLMP.h"
#include "CList.h"
#include "CListIterator.h"
#include "CBufferSegment.h"
#include "IrDALog.h"
#if (hasTracing > 0 && hasLSAPConnTracing > 0)
enum IrLSAPConnTraceCodes
{
kNullEvent = 1,
kDestroy,
kDeInit,
kUnexpectedEvent,
kDiscConnectEvent,
kDiscListenEvent,
kDiscDiscRequestEvent,
kDiscLeftoversReplyEvent,
kConnectPendConnectReplyEvent,
kConnectPendPutReplyEvent,
kConnectPendDiscRequestEvent,
kConnectPendDiscReplyEvent,
kConnectGetReplyEvent,
kConnectWatchdogTimeoutEvent,
kConnectDisconnectRequestEvent,
kConnectDisconnectReplyEvent,
kListenPendListenReplyEvent,
kListenPendDiscRequestEvent,
kListenPendDiscReplyEvent,
kListenGetReplyEvent,
kListenPutReplyEvent,
kListenDisconnectRequestEvent,
kListenDisconnectReplyEvent,
kAcceptConnectRequestEvent,
kRejectConnectRequestEvent,
kAccRejPutReplyEvent,
kAccRejDisconnectReplyEvent,
kDTRPutRequestEvent,
kDTRGetRequestEvent,
kDTRPutReplyEvent,
kDTRGetReplyEvent,
kDTRCancelPutRequestEvent,
kDTRCancelGetRequestEvent,
kDTRCancelPutReplyEvent,
kDTRCancelGetReplyEvent,
kDTRDisconnectRequestEvent,
kDTRDisconnectReplyEvent,
kDTRReleaseRequestEvent,
kMyData,
kDataForMe,
kDataWaitingForMe,
kLogRejectingMyData,
kGetMyId,
kLogDiscPendingEvent,
kLogDiscPendingClient,
kLogDiscPendingRejectRequest,
kLogDiscPendingMiscReply,
kLogDiscPendingConnLstnDone,
kLogDiscPendingInternalDisc,
kLogDiscPendingWatchDog,
kLogDiscPendingDiscDone,
kLogDiscPendingRequeue,
kEnqueueEvent,
kDequeueEventStart,
kDequeueEventEnd
};
static
EventTraceCauseDesc IrLSAPConnTraceEvents[] = {
{kNullEvent, "IrLSAPConn: null event"},
{kDestroy, "IrLSAPConn: destroy obj="},
{kDeInit, "IrLSAPConn: DeInit"},
{kUnexpectedEvent, "IrLSAPConn: unexpected event"},
{kDiscConnectEvent, "IrLSAPConn: disc connect request"},
{kDiscListenEvent, "IrLSAPConn: disc listen request"},
{kDiscDiscRequestEvent, "IrLSAPConn: disc disconnect request"},
{kDiscLeftoversReplyEvent, "IrLSAPConn: disc leftovers reply"},
{kConnectPendConnectReplyEvent, "IrLSAPConn: conn pend got LAP reply"},
{kConnectPendPutReplyEvent, "IrLSAPConn: conn pend put LM-PDU conn request"},
{kConnectPendDiscRequestEvent, "IrLSAPConn: conn pend disconnect request"},
{kConnectPendDiscReplyEvent, "IrLSAPConn: conn pend disconnect reply"},
{kConnectGetReplyEvent, "IrLSAPConn: connect got LM-PDU conn reply"},
{kConnectWatchdogTimeoutEvent, "IrLSAPConn: connect watchdog timed out"},
{kConnectDisconnectRequestEvent,"IrLSAPConn: connect disconnect request"},
{kConnectDisconnectReplyEvent, "IrLSAPConn: connect disconnect reply"},
{kListenPendListenReplyEvent, "IrLSAPConn: lstn pend got LAP reply"},
{kListenPendDiscRequestEvent, "IrLSAPConn: lstn pend disconnect request"},
{kListenPendDiscReplyEvent, "IrLSAPConn: lstn pend disconnect reply"},
{kListenGetReplyEvent, "IrLSAPConn: listen got LM-PDU conn request"},
{kListenPutReplyEvent, "IrLSAPConn: listen put LM-PDU disc reply"},
{kListenDisconnectRequestEvent, "IrLSAPConn: listen disconnect request"},
{kListenDisconnectReplyEvent, "IrLSAPConn: listen disconnect reply"},
{kAcceptConnectRequestEvent, "IrLSAPConn: accept connect request"},
{kRejectConnectRequestEvent, "IrLSAPConn: reject connect request"},
{kAccRejPutReplyEvent, "IrLSAPConn: acc/rej put LM-PDU conn/disc reply"},
{kAccRejDisconnectReplyEvent, "IrLSAPConn: acc/rej disconnect reply"},
{kDTRPutRequestEvent, "IrLSAPConn: DTR put request"},
{kDTRGetRequestEvent, "IrLSAPConn: DTR get request"},
{kDTRPutReplyEvent, "IrLSAPConn: DTR put reply"},
{kDTRGetReplyEvent, "IrLSAPConn: DTR get reply"},
{kDTRCancelPutRequestEvent, "IrLSAPConn: DTR cancel put request"},
{kDTRCancelGetRequestEvent, "IrLSAPConn: DTR cancel get request"},
{kDTRCancelPutReplyEvent, "IrLSAPConn: DTR cancel put reply"},
{kDTRCancelGetReplyEvent, "IrLSAPConn: DTR cancel get reply"},
{kDTRDisconnectRequestEvent, "IrLSAPConn: DTR disconnect request"},
{kDTRDisconnectReplyEvent, "IrLSAPConn: DTR disconnect reply"},
{kDTRReleaseRequestEvent, "IrLSAPConn: DTR release request"},
{kMyData, "IrLSAPConn: checking packet header"},
{kDataForMe, "IrLSAPConn: data for this LSAP" },
{kDataWaitingForMe, "IrLSAPConn: data waiting for this LSAP" },
{kLogRejectingMyData, "IrLSAPConn: rejecting listen attempt, state="},
{kGetMyId, "IrLSAPConn: get my id. obj=, id="},
{kLogDiscPendingEvent, "IrLSAPConn: disconnect pending, 0, event"},
{kLogDiscPendingClient, "IrLSAPConn: disconnect pending, client=="},
{kLogDiscPendingRejectRequest, "IrLSAPConn: disconnect pending, rejecting request"},
{kLogDiscPendingMiscReply, "IrLSAPConn: disconnect pending, reply. event, pendevent"},
{kLogDiscPendingConnLstnDone, "IrLSAPConn: disconnect pending, connlstn done"},
{kLogDiscPendingInternalDisc, "IrLSAPConn: disconnect pending, internal discon (pending event, result)"},
{kLogDiscPendingWatchDog, "IrLSAPConn: disconnect pending, watchdog timer"},
{kLogDiscPendingDiscDone, "IrLSAPConn: disconnect pending, disconnect complete, result="},
{kLogDiscPendingRequeue, "IrLSAPConn: disconnect pending, requeue event"},
{kEnqueueEvent, "IrLSAPConn: Event Queued"},
{kDequeueEventStart, "IrLSAPConn: Event Start"},
{kDequeueEventEnd, "IrLSAPConn: Event End"}
};
#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, IrLSAPConnTraceEvents, true)
#else
#define XTRACE(x, y, z) ((void)0)
#endif
#define GetLMP (fIrDA->GetLMP())
#define super TIrStream
OSDefineMetaClassAndStructors(TLSAPConn, TIrStream);
TLSAPConn *
TLSAPConn::tLSAPConn(TIrGlue* irda, TIrStream* client)
{
TLSAPConn *obj = new TLSAPConn;
XTRACE(kNullEvent, 0, obj);
if (obj && !obj->Init(irda, client)) {
obj->release();
obj = nil;
}
return obj;
}
void
TLSAPConn::free()
{
XTRACE(kDestroy, 0, this);
if ((fMyLSAPId != kInvalidLSAPId) && (fMyLSAPId != kNameServerLSAPId)) {
fIrDA->ReleaseLSAPId(fMyLSAPId);
}
fMyLSAPId = kInvalidLSAPId;
if (fPendingRequests) { fPendingRequests->release();
fPendingRequests = nil;
}
super::free();
}
Boolean TLSAPConn::Init(TIrGlue* irda, TIrStream* client)
{
fState = kLSAPConnDisconnected;
fConnecting = false;
fClient = nil;
fResult = noErr;
fPendConnLstn = nil;
fConnLstnUserData = nil;
fGetData = nil;
fGetOffset = fGetLength = 0;
fMyLSAPId = fPeerLSAPId = kInvalidLSAPId;
fDevAddr = fLSAPId = 0;
fPendingRequests = nil;
fWatchdogTimerActive = false;
fWatchdogTimerCount = 0;
#if (hasTracing > 0 && hasLSAPConnTracing > 0)
if (!super::Init(irda, IrLSAPConnTraceEvents, kEnqueueEvent)) return false;
#else
if (!super::Init(irda)) return false;
#endif
fClient = client;
fPendingRequests = CList::cList();
require(fPendingRequests, Fail);
return true;
Fail:
return false;
}
void TLSAPConn::AssignId(ULong id)
{
XASSERT(fMyLSAPId == kInvalidLSAPId);
fMyLSAPId = (UByte)id;
}
UByte TLSAPConn::GetMyLSAPId(void)
{
XTRACE(kGetMyId, 0, this);
XTRACE(kGetMyId, 0, fMyLSAPId);
return fMyLSAPId;
};
void TLSAPConn::NextState(ULong event)
{
switch (fState) {
case kLSAPConnDisconnected:
HandleDisconnectedStateEvent(event);
break;
case kLSAPConnConnectPending:
HandleConnectPendingStateEvent(event);
break;
case kLSAPConnConnect:
HandleConnectStateEvent(event);
break;
case kLSAPConnListenPending:
HandleListenPendingStateEvent(event);
break;
case kLSAPConnListen:
HandleListenStateEvent(event);
break;
case kLSAPConnAccept:
HandleAcceptStateEvent(event);
break;
case kLSAPConnDataTransferReady:
HandleDataTransferReadyStateEvent(event);
break;
case kLSAPDisconnectPending:
HandleDisconnectPendingStateEvent(event);
break;
default:
DebugLog("TLSAPConn::NextState: bad fState");
break;
}
}
void TLSAPConn::HandleDisconnectedStateEvent(ULong event)
{
switch (event) {
case kIrConnectRequestEvent:
case kIrListenRequestEvent:
{
XTRACE(event == kIrConnectRequestEvent ? kDiscConnectEvent : kDiscListenEvent, fMyLSAPId, 0);
TIrConnLstnRequest* connLstnReq = (TIrConnLstnRequest*)GetCurrentEvent();
PassRequestToLMP();
SaveCurrentRequest();
XASSERT(fPendConnLstn == nil);
fPendConnLstn = GetCurrentEvent();
fConnLstnUserData = connLstnReq->fData;
if (event == kIrConnectRequestEvent) {
fConnecting = true;
fPeerLSAPId = connLstnReq->fLSAPId;
fState = kLSAPConnConnectPending;
}
else {
fConnecting = false;
fPeerLSAPId = kPendingConnectLSAPId;
fState = kLSAPConnListenPending;
}
}
break;
case kIrDisconnectRequestEvent:
{
XTRACE(kDiscDiscRequestEvent, 0, 0);
TIrDisconnectRequest* disconnectReq = (TIrDisconnectRequest*)GetCurrentEvent();
disconnectReq->fEvent = kIrDisconnectReplyEvent;
fClient->EnqueueEvent(disconnectReq);
}
break;
case kIrGetDataRequestEvent:
case kIrPutDataRequestEvent:
{
TIrEvent* getPutReq = (TIrEvent*)GetCurrentEvent();
XTRACE(kDiscLeftoversReplyEvent, event, 0);
XTRACE(kDiscLeftoversReplyEvent, 0, fClient); getPutReq->fEvent = (UByte)RequestIdToReplyId(getPutReq->fEvent);
getPutReq->fResult = kIrDAErrNotConnected; fClient->EnqueueEvent(getPutReq);
}
break;
case kIrGetDataReplyEvent:
case kIrPutDataReplyEvent:
case kIrDisconnectReplyEvent:
{
check(event != kIrDisconnectReplyEvent); TIrEvent* reply = (TIrEvent*)GetCurrentEvent();
XTRACE(kDiscLeftoversReplyEvent, event, reply->fPendEvent);
XTRACE(kDiscLeftoversReplyEvent, 0, fClient); reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);
fClient->EnqueueEvent(reply);
}
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleDisconnectedStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleConnectPendingStateEvent(ULong event)
{
switch (event) {
case kIrConnectReplyEvent:
{
TIrConnLstnReply* connectReply = (TIrConnLstnReply*)GetCurrentEvent();
XTRACE(kConnectPendConnectReplyEvent, 0, connectReply->fResult);
if (connectReply->fResult != noErr) {
DisconnectStart(connectReply->fResult); }
else {
fDevAddr = connectReply->fDevAddr; fLSAPId = connectReply->fLSAPId;
PutControlFrame(kLMPDUConnectRequest, 0);
}
}
break;
case kIrPutDataReplyEvent:
{
TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
XTRACE(kConnectPendPutReplyEvent, 0, putReply->fResult);
if (putReply->fResult != noErr) {
DisconnectStart(putReply->fResult);
}
else {
StartConnectTimer();
GetControlFrame();
fState = kLSAPConnConnect;
}
}
break;
case kIrDisconnectRequestEvent:
{
XTRACE(kConnectPendDiscRequestEvent, 0, 0);
SaveCurrentRequest();
fState = kLSAPDisconnectPending; PassRequestToLMP();
}
break;
case kIrDisconnectReplyEvent:
{
check(event != kIrDisconnectReplyEvent); fState = kLSAPConnDisconnected;
if (InternalDisconnectRequest()) {
XTRACE(kConnectPendDiscReplyEvent, 0, fResult);
ConnLstnComplete(fResult);
}
else {
XTRACE(kConnectPendDiscReplyEvent, 0, 0);
fPendConnLstn = nil; fClient->EnqueueEvent(GetCurrentEvent());
}
}
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleConnectPendingStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleConnectStateEvent(ULong event)
{
switch (event) {
case kIrGetDataReplyEvent:
{
TIrGetReply* getReply = (TIrGetReply*)GetCurrentEvent();
XTRACE(kConnectGetReplyEvent, getReply->fCtrlOpCode, getReply->fResult);
StopConnectTimer();
if (getReply->fResult != noErr) {
DisconnectStart(getReply->fResult);
}
else {
switch(getReply->fCtrlOpCode) {
case kLMPDUConnectRequest:
DisconnectStart(kIrDAErrGeneric );
break;
case kLMPDUDisconnectEvent:
DisconnectStart(kIrDAErrGeneric );
break;
case kLMPDUConnectReply:
ConnLstnComplete(noErr);
fState = kLSAPConnDataTransferReady;
break;
default:
DebugLog("TLSAPConn::HandleConnectStateEvent: unexpected ctrl opcode");
break;
}
}
}
break;
case kIrConnWatchdogExpiredEvent:
{
XTRACE(kConnectWatchdogTimeoutEvent, 0, 0);
StopConnectTimer();
if (1) { TIrDisconnectRequest *disconnectRequest;
disconnectRequest = (TIrDisconnectRequest*)fIrDA->GrabEventBlock(kIrDisconnectRequestEvent, sizeof(TIrDisconnectRequest));
check(disconnectRequest); if (disconnectRequest) {
disconnectRequest->fPendEvent = kIrConnWatchdogExpiredEvent; DisconnectStart(kIrDAErrGeneric, disconnectRequest);
}
}
}
break;
case kIrDisconnectRequestEvent:
XTRACE(kConnectDisconnectRequestEvent, 0, 0);
StopConnectTimer();
SaveCurrentRequest();
fState = kLSAPDisconnectPending; PassRequestToLMP();
break;
case kIrDisconnectReplyEvent:
check(event != kIrDisconnectReplyEvent); fState = kLSAPConnDisconnected;
if (InternalDisconnectRequest()) {
XTRACE(kConnectDisconnectReplyEvent, 0, fResult);
ConnLstnComplete(fResult);
}
else {
XTRACE(kConnectDisconnectReplyEvent, 0, 0);
fPendConnLstn = nil; fClient->EnqueueEvent(GetCurrentEvent());
}
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleConnectStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleListenPendingStateEvent(ULong event)
{
switch (event) {
case kIrListenReplyEvent:
{
TIrConnLstnReply* listenReply = (TIrConnLstnReply*)GetCurrentEvent();
XTRACE(kListenPendListenReplyEvent, fMyLSAPId, listenReply->fResult);
if (listenReply->fResult != noErr) {
DisconnectStart(listenReply->fResult);
}
else {
fDevAddr = listenReply->fDevAddr; fLSAPId = listenReply->fLSAPId;
GetControlFrame();
fState = kLSAPConnListen;
}
}
break;
case kIrDisconnectRequestEvent:
XTRACE(kListenPendDiscRequestEvent, 0, 0);
SaveCurrentRequest();
fState = kLSAPDisconnectPending; PassRequestToLMP();
break;
case kIrDisconnectReplyEvent:
check(event != kIrDisconnectReplyEvent); fState = kLSAPConnDisconnected;
if (InternalDisconnectRequest()) {
XTRACE(kListenPendDiscReplyEvent, 1, fResult);
ConnLstnComplete(fResult);
if (0) { TIrConnLstnRequest *req = (TIrConnLstnRequest*)GetCurrentEvent();
check(req->fPendEvent == kIrListenRequestEvent);
req->fEvent = req->fPendEvent; fPendConnLstn = nil; this->EnqueueEvent(req); }
}
else {
XTRACE(kListenPendDiscReplyEvent, 2, 0);
if (1) { TIrConnLstnReply* reply = (TIrConnLstnReply*)fPendConnLstn;
XASSERT(fPendConnLstn != nil); reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent); reply->fResult = kIrDAErrRequestCanceled;
fClient->EnqueueEvent(reply);
}
fPendConnLstn = nil; fClient->EnqueueEvent(GetCurrentEvent()); }
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleListenPendingStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleListenStateEvent(ULong event)
{
switch (event) {
case kIrGetDataReplyEvent:
{
TIrGetReply *getReply = (TIrGetReply *) GetCurrentEvent();
XTRACE(kListenGetReplyEvent, getReply->fCtrlOpCode, getReply->fResult);
if (getReply->fResult != noErr) {
DisconnectStart(getReply->fResult); }
else {
switch(getReply->fCtrlOpCode) {
case kLMPDUDataEvent:
case kLMPDUConnectReply:
PutControlFrame(kLMPDUDisconnectEvent, kIrDataSentOnDiscLSAPConn);
break;
case kLMPDUConnectRequest:
{
TIrConnLstnReply* listenReply = (TIrConnLstnReply*)GetCurrentEvent();
listenReply->fLSAPId = fPeerLSAPId;
ConnLstnComplete(noErr);
fState = kLSAPConnAccept;
}
break;
default:
DebugLog("TLSAPConn::HandleListenStateEvent: unexpected ctrl opcode");
break;
}
}
}
break;
case kIrPutDataReplyEvent:
{
TIrPutReply *putReply = (TIrPutReply *) GetCurrentEvent();
XTRACE(kListenPutReplyEvent, 0, putReply->fResult);
if (putReply->fResult != noErr) {
DisconnectStart(putReply->fResult);
}
else {
GetControlFrame();
}
}
break;
case kIrDisconnectRequestEvent:
XTRACE(kListenDisconnectRequestEvent, 0, 0);
SaveCurrentRequest();
fState = kLSAPDisconnectPending; PassRequestToLMP();
break;
case kIrDisconnectReplyEvent:
check(event != kIrDisconnectReplyEvent); fState = kLSAPConnDisconnected;
if (InternalDisconnectRequest()) {
XTRACE(kListenDisconnectReplyEvent, 0, fResult);
ConnLstnComplete(fResult);
if (0) { TIrConnLstnRequest *req = (TIrConnLstnRequest*)GetCurrentEvent();
if (req->fPendEvent == kIrListenRequestEvent) { req->fEvent = req->fPendEvent; fPendConnLstn = nil; this->EnqueueEvent(req); }
}
}
else {
XTRACE(kListenDisconnectReplyEvent, 0, 0);
fPendConnLstn = nil; fClient->EnqueueEvent(GetCurrentEvent());
}
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleListenStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleAcceptStateEvent(ULong event)
{
switch (event) {
case kIrAcceptRequestEvent:
XTRACE(kAcceptConnectRequestEvent, 0, 0);
SaveCurrentRequest();
fConnLstnUserData = ((TIrConnLstnRequest*)GetCurrentEvent())->fData;
PutControlFrame(kLMPDUConnectReply, 0);
break;
case kIrDisconnectRequestEvent:
XTRACE(kRejectConnectRequestEvent, 0, 0);
SaveCurrentRequest();
PutControlFrame(kLMPDUDisconnectEvent, kIrUserRequestedDisconnect);
break;
case kIrPutDataReplyEvent:
XTRACE(kAccRejPutReplyEvent, 0, 0);
if (GetCurrentEvent()->fPendEvent == kIrAcceptRequestEvent) {
TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
if (putReply->fResult != noErr) {
DisconnectStart(putReply->fResult);
}
else {
ConnLstnComplete(noErr);
fState = kLSAPConnDataTransferReady;
}
}
else {
XASSERT(GetCurrentEvent()->fPendEvent == kIrDisconnectRequestEvent);
DisconnectStart(noErr);
}
break;
case kIrDisconnectReplyEvent:
check(event != kIrDisconnectReplyEvent); XTRACE(kAccRejDisconnectReplyEvent, 0, fResult);
ConnLstnComplete(fResult);
fState = kLSAPConnDisconnected;
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleAcceptStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleDataTransferReadyStateEvent(ULong event)
{
switch (event) {
case kIrGetDataRequestEvent:
XTRACE(kDTRGetRequestEvent, 0, 0);
SaveCurrentRequest();
GetDataFrame();
break;
case kIrPutDataRequestEvent:
XTRACE(kDTRPutRequestEvent, 0, 0);
SaveCurrentRequest();
PutDataFrame();
break;
case kIrCancelGetRequestEvent:
case kIrCancelPutRequestEvent:
XTRACE(event == kIrCancelGetRequestEvent ? kDTRCancelGetRequestEvent : kDTRCancelPutRequestEvent, 0, 0);
PassRequestToLMP();
break;
case kIrReleaseRequestEvent:
case kIrDisconnectRequestEvent:
XTRACE(event == kIrReleaseRequestEvent ? kDTRReleaseRequestEvent : kDTRDisconnectRequestEvent, 0, 0);
SaveCurrentRequest();
fState = kLSAPDisconnectPending; PutControlFrame(kLMPDUDisconnectEvent, kIrUserRequestedDisconnect);
break;
case kIrGetDataReplyEvent:
{
TIrGetReply* getReply = (TIrGetReply*)GetCurrentEvent();
XTRACE(kDTRGetReplyEvent, getReply->fCtrlOpCode, 0);
if (getReply->fResult != noErr) {
if (getReply->fResult == kIrDAErrRequestCanceled) {
fClient->EnqueueEvent(getReply);
}
else {
DisconnectStart(getReply->fResult);
}
}
else {
switch(getReply->fCtrlOpCode) {
case kLMPDUDataEvent:
fClient->EnqueueEvent(getReply);
break;
case kLMPDUConnectRequest:
PutControlFrame(kLMPDUDisconnectEvent, kIrHalfOpen);
break;
case kLMPDUDisconnectEvent:
DisconnectStart(kIrDAErrGeneric );
break;
default:
DebugLog("TLSAPConn::HandleDataTransferReadyStateEvent: unexpected ctrl opcode");
GetDataFrame(true );
break;
}
}
}
break;
case kIrPutDataReplyEvent:
{
TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
XTRACE(kDTRPutReplyEvent, 0, putReply->fResult);
if (InternalPutRequest()) {
if ((putReply->fPendEvent == kIrReleaseRequestEvent) || (putReply->fPendEvent == kIrDisconnectRequestEvent)) {
DisconnectStart(noErr);
}
else {
XASSERT(putReply->fPendEvent == kIrGetDataRequestEvent);
DisconnectStart(kIrDAErrGeneric );
}
}
else {
fClient->EnqueueEvent(putReply);
}
}
break;
case kIrCancelGetReplyEvent:
case kIrCancelPutReplyEvent:
XTRACE(event == kIrCancelGetReplyEvent ? kDTRCancelGetReplyEvent : kDTRCancelPutReplyEvent, 0, 0);
fClient->EnqueueEvent(GetCurrentEvent());
break;
case kIrDisconnectReplyEvent:
check(event != kIrDisconnectReplyEvent); if (InternalDisconnectRequest()) {
TIrEvent* reply = (TIrEvent*)GetCurrentEvent();
XTRACE(kDTRDisconnectReplyEvent, 0, fResult);
reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);
reply->fResult = fResult;
fClient->EnqueueEvent(reply);
}
else {
TIrDisconnectReply* disconnectReply;
disconnectReply = (TIrDisconnectReply*)GetCurrentEvent();
XTRACE(kDTRDisconnectReplyEvent, 0, disconnectReply->fResult);
fClient->EnqueueEvent(disconnectReply);
}
fPendConnLstn = nil; fState = kLSAPConnDisconnected;
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleDataTransferReadyStateEvent: bad event");
break;
}
}
void TLSAPConn::HandleDisconnectPendingStateEvent(ULong event)
{
TIrEvent* eventBlock = (TIrEvent*)GetCurrentEvent();
XTRACE(kLogDiscPendingEvent, 0, event);
XTRACE(kLogDiscPendingClient, 0, fClient);
switch (event) {
case kIrDisconnectRequestEvent: case kIrConnectRequestEvent:
case kIrListenRequestEvent:
fPendingRequests->InsertLast(GetCurrentEvent());
break;
case kIrAcceptRequestEvent: case kIrGetDataRequestEvent:
case kIrPutDataRequestEvent:
eventBlock->fEvent = (UByte)RequestIdToReplyId(eventBlock->fEvent);
eventBlock->fResult = kIrDAErrNotConnected;
fClient->EnqueueEvent(eventBlock);
break;
case kIrListenReplyEvent:
case kIrConnectReplyEvent:
eventBlock->fResult = kIrDAErrNotConnected; case kIrGetDataReplyEvent:
case kIrPutDataReplyEvent:
XTRACE(kLogDiscPendingMiscReply, event, eventBlock->fPendEvent);
if (GetCurrentEvent() == fPendConnLstn) {
XTRACE(kLogDiscPendingConnLstnDone, 0, fPendConnLstn);
fPendConnLstn = nil; }
eventBlock->fEvent = (UByte)RequestIdToReplyId(eventBlock->fPendEvent);
if (eventBlock->fEvent == kIrDisconnectReplyEvent || eventBlock->fEvent == kIrReleaseReplyEvent) { check(fPendConnLstn == nil); DisconnectStart(noErr); }
else
fClient->EnqueueEvent(eventBlock);
break;
case kIrDisconnectReplyEvent:
if (InternalDisconnectRequest()) {
XTRACE(kLogDiscPendingInternalDisc, eventBlock->fPendEvent, fResult);
if (eventBlock->fPendEvent != kIrConnWatchdogExpiredEvent) { eventBlock->fEvent = (UByte)RequestIdToReplyId(eventBlock->fPendEvent);
eventBlock->fResult = fResult;
fClient->EnqueueEvent(eventBlock);
}
else { DebugLog("IrLSAPConn: just fyi, got disconnect reply after watchdog timeout");
XTRACE(kLogDiscPendingWatchDog, 0, 0);
fIrDA->ReleaseEventBlock(eventBlock);
}
}
else { XTRACE(kLogDiscPendingDiscDone, 0, eventBlock->fResult);
fClient->EnqueueEvent(eventBlock);
}
check(fPendConnLstn == nil); fState = kLSAPConnDisconnected;
if (fPendingRequests && !fPendingRequests->Empty()) {
TIrEvent* request;
CListIterator *iter = CListIterator::cListIterator(fPendingRequests);
for (request = (TIrEvent*)iter->FirstItem();
iter->More(); request = (TIrEvent*)iter->NextItem()) {
XTRACE(kLogDiscPendingRequeue, 0, request->fEvent);
this->EnqueueEvent(request);
}
while (!fPendingRequests->Empty())
fPendingRequests->RemoveLast();
iter->release();
}
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TLSAPConn::HandleDisconnectPendingStateEvent: bad event");
break;
}
}
void TLSAPConn::SaveCurrentRequest()
{
TIrEvent* request = GetCurrentEvent();
request->fPendEvent = request->fEvent;
}
Boolean TLSAPConn::InternalDisconnectRequest()
{
return GetCurrentEvent()->fPendEvent != kIrDisconnectRequestEvent;
}
Boolean TLSAPConn::InternalPutRequest()
{
return GetCurrentEvent()->fPendEvent != kIrPutDataRequestEvent;
}
TIrEvent* TLSAPConn::GetPendConnLstn()
{
return fPendConnLstn;
}
void TLSAPConn::PassRequestToLMP()
{
TIrLSAPConnEvent* theEvent = (TIrLSAPConnEvent*)GetCurrentEvent();
theEvent->fLSAPConn = this;
GetLMP->EnqueueEvent(theEvent);
}
void TLSAPConn::DisconnectStart(IrDAErr result, TIrDisconnectRequest* discRequest)
{
fPendConnLstn = nil;
if (discRequest == nil) {
discRequest = (TIrDisconnectRequest*)GetCurrentEvent();
}
discRequest->fEvent = kIrDisconnectRequestEvent;
discRequest->fResult = kIrDAErrCancel;
discRequest->fLSAPConn = this;
fResult = result;
fState = kLSAPDisconnectPending;
GetLMP->EnqueueEvent(discRequest);
}
void TLSAPConn::GetControlFrame()
{
TIrGetRequest* getRequest = (TIrGetRequest*)GetCurrentEvent();
if (fConnLstnUserData) {
fConnLstnUserData->Reset();
}
getRequest->fEvent = kIrGetDataRequestEvent;
getRequest->fResult = noErr;
getRequest->fData = fConnLstnUserData;
getRequest->fOffset = 0;
getRequest->fLength = fConnLstnUserData ? fConnLstnUserData->GetSize() : 0;
PassRequestToLMP();
}
void TLSAPConn::PutControlFrame(UByte opCode, UByte info)
{
CBuffer* data = nil; TIrPutRequest* putRequest = (TIrPutRequest*)GetCurrentEvent();
if ((opCode == kLMPDUConnectRequest) || (opCode == kLMPDUConnectReply)) {
data = fConnLstnUserData;
}
XASSERT(fPeerLSAPId <= kLastValidLSAPId);
putRequest->fEvent = kIrPutDataRequestEvent;
putRequest->fResult = noErr;
putRequest->fData = data;
putRequest->fOffset = 0;
putRequest->fLength = data ? data->GetSize() : 0;
putRequest->fDstLSAPId = fPeerLSAPId;
putRequest->fSrcLSAPId = fMyLSAPId;
putRequest->fCtrlOpCode = opCode;
putRequest->fCtrlInfo = info;
PassRequestToLMP();
}
void TLSAPConn::GetDataFrame(Boolean resend)
{
TIrGetRequest* getRequest = (TIrGetRequest*)GetCurrentEvent();
if (resend) {
getRequest->fEvent = kIrGetDataRequestEvent;
getRequest->fResult = noErr;
getRequest->fData = fGetData;
getRequest->fOffset = fGetOffset;
getRequest->fLength = fGetLength;
}
else {
fGetData = getRequest->fData;
fGetOffset = getRequest->fOffset;
fGetLength = getRequest->fLength;
}
PassRequestToLMP();
}
void TLSAPConn::PutDataFrame()
{
TIrPutRequest* putRequest = (TIrPutRequest*)GetCurrentEvent();
XASSERT(fPeerLSAPId <= kLastValidLSAPId);
putRequest->fDstLSAPId = fPeerLSAPId;
putRequest->fSrcLSAPId = fMyLSAPId;
putRequest->fCtrlOpCode = kLMPDUDataEvent;
putRequest->fCtrlInfo = 0;
PassRequestToLMP();
}
void TLSAPConn::ConnLstnComplete(IrDAErr result)
{
TIrConnLstnReply* reply = (TIrConnLstnReply*)GetCurrentEvent();
#ifdef forDebug
if ((reply->fPendEvent == kIrConnectRequestEvent) || (reply->fPendEvent == kIrListenRequestEvent)) {
XASSERT(fPendConnLstn != nil);
}
#endif
fPendConnLstn = nil;
if (reply->fPendEvent == kIrConnectRequestEvent) reply->fLSAPId = fLSAPId;
reply->fEvent = (UByte)RequestIdToReplyId(reply->fPendEvent);
reply->fResult = result;
reply->fDevAddr = fDevAddr; fClient->EnqueueEvent(reply);
}
Boolean TLSAPConn::YourData(TLMPDUHeader& header, Boolean justChecking)
{
XTRACE( kMyData, header.fDstLSAPId, fMyLSAPId );
if (header.fDstLSAPId == fMyLSAPId) {
if (header.fSrcLSAPId == fPeerLSAPId) {
XTRACE( kDataForMe, header.fOpCode, header.fSrcLSAPId );
return true;
}
else if (fPeerLSAPId == kPendingConnectLSAPId) {
XASSERT(fState == kLSAPConnListen || fState == kLSAPDisconnectPending);
XTRACE( kDataWaitingForMe, header.fOpCode, header.fSrcLSAPId );
if (header.fOpCode == kLMPDUConnectRequest) {
if (!justChecking) {
fPeerLSAPId = header.fSrcLSAPId;
}
return true;
}
}
}
return false;
}
void TLSAPConn::StartConnectTimer()
{
fWatchdogTimerActive = true;
fWatchdogTimerCount = 0;
GetLMP->StartOneSecTicker();
}
void TLSAPConn::StopConnectTimer()
{
fWatchdogTimerActive = false;
GetLMP->StopOneSecTicker();
}
void TLSAPConn::OneSecTickerComplete()
{
if (!fWatchdogTimerActive) return;
XASSERT(fState == kLSAPConnConnect);
if (++fWatchdogTimerCount >= kWatchdogTimeoutCount) {
NextState(kIrConnWatchdogExpiredEvent);
}
}