1/*
2    File:       IrIASServer.c
3
4    Contains:   Implementation of the TIASServer class
5
6*/
7
8//#include "IrGlue.h"                   // includes CommErrors.h
9
10#include "IrIASServer.h"
11#include "IrIASService.h"
12#include "IrEvent.h"
13#include "IrLSAPConn.h"
14#include "CBufferSegment.h"
15#include "IrGlue.h"
16#include "IrDALog.h"
17
18
19#if (hasTracing > 0 && hasIASServerTracing > 0)
20
21enum IrIASServerTraceCodes
22{
23    kNullEvent = 1,
24    kDestroy,
25    kInit,
26    kUnexpectedEvent,
27    kLogNextState,
28
29    kResettingToListenEvent,
30
31    kListenRequestEvent,
32    kListenReplyEvent,
33    kAcceptRequestEvent,
34    kAcceptReplyEvent,
35    kDisconnectRequestEvent,
36    kDisconnectReplyEvent,
37    kGetDataRequestEvent,
38    kGetDataReplyEvent,
39    kPutDataRequestEvent,
40    kPutDataReplyEvent,
41
42    kSendResponseEvent,
43    kParseInputEvent,
44    kParseRequestEvent,
45
46    kEnqueueEvent,
47    kDequeueEventStart,
48    kDequeueEventEnd
49
50};
51
52EventTraceCauseDesc TraceEvents[] = {
53    {kNullEvent,                    "iasserver: create obj="},
54    {kDestroy,                      "iasserver: destroy obj="},
55    {kInit,                         "iasserver: init"},
56    {kUnexpectedEvent,              "iasserver: unexpected event"},
57    {kLogNextState,                 "iasserver: nextstate, result=,event="},
58
59    {kResettingToListenEvent,       "iasserver: resetting to listen"},
60
61    {kListenRequestEvent,           "iasserver: listen request"},
62    {kListenReplyEvent,             "iasserver: listen reply"},
63    {kAcceptRequestEvent,           "iasserver: accept request"},
64    {kAcceptReplyEvent,             "iasserver: accept reply"},
65    {kDisconnectRequestEvent,       "iasserver: disconnect request"},
66    {kDisconnectReplyEvent,         "iasserver: disconnect reply"},
67    {kGetDataRequestEvent,          "iasserver: get data request"},
68    {kGetDataReplyEvent,            "iasserver: get data reply"},
69    {kPutDataRequestEvent,          "iasserver: put data request"},
70    {kPutDataReplyEvent,            "iasserver: put data reply"},
71
72    {kSendResponseEvent,            "iasserver: send ias response"},
73    {kParseInputEvent,              "iasserver: parse ias input"},
74    {kParseRequestEvent,            "iasserver: parse ias request"},
75
76    {kEnqueueEvent,                 "iasserver: Event Queued"},
77    {kDequeueEventStart,            "iasserver: Event Start"},
78    {kDequeueEventEnd,              "iasserver: Event End"}
79};
80
81
82#define XTRACE(x, y, z) IrDALogAdd ( x, y, ((uintptr_t)z & 0xffff), TraceEvents, true)
83#else
84
85#define XTRACE(x, y, z) ((void)0)
86#endif
87
88
89
90//--------------------------------------------------------------------------------
91#define super TIrStream
92    OSDefineMetaClassAndStructors(TIASServer, TIrStream);
93//--------------------------------------------------------------------------------
94
95//--------------------------------------------------------------------------------
96//      TIASServer
97//--------------------------------------------------------------------------------
98/*static*/
99TIASServer *
100TIASServer::tIASServer(TIrGlue* irda, TIASService *nameService)
101{
102    TIASServer *obj = new TIASServer;
103    XTRACE(kNullEvent, 0, obj);
104
105    if (obj && !obj->Init(irda, nameService)) {
106	obj->release();
107	obj = nil;
108    }
109    return obj;
110}
111
112
113//--------------------------------------------------------------------------------
114//      free
115//--------------------------------------------------------------------------------
116void
117TIASServer::free()
118{
119    XTRACE(kDestroy, 0, this);
120
121#define FREE(x) { if (x) { (x)->release(); x = nil; } }
122
123    FREE(fLSAPConn);                    // free the lsap connection
124
125    if (fRequestReply) {
126	fIrDA->ReleaseEventBlock(fRequestReply);
127	fRequestReply = nil;
128    }
129
130    // Delete the buffer
131    if (fGetPutBuffer) {
132	fGetPutBuffer->Delete();        // jdg: new style buffer release
133	fGetPutBuffer = nil;
134    }
135    super::free();
136
137} // TIASServer::free
138
139
140//--------------------------------------------------------------------------------
141//      Init
142//--------------------------------------------------------------------------------
143Boolean TIASServer::Init(TIrGlue* irda, TIASService *nameService)
144{
145    XTRACE(kInit, 0, this);
146    //int Listen_Start_Commented_Out;
147
148    fOpCode         = kIASOpUnassigned;
149    fReceiveState   = kIASServerReceiveStart;
150
151    fNameService = nil;
152    fLSAPConn = nil;
153    fRequestReply = nil;
154    fGetPutBuffer = nil;
155
156
157    // Init IrStream
158#if (hasTracing > 0 && hasIASServerTracing > 0)
159    if (!super::Init(irda, TraceEvents, kEnqueueEvent)) return false;
160#else
161    if (!super::Init(irda)) return false;
162#endif
163
164    // save name db service
165    fNameService = nameService;
166
167    // need an lsapconn
168    fLSAPConn = TLSAPConn::tLSAPConn(irda, this);
169    require(fLSAPConn, Fail);
170
171    fRequestReply = fIrDA->GrabEventBlock();        // get an event block for us (wait til later?)
172    require(fRequestReply, Fail);
173
174    // Allocate, init a buffer segment
175    fGetPutBuffer = CBufferSegment::New(kIASServerBufferSize);
176    require(fGetPutBuffer, Fail);
177
178    // Claim the well-known NameServer LSAP id
179    fLSAPConn->AssignId(kNameServerLSAPId);
180
181    // Start everything off
182    ////// ListenStart();
183
184    return true;
185
186Fail:
187    return false;
188
189} // TIASServer::Init
190
191
192
193//--------------------------------------------------------------------------------
194//      NextState
195//--------------------------------------------------------------------------------
196void TIASServer::NextState(ULong event)
197{
198    TIrEvent* reqOrReply = GetCurrentEvent();
199
200    XTRACE(kLogNextState, reqOrReply->fResult, event);
201
202    require(reqOrReply == (TIrEvent *)fRequestReply, Fail);
203
204    if (reqOrReply->fResult != noErr) {     // if previous request failed and
205	if (reqOrReply->fEvent != kIrDisconnectReplyEvent &&    // neither a disconnect or listen reply
206	    reqOrReply->fEvent != kIrListenReplyEvent) {            // then let's do a disconnect to clean up
207	    XTRACE(kDisconnectRequestEvent, 0, this);
208	    reqOrReply->fEvent = kIrDisconnectRequestEvent;     // request a disconnect
209	    fLSAPConn->EnqueueEvent(reqOrReply);
210	    return;
211	}
212    }
213
214    switch (event) {
215	case kIrDisconnectReplyEvent:               // disconnect finished, start up a listen again
216	    XTRACE(kResettingToListenEvent, 0, 0);
217	    // fall through
218
219	case kIrListenRequestEvent:
220	    ListenStart();                          // xtrace inside ListenStart()
221	    break;
222
223	case kIrListenReplyEvent:
224	    XTRACE(kListenReplyEvent, 0, this);
225	    if (reqOrReply->fResult == noErr) {         // if listen worked
226		XTRACE(kAcceptRequestEvent, 0, 0);
227		// Send the listen reply back as the accept
228		TIrConnLstnRequest* acceptRequest = (TIrConnLstnRequest*)GetCurrentEvent();
229		acceptRequest->fEvent = kIrAcceptRequestEvent;
230		fLSAPConn->EnqueueEvent(acceptRequest);
231	    }
232	    else {                                  // if it failed, listen again
233		ListenStart();
234	    }
235	    break;
236
237	case kIrAcceptReplyEvent:
238	    XTRACE(kAcceptReplyEvent, 0, this);
239	    GetStart();
240	    break;
241
242	case kIrPutDataReplyEvent:
243	    XTRACE(kPutDataReplyEvent, 0, this);
244	    GetStart();
245	    break;
246
247	case kIrGetDataReplyEvent:
248	    XTRACE(kGetDataReplyEvent, 0, this);
249	    ParseInput();
250	    break;
251
252	default:
253	    XTRACE(kUnexpectedEvent, 0, event);
254	    DebugLog("TIASServer::NextState: unknown event");
255	    break;
256    }
257Fail:
258    return;
259} // TIASServer::NextState
260
261
262//================================ Helper methods ================================
263
264
265//--------------------------------------------------------------------------------
266//      ParseInput
267//--------------------------------------------------------------------------------
268void TIASServer::ParseInput()
269{
270    UByte ctrlByte;
271    Boolean lastFrame;
272    Boolean ackedFrame;
273    UByte iasReturnCode;
274    TIASAttribute* iasEntry = nil;
275
276    // An operation frame has been received - parse it and decide what to do with it
277
278    fGetPutBuffer->Seek(0, kPosBeg);
279    ctrlByte = fGetPutBuffer->Get();
280    lastFrame = ctrlByte & kIASFrameLstBit;
281    ackedFrame = ctrlByte & kIASFrameAckBit;
282
283    XTRACE(kParseInputEvent, ctrlByte, fReceiveState);
284
285    switch(fReceiveState) {
286	case kIASServerReceiveStart:
287	    if (ackedFrame) {
288		// Must be an ack from my previous response (or some other bogus data)
289		// Keep looking
290	    }
291	    else {
292		fOpCode = ctrlByte & kIASFrameOpCodeMask;
293		if (lastFrame) {
294		    if (fOpCode == kIASOpGetValueByClass) {
295			iasEntry = ParseRequest(iasReturnCode);
296		    }
297		    else {
298			iasEntry = nil;
299			iasReturnCode = kIASRetUnsupported;
300		    }
301		}
302		else {
303		    fReceiveState = kIASServerReceiveWaitFinal;
304		}
305	    }
306	    break;
307
308	case kIASServerReceiveWaitFinal:
309	    // I didn't accept the request, so all I want to do is get the
310	    // final frame of the request so I can reject it.
311	    XASSERT(!ackedFrame);
312	    if (lastFrame) {
313		// I don't really care if they sent an ack w/final, so ignore it
314		ackedFrame = false;
315
316		// Return no such class for too large get value by class requests
317		// Return unsupported for all other requests
318		iasEntry = nil;
319		iasReturnCode = fOpCode == kIASOpGetValueByClass ? kIASRetNoSuchClass : kIASRetUnsupported;
320	    }
321	    break;
322
323	default:
324	    break;
325    }
326
327    // Either respond to the current request or continue accepting more of the request
328    if (lastFrame && !ackedFrame) {
329	// Reply to the request
330	SendResponse(iasReturnCode, iasEntry);
331
332	// Reset the receive state
333	fOpCode = kIASOpUnassigned;
334	fReceiveState = kIASServerReceiveStart;
335    }
336    else if (fReceiveState == kIASServerReceiveWaitFinal) {
337	// Ack the frame I don't want/care about
338	fGetPutBuffer->Seek(0, kPosBeg);
339	fGetPutBuffer->Put(fOpCode | kIASFrameAckBit);
340	PutStart();
341    }
342    else {
343	// Post another get
344	GetStart();
345    }
346
347} // TIASServer::ParseInput
348
349
350//--------------------------------------------------------------------------------
351//      ParseRequest
352//--------------------------------------------------------------------------------
353TIASAttribute* TIASServer::ParseRequest(UByte& iasReturnCode)
354{
355    TIASClass* classItem;
356    TIASAttribute* attrItem;
357    //UChar theString[kIASMaxClassOrAttrStrLen+1];
358    UChar classString[kIASMaxClassOrAttrStrLen+1];
359    UChar attrString[kIASMaxClassOrAttrStrLen+1];
360
361    // Prepare return for ill-formed class string or class not found
362    iasReturnCode = kIASRetNoSuchClass;
363
364    // Get the class string
365    if (!GotAValidString((UChar*)classString)) {
366	XTRACE(kParseRequestEvent, 4, 0);
367	return nil;
368    }
369
370    // Look up the class
371    classItem = fNameService->FindClass((const UChar*)classString);
372    if (classItem == nil) {
373	XTRACE(kParseRequestEvent, 3, 0);
374	return nil;
375    }
376
377    // Prepare return for ill-formed attribute string or attribute not found
378    iasReturnCode = kIASRetNoSuchAttribute;
379
380    // Get the attribute string
381    if (!GotAValidString((UChar*)attrString)) {
382	XTRACE(kParseRequestEvent, 2, 0);
383	return nil;
384    }
385
386    // Look up the attribute
387    attrItem = classItem->FindAttribute((const UChar*)attrString);
388    if (attrItem == nil) {
389	//DebugPrintf("ias server, class '%s' attr '%s' not found",
390	//                                  classString, attrString);
391	XTRACE(kParseRequestEvent, 1, 0);
392	return nil;
393    }
394
395    // Found the attribute
396    iasReturnCode = kIASRetOkay;
397    XTRACE(kParseRequestEvent, 0, 0);
398    return attrItem;
399
400} // TIASServer::ParseRequest
401
402
403//--------------------------------------------------------------------------------
404//      GotAValidString
405//--------------------------------------------------------------------------------
406Boolean TIASServer::GotAValidString(UChar* theString)
407{
408    // In this case, a valid string is one that is less than kIASMaxClassOrAttrStrLen
409    // and is contained entirely within the current receive buffer.
410    UByte nameLength;
411
412    // Get the class string length
413    nameLength = fGetPutBuffer->Get();
414    if (nameLength > kIASMaxClassOrAttrStrLen) return false;
415
416    // Get the class string
417    if (fGetPutBuffer->Getn(theString, nameLength) != nameLength) return false;
418
419    // Null terminate the string
420    theString[nameLength] = 0;
421
422    return true;
423
424} // TIASServer::GotAValidString
425
426
427//--------------------------------------------------------------------------------
428//      SendResponse
429//--------------------------------------------------------------------------------
430void TIASServer::SendResponse(UByte iasReturnCode, TIASAttribute* attrEntry)
431{
432    XTRACE(kSendResponseEvent, iasReturnCode, 0);
433
434    // Do the header common to all types of responses
435    fGetPutBuffer->Seek(0, kPosBeg);
436    fGetPutBuffer->Put(fOpCode | kIASFrameLstBit);
437    fGetPutBuffer->Put(iasReturnCode);
438
439    // Have the attribute object and its elements add their data to the buffer
440    if (iasReturnCode == kIASRetOkay) {
441	XASSERT(attrEntry != nil);
442	attrEntry->AddInfoToBuffer(fGetPutBuffer);
443    }
444
445    PutStart();
446
447} // TIASServer::SendResponse
448
449
450//--------------------------------------------------------------------------------
451//      ListenStart
452//--------------------------------------------------------------------------------
453void TIASServer::ListenStart()
454{
455    XTRACE(kListenRequestEvent, 0, this);
456
457    TIrConnLstnRequest* listenRequest = (TIrConnLstnRequest*)fRequestReply;
458    listenRequest->fEvent = kIrListenRequestEvent;
459    listenRequest->fResult = noErr;
460    listenRequest->fDevAddr = 0;
461    listenRequest->fLSAPId = 0;
462    listenRequest->fMyQOS = fIrDA->GetMyQOS();
463    listenRequest->fPeerQOS = fIrDA->GetPeerQOS();
464    listenRequest->fData = nil;
465    fLSAPConn->EnqueueEvent(listenRequest);
466
467    fReceiveState = kIASServerReceiveStart;
468
469} // TIASServer::ListenStart
470
471
472//--------------------------------------------------------------------------------
473//      GetStart
474//--------------------------------------------------------------------------------
475void TIASServer::GetStart()
476{
477    XTRACE(kGetDataRequestEvent, 0, this);
478
479    TIrGetRequest* getRequest = (TIrGetRequest*)fRequestReply;
480    getRequest->fEvent = kIrGetDataRequestEvent;
481    getRequest->fData = fGetPutBuffer;
482    getRequest->fOffset = 0;
483    getRequest->fLength = fGetPutBuffer->GetSize();
484    fLSAPConn->EnqueueEvent(getRequest);
485
486} // TIASServer::GetStart
487
488
489//--------------------------------------------------------------------------------
490//      PutStart
491//--------------------------------------------------------------------------------
492void TIASServer::PutStart()
493{
494    XTRACE(kPutDataRequestEvent, 0, this);
495
496    TIrPutRequest* putRequest = (TIrPutRequest*)fRequestReply;
497    putRequest->fEvent = kIrPutDataRequestEvent;
498    putRequest->fData = fGetPutBuffer;
499    putRequest->fOffset = 0;
500    putRequest->fLength = fGetPutBuffer->Position();
501    fLSAPConn->EnqueueEvent(putRequest);
502
503} // TIASServer::PutStart
504
505