#include "IrIASServer.h"
#include "IrIASService.h"
#include "IrEvent.h"
#include "IrLSAPConn.h"
#include "CBufferSegment.h"
#include "IrGlue.h"
#include "IrDALog.h"
#if (hasTracing > 0 && hasIASServerTracing > 0)
enum IrIASServerTraceCodes
{
kNullEvent = 1,
kDestroy,
kInit,
kUnexpectedEvent,
kLogNextState,
kResettingToListenEvent,
kListenRequestEvent,
kListenReplyEvent,
kAcceptRequestEvent,
kAcceptReplyEvent,
kDisconnectRequestEvent,
kDisconnectReplyEvent,
kGetDataRequestEvent,
kGetDataReplyEvent,
kPutDataRequestEvent,
kPutDataReplyEvent,
kSendResponseEvent,
kParseInputEvent,
kParseRequestEvent,
kEnqueueEvent,
kDequeueEventStart,
kDequeueEventEnd
};
EventTraceCauseDesc TraceEvents[] = {
{kNullEvent, "iasserver: create obj="},
{kDestroy, "iasserver: destroy obj="},
{kInit, "iasserver: init"},
{kUnexpectedEvent, "iasserver: unexpected event"},
{kLogNextState, "iasserver: nextstate, result=,event="},
{kResettingToListenEvent, "iasserver: resetting to listen"},
{kListenRequestEvent, "iasserver: listen request"},
{kListenReplyEvent, "iasserver: listen reply"},
{kAcceptRequestEvent, "iasserver: accept request"},
{kAcceptReplyEvent, "iasserver: accept reply"},
{kDisconnectRequestEvent, "iasserver: disconnect request"},
{kDisconnectReplyEvent, "iasserver: disconnect reply"},
{kGetDataRequestEvent, "iasserver: get data request"},
{kGetDataReplyEvent, "iasserver: get data reply"},
{kPutDataRequestEvent, "iasserver: put data request"},
{kPutDataReplyEvent, "iasserver: put data reply"},
{kSendResponseEvent, "iasserver: send ias response"},
{kParseInputEvent, "iasserver: parse ias input"},
{kParseRequestEvent, "iasserver: parse ias request"},
{kEnqueueEvent, "iasserver: Event Queued"},
{kDequeueEventStart, "iasserver: Event Start"},
{kDequeueEventEnd, "iasserver: Event End"}
};
#define XTRACE(x, y, z) IrDALogAdd ( x, y, ((uintptr_t)z & 0xffff), TraceEvents, true)
#else
#define XTRACE(x, y, z) ((void)0)
#endif
#define super TIrStream
OSDefineMetaClassAndStructors(TIASServer, TIrStream);
TIASServer *
TIASServer::tIASServer(TIrGlue* irda, TIASService *nameService)
{
TIASServer *obj = new TIASServer;
XTRACE(kNullEvent, 0, obj);
if (obj && !obj->Init(irda, nameService)) {
obj->release();
obj = nil;
}
return obj;
}
void
TIASServer::free()
{
XTRACE(kDestroy, 0, this);
#define FREE(x) { if (x) { (x)->release(); x = nil; } }
FREE(fLSAPConn);
if (fRequestReply) {
fIrDA->ReleaseEventBlock(fRequestReply);
fRequestReply = nil;
}
if (fGetPutBuffer) {
fGetPutBuffer->Delete(); fGetPutBuffer = nil;
}
super::free();
}
Boolean TIASServer::Init(TIrGlue* irda, TIASService *nameService)
{
XTRACE(kInit, 0, this);
fOpCode = kIASOpUnassigned;
fReceiveState = kIASServerReceiveStart;
fNameService = nil;
fLSAPConn = nil;
fRequestReply = nil;
fGetPutBuffer = nil;
#if (hasTracing > 0 && hasIASServerTracing > 0)
if (!super::Init(irda, TraceEvents, kEnqueueEvent)) return false;
#else
if (!super::Init(irda)) return false;
#endif
fNameService = nameService;
fLSAPConn = TLSAPConn::tLSAPConn(irda, this);
require(fLSAPConn, Fail);
fRequestReply = fIrDA->GrabEventBlock(); require(fRequestReply, Fail);
fGetPutBuffer = CBufferSegment::New(kIASServerBufferSize);
require(fGetPutBuffer, Fail);
fLSAPConn->AssignId(kNameServerLSAPId);
return true;
Fail:
return false;
}
void TIASServer::NextState(ULong event)
{
TIrEvent* reqOrReply = GetCurrentEvent();
XTRACE(kLogNextState, reqOrReply->fResult, event);
require(reqOrReply == (TIrEvent *)fRequestReply, Fail);
if (reqOrReply->fResult != noErr) { if (reqOrReply->fEvent != kIrDisconnectReplyEvent && reqOrReply->fEvent != kIrListenReplyEvent) { XTRACE(kDisconnectRequestEvent, 0, this);
reqOrReply->fEvent = kIrDisconnectRequestEvent; fLSAPConn->EnqueueEvent(reqOrReply);
return;
}
}
switch (event) {
case kIrDisconnectReplyEvent: XTRACE(kResettingToListenEvent, 0, 0);
case kIrListenRequestEvent:
ListenStart(); break;
case kIrListenReplyEvent:
XTRACE(kListenReplyEvent, 0, this);
if (reqOrReply->fResult == noErr) { XTRACE(kAcceptRequestEvent, 0, 0);
TIrConnLstnRequest* acceptRequest = (TIrConnLstnRequest*)GetCurrentEvent();
acceptRequest->fEvent = kIrAcceptRequestEvent;
fLSAPConn->EnqueueEvent(acceptRequest);
}
else { ListenStart();
}
break;
case kIrAcceptReplyEvent:
XTRACE(kAcceptReplyEvent, 0, this);
GetStart();
break;
case kIrPutDataReplyEvent:
XTRACE(kPutDataReplyEvent, 0, this);
GetStart();
break;
case kIrGetDataReplyEvent:
XTRACE(kGetDataReplyEvent, 0, this);
ParseInput();
break;
default:
XTRACE(kUnexpectedEvent, 0, event);
DebugLog("TIASServer::NextState: unknown event");
break;
}
Fail:
return;
}
void TIASServer::ParseInput()
{
UByte ctrlByte;
Boolean lastFrame;
Boolean ackedFrame;
UByte iasReturnCode;
TIASAttribute* iasEntry = nil;
fGetPutBuffer->Seek(0, kPosBeg);
ctrlByte = fGetPutBuffer->Get();
lastFrame = ctrlByte & kIASFrameLstBit;
ackedFrame = ctrlByte & kIASFrameAckBit;
XTRACE(kParseInputEvent, ctrlByte, fReceiveState);
switch(fReceiveState) {
case kIASServerReceiveStart:
if (ackedFrame) {
}
else {
fOpCode = ctrlByte & kIASFrameOpCodeMask;
if (lastFrame) {
if (fOpCode == kIASOpGetValueByClass) {
iasEntry = ParseRequest(iasReturnCode);
}
else {
iasEntry = nil;
iasReturnCode = kIASRetUnsupported;
}
}
else {
fReceiveState = kIASServerReceiveWaitFinal;
}
}
break;
case kIASServerReceiveWaitFinal:
XASSERT(!ackedFrame);
if (lastFrame) {
ackedFrame = false;
iasEntry = nil;
iasReturnCode = fOpCode == kIASOpGetValueByClass ? kIASRetNoSuchClass : kIASRetUnsupported;
}
break;
default:
break;
}
if (lastFrame && !ackedFrame) {
SendResponse(iasReturnCode, iasEntry);
fOpCode = kIASOpUnassigned;
fReceiveState = kIASServerReceiveStart;
}
else if (fReceiveState == kIASServerReceiveWaitFinal) {
fGetPutBuffer->Seek(0, kPosBeg);
fGetPutBuffer->Put(fOpCode | kIASFrameAckBit);
PutStart();
}
else {
GetStart();
}
}
TIASAttribute* TIASServer::ParseRequest(UByte& iasReturnCode)
{
TIASClass* classItem;
TIASAttribute* attrItem;
UChar classString[kIASMaxClassOrAttrStrLen+1];
UChar attrString[kIASMaxClassOrAttrStrLen+1];
iasReturnCode = kIASRetNoSuchClass;
if (!GotAValidString((UChar*)classString)) {
XTRACE(kParseRequestEvent, 4, 0);
return nil;
}
classItem = fNameService->FindClass((const UChar*)classString);
if (classItem == nil) {
XTRACE(kParseRequestEvent, 3, 0);
return nil;
}
iasReturnCode = kIASRetNoSuchAttribute;
if (!GotAValidString((UChar*)attrString)) {
XTRACE(kParseRequestEvent, 2, 0);
return nil;
}
attrItem = classItem->FindAttribute((const UChar*)attrString);
if (attrItem == nil) {
XTRACE(kParseRequestEvent, 1, 0);
return nil;
}
iasReturnCode = kIASRetOkay;
XTRACE(kParseRequestEvent, 0, 0);
return attrItem;
}
Boolean TIASServer::GotAValidString(UChar* theString)
{
UByte nameLength;
nameLength = fGetPutBuffer->Get();
if (nameLength > kIASMaxClassOrAttrStrLen) return false;
if (fGetPutBuffer->Getn(theString, nameLength) != nameLength) return false;
theString[nameLength] = 0;
return true;
}
void TIASServer::SendResponse(UByte iasReturnCode, TIASAttribute* attrEntry)
{
XTRACE(kSendResponseEvent, iasReturnCode, 0);
fGetPutBuffer->Seek(0, kPosBeg);
fGetPutBuffer->Put(fOpCode | kIASFrameLstBit);
fGetPutBuffer->Put(iasReturnCode);
if (iasReturnCode == kIASRetOkay) {
XASSERT(attrEntry != nil);
attrEntry->AddInfoToBuffer(fGetPutBuffer);
}
PutStart();
}
void TIASServer::ListenStart()
{
XTRACE(kListenRequestEvent, 0, this);
TIrConnLstnRequest* listenRequest = (TIrConnLstnRequest*)fRequestReply;
listenRequest->fEvent = kIrListenRequestEvent;
listenRequest->fResult = noErr;
listenRequest->fDevAddr = 0;
listenRequest->fLSAPId = 0;
listenRequest->fMyQOS = fIrDA->GetMyQOS();
listenRequest->fPeerQOS = fIrDA->GetPeerQOS();
listenRequest->fData = nil;
fLSAPConn->EnqueueEvent(listenRequest);
fReceiveState = kIASServerReceiveStart;
}
void TIASServer::GetStart()
{
XTRACE(kGetDataRequestEvent, 0, this);
TIrGetRequest* getRequest = (TIrGetRequest*)fRequestReply;
getRequest->fEvent = kIrGetDataRequestEvent;
getRequest->fData = fGetPutBuffer;
getRequest->fOffset = 0;
getRequest->fLength = fGetPutBuffer->GetSize();
fLSAPConn->EnqueueEvent(getRequest);
}
void TIASServer::PutStart()
{
XTRACE(kPutDataRequestEvent, 0, this);
TIrPutRequest* putRequest = (TIrPutRequest*)fRequestReply;
putRequest->fEvent = kIrPutDataRequestEvent;
putRequest->fData = fGetPutBuffer;
putRequest->fOffset = 0;
putRequest->fLength = fGetPutBuffer->Position();
fLSAPConn->EnqueueEvent(putRequest);
}