#include "IrGlue.h" // includes CommErrors.h
#include "IrIASClient.h"
#include "IrIASService.h"
#include "IrLSAPConn.h"
#include "CBufferSegment.h"
#include "IrDALog.h"
#if (hasTracing > 0 && hasIASClientTracing > 0)
enum IrIASClientTraceCodes
{
kLogNew = 1,
kLogInit,
kLogFree,
kUnexpectedEvent,
kConnectRequestEvent,
kConnectReplyEvent,
kDisconnectRequestEvent,
kDisconnectReplyEvent,
kLookupRequestEvent,
kLookupReplyEvent,
kGetDataRequestEvent,
kGetDataReplyEvent,
kPutDataRequestEvent,
kPutDataReplyEvent,
kSendRequestEvent,
kParseInputEvent,
kLogParseReplyEvent,
kEnqueueEvent,
kDequeueEventStart,
kDequeueEventEnd
};
static
EventTraceCauseDesc TraceEvents[] = {
{kLogNew, "iasclient: create, obj="},
{kLogInit, "iasclient: init"},
{kLogFree, "iasclient: free, obj="},
{kUnexpectedEvent, "iasclient: unexpected event"},
{kConnectRequestEvent, "iasclient: connect request"},
{kConnectReplyEvent, "iasclient: connect reply"},
{kDisconnectRequestEvent, "iasclient: disconnect request"},
{kDisconnectReplyEvent, "iasclient: disconnect reply"},
{kLookupRequestEvent, "iasclient: lookup request"},
{kLookupReplyEvent, "iasclient: lookup reply"},
{kGetDataRequestEvent, "iasclient: get data request"},
{kGetDataReplyEvent, "iasclient: get data reply"},
{kPutDataRequestEvent, "iasclient: put data request"},
{kPutDataReplyEvent, "iasclient: put data reply"},
{kSendRequestEvent, "iasclient: send ias request"},
{kParseInputEvent, "iasclient: parse ias input"},
{kLogParseReplyEvent, "iasclient: parse ias reply, lkupstatus="},
{kEnqueueEvent, "iasclient: Event Queued"},
{kDequeueEventStart, "iasclient: Event Start"},
{kDequeueEventEnd, "iasclient: Event End"}
};
#define XTRACE(x, y, z) IrDALogAdd ( x, y, ((int)z & 0xffff), TraceEvents, true)
#else
#define XTRACE(x, y, z) ((void)0)
#endif
#define super TIrStream
OSDefineMetaClassAndStructors(TIASClient, TIrStream)
TIASClient *
TIASClient::tIASClient(TIrGlue* irda, TIrStream* client)
{
TIASClient *obj = new TIASClient;
XTRACE(kLogNew, (int)obj >> 16, obj);
if (obj && !obj->Init(irda, client)) {
obj->release();
obj = nil;
}
return obj;
}
void TIASClient::free()
{
XTRACE(kLogFree, (int)this >> 16, this);
#define FREE(x) { if (x) { (x)->release(); x = nil; } }
FREE(fLSAPConn);
FREE(fAttribute);
if (fRequestReply) {
fIrDA->ReleaseEventBlock(fRequestReply);
fRequestReply = nil;
}
if (fGetPutBuffer) {
fGetPutBuffer->Delete(); fGetPutBuffer = nil;
}
super::free();
}
Boolean TIASClient::Init(TIrGlue* irda, TIrStream* client)
{
ULong myLSAPId;
IrDAErr result;
XTRACE(kLogInit, (int)this >> 16, this);
fState = kIrIASClientDisconnected;
fReceiveState = kIASClientReceiveReply;
fClient = client;
fLookupRequest = nil;
fLSAPConn = nil;
fRequestReply = nil;
fGetPutBuffer = nil;
fAttribute = nil;
#if (hasTracing > 0 && hasIASClientTracing > 0)
if (!super::Init(irda, TraceEvents, kEnqueueEvent)) return false;
#else
if (!super::Init(irda)) return false;
#endif
fLSAPConn = TLSAPConn::tLSAPConn(irda, this);
require(fLSAPConn, Fail);
fRequestReply = irda->GrabEventBlock();
require(fRequestReply, Fail);
fGetPutBuffer = CBufferSegment::New( kIASClientBufferSize );
XREQUIRE(fGetPutBuffer, Fail);
myLSAPId = kAssignDynamicLSAPId; result = irda->ObtainLSAPId(myLSAPId);
XREQUIRENOT(result, Fail);
fLSAPConn->AssignId(myLSAPId);
return true;
Fail:
return false;
}
void TIASClient::NextState(ULong event)
{
switch (fState) {
case kIrIASClientDisconnected:
HandleDisconnectedStateEvent(event);
break;
case kIrIASClientConnected:
HandleConnectedStateEvent(event);
break;
default:
XTRACE(kUnexpectedEvent, 0, event);
DebugLog("TIASClient::NextState: bad fState");
break;
}
}
void TIASClient::HandleDisconnectedStateEvent(ULong event)
{
switch (event) {
case kIrConnectRequestEvent:
{
XTRACE(kConnectRequestEvent, 0, 0);
TIrConnLstnRequest* connectRequest = (TIrConnLstnRequest*)GetCurrentEvent();
connectRequest->fLSAPId = kNameServerLSAPId;
connectRequest->fData = nil;
fLSAPConn->EnqueueEvent(connectRequest);
}
break;
case kIrConnectReplyEvent:
{
TIrConnLstnReply* connectReply = (TIrConnLstnReply*)GetCurrentEvent();
XTRACE(kConnectReplyEvent, 0, connectReply->fResult);
if (connectReply->fResult == noErr) {
fState = kIrIASClientConnected;
}
fClient->EnqueueEvent(connectReply);
}
break;
case kIrDisconnectRequestEvent:
{
XTRACE(kDisconnectRequestEvent, 0, 0);
fLSAPConn->EnqueueEvent(GetCurrentEvent());
}
break;
case kIrDisconnectReplyEvent:
XTRACE(kDisconnectReplyEvent, 0, 0);
fClient->EnqueueEvent(GetCurrentEvent());
break;
default:
DebugLog("TIASClient::HandleDisconnectedStateEvent: bad event");
break;
}
}
void TIASClient::HandleConnectedStateEvent(ULong event)
{
switch (event) {
case kIrLookupRequestEvent:
{
XTRACE(kLookupRequestEvent, 0, 0);
IrDAErr result = SendRequest();
if (result != noErr) {
LookupComplete(result);
}
}
break;
case kIrPutDataReplyEvent:
{
TIrPutReply* putReply = (TIrPutReply*)GetCurrentEvent();
XTRACE(kPutDataReplyEvent, 0, putReply->fResult);
if (putReply->fResult != noErr) {
LookupComplete(putReply->fResult);
}
else {
GetStart();
}
}
break;
case kIrGetDataReplyEvent:
{
TIrGetReply* getReply = (TIrGetReply*)GetCurrentEvent();
XTRACE(kGetDataReplyEvent, 0, getReply->fResult);
if (getReply->fResult != noErr) {
LookupComplete(getReply->fResult);
}
else {
ParseInput();
}
}
break;
case kIrReleaseRequestEvent:
case kIrDisconnectRequestEvent:
XTRACE(kDisconnectRequestEvent, 1, event);
fLSAPConn->EnqueueEvent(GetCurrentEvent());
break;
case kIrReleaseReplyEvent:
case kIrDisconnectReplyEvent:
XTRACE(kDisconnectReplyEvent, 1, event);
fState = kIrIASClientDisconnected;
fClient->EnqueueEvent(GetCurrentEvent());
break;
default:
DebugLog("TIASClient::HandleConnectedStateEvent: bad event");
break;
}
}
IrDAErr TIASClient::SendRequest()
{
Size classNameLen;
Size attrNameLen;
TIrLookupRequest* lookupRequest = (TIrLookupRequest*)GetCurrentEvent();
XTRACE(kSendRequestEvent, 0, 0);
XASSERT(fLookupRequest == nil);
fLookupRequest = lookupRequest;
classNameLen = strlen((const char*)(lookupRequest->fClassName));
attrNameLen = strlen((const char*)(lookupRequest->fAttrName));
XASSERT((classNameLen + attrNameLen + 3) <= kIASClientBufferSize);
if ((classNameLen + attrNameLen + 3) > kIASClientBufferSize) {
return kIrDAErrBadParameter;
}
fGetPutBuffer->Seek(0, kPosBeg);
fGetPutBuffer->Put(kIASOpGetValueByClass | kIASFrameLstBit);
fGetPutBuffer->Put((UByte)classNameLen);
fGetPutBuffer->Putn((const UByte *)lookupRequest->fClassName, classNameLen);
fGetPutBuffer->Put((UByte)attrNameLen);
fGetPutBuffer->Putn((const UByte *)lookupRequest->fAttrName, attrNameLen);
PutStart();
return noErr;
}
void TIASClient::ParseInput()
{
UByte ctrlByte;
Boolean lastFrame;
Boolean ackedFrame;
IrDAErr result;
fGetPutBuffer->Seek(0, kPosBeg);
ctrlByte = fGetPutBuffer->Get();
lastFrame = ctrlByte & kIASFrameLstBit;
ackedFrame = ctrlByte & kIASFrameAckBit;
XTRACE(kParseInputEvent, ctrlByte, fReceiveState);
switch(fReceiveState) {
case kIASClientReceiveReply:
if (ackedFrame) {
XASSERT(lastFrame);
GetStart();
}
else {
if (ctrlByte == (kIASOpGetValueByClass | kIASFrameLstBit)) {
result = ParseReply();
LookupComplete(result);
}
else if (lastFrame) {
LookupComplete(kIrDAErrGeneric); }
else {
fReceiveState = kIASClientReceiveWaitFinal;
}
}
break;
case kIASClientReceiveWaitFinal:
XASSERT(!ackedFrame);
if (lastFrame) {
fReceiveState = kIASClientReceiveReply;
LookupComplete(kIrDAErrGeneric); }
break;
default:
break;
}
if (fReceiveState == kIASClientReceiveWaitFinal) {
fGetPutBuffer->Seek(0, kPosBeg);
fGetPutBuffer->Put(kIASOpGetValueByClass | kIASFrameAckBit);
PutStart();
}
}
IrDAErr TIASClient::ParseReply()
{
UByte lookupStatus;
lookupStatus = fGetPutBuffer->Get();
require(lookupStatus == kIASRetOkay, Fail);
check(fAttribute == nil);
fAttribute = TIASAttribute::tIASAttribute(fGetPutBuffer);
require(fAttribute, FailNoMem);
return noErr;
Fail:
XTRACE(kLogParseReplyEvent, 0, lookupStatus);
FailNoMem: return kIrDAErrGeneric;
}
void TIASClient::GetStart()
{
XTRACE(kGetDataRequestEvent, 0, 0);
TIrGetRequest* getRequest = (TIrGetRequest*)fRequestReply;
getRequest->fEvent = kIrGetDataRequestEvent;
getRequest->fData = fGetPutBuffer;
getRequest->fOffset = 0;
getRequest->fLength = fGetPutBuffer->GetSize();
fLSAPConn->EnqueueEvent(getRequest);
}
void TIASClient::PutStart()
{
XTRACE(kPutDataRequestEvent, 0, 0);
TIrPutRequest* putRequest = (TIrPutRequest*)fRequestReply;
putRequest->fEvent = kIrPutDataRequestEvent;
putRequest->fData = fGetPutBuffer;
putRequest->fOffset = 0;
putRequest->fLength = fGetPutBuffer->Position();
fLSAPConn->EnqueueEvent(putRequest);
}
void TIASClient::LookupComplete(IrDAErr result)
{
XTRACE(kLookupReplyEvent, 0, result);
if ((result != noErr) && (fAttribute != nil)) {
fAttribute->release();
fAttribute = nil;
}
TIrLookupReply* lookupReply = (TIrLookupReply*)fLookupRequest;
lookupReply->fEvent = kIrLookupReplyEvent;
lookupReply->fResult = result;
lookupReply->fAttribute = fAttribute;
fLookupRequest = nil;
fAttribute = nil;
fClient->EnqueueEvent(lookupReply);
}