1/*
2    File:       CIrLSAP.c
3
4    Contains:   IrDA client routines for TinyTP (and others)
5
6
7*/
8
9
10#include "CIrLSAP.h"
11#include "IrIASClient.h"
12#include "IrIASService.h"
13#include "IrGlue.h"
14#include "IrLSAPConn.h"
15#include "CBufferSegment.h"
16#include "IrDALog.h"
17
18#if (hasTracing > 0 && hasIrLSAPTracing > 0)
19
20enum IrLSAPTraceCodes
21{
22    kLogNew = 1,
23    kLogFree,
24    kLogInit,
25
26    kUnexpectedEvent,
27
28    kDiscoverStartEvent,
29    kDiscoverCompleteEvent,
30    kLogDiscoverCompleteErr,
31
32    kLookupStartEvent,
33    kNSClientConnectedEvent,
34    kNSClientLookupReplyEvent,
35    kNSClientLookupDisconnectEvent,
36    kLookupCompleteEvent,
37
38    kConnectStartEvent,
39    kConnectCompleteEvent,
40
41    kListenStartEvent,
42    kListenCompleteEvent,
43    kLogListenCompleteErr,
44
45    kAcceptStartEvent,
46    kAcceptCompleteEvent,
47
48    kGetStartEvent,
49    kGetCompleteEvent,
50
51    kPutStartEvent,
52    kPutCompleteEvent,
53
54    kDisconnectStartEvent,
55    kDisconnectCompleteEvent,
56
57    kGetBackFromGrabEvent,
58    kGetAboutToEnqueueEvent,
59    kGetBackFromEnqueue,
60    kCheckCBOk,
61    kCheckCBBad,
62    kLSAPEventProcess,
63
64    kCancelPuts,
65    kCancelGets,
66    kCancelPutsComplete,
67    kCancelGetsComplete,
68
69    kEnqueueEvent,
70    kDequeueEventStart,
71    kDequeueEventEnd
72
73};
74
75static
76EventTraceCauseDesc gTraceEvents[] = {
77    {kLogNew,                       "CIrLSAP: new obj="},
78    {kLogFree,                      "CIrLSAP: free obj="},
79    {kLogInit,                      "CIrLSAP: init, obj=,lsapid="},
80
81    {kUnexpectedEvent,              "CIrLSAP: unexpected event"},
82
83    {kDiscoverStartEvent,           "CIrLSAP: Discover request"},
84    {kDiscoverCompleteEvent,        "CIrLSAP: Discover reply"},
85    {kLogDiscoverCompleteErr,       "CirLSAP: Discover reply ERROR"},
86
87    {kLookupStartEvent,             "CIrLSAP: Lookup request"},
88    {kNSClientConnectedEvent,       "CIrLSAP: Lookup IAS Client Connected"},
89    {kNSClientLookupReplyEvent,     "CIrLSAP: Lookup IAS Client Reply"},
90    {kNSClientLookupDisconnectEvent,"CIrLSAP: Lookup IAS Client Disconnected"},
91    {kLookupCompleteEvent,          "CIrLSAP: Lookup complete"},
92
93    {kConnectStartEvent,            "CIrLSAP: Connect request"},
94    {kConnectCompleteEvent,         "CIrLSAP: Connect reply"},
95
96    {kListenStartEvent,             "CIrLSAP: Listen request"},
97    {kListenCompleteEvent,          "CIrLSAP: Listen reply"},
98    {kLogListenCompleteErr,         "CIrLSAP: Listen reply ERROR"},
99
100    {kAcceptStartEvent,             "CIrLSAP: Accept request"},
101    {kAcceptCompleteEvent,          "CIrLSAP: Accept reply"},
102
103    {kGetStartEvent,                "CIrLSAP: Get request"},
104    {kGetCompleteEvent,             "CIrLSAP: Get reply"},
105    {kPutStartEvent,                "CIrLSAP: Put request"},
106    {kPutCompleteEvent,             "CIrLSAP: Put reply"},
107
108    {kDisconnectStartEvent,         "CIrLSAP: Disconnect request"},
109    {kDisconnectCompleteEvent,      "CIrLSAP: Disconnect complete"},
110
111    {kGetBackFromGrabEvent,         "CIrLSAP: Get req back from grab event block"},
112    {kGetAboutToEnqueueEvent,       "CIrLSAP: Get req about to enqueue event"},
113    {kGetBackFromEnqueue,           "CIrLSAP: Get req back from enqueue event"},
114    {kCheckCBOk,                    "CIrLSAP: check of CB looks ok"},
115    {kCheckCBBad,                   "CIrLSAP: check of CB failed!"},
116    {kLSAPEventProcess,             "CIrLSAP: Next State, event, state" },
117
118    {kCancelPuts,                   "CIrLSAP: cancel pending puts"},
119    {kCancelGets,                   "CIrLSAP: cancel pending gets"},
120    {kCancelPutsComplete,           "CIrLSAP: cancel puts done"},
121    {kCancelGetsComplete,           "CIrLSAP: cancel gets done"},
122
123    {kEnqueueEvent,                 "CIrLSAP: Event Queued"},       // these 3 need to stay in order
124    {kDequeueEventStart,            "CIrLSAP: Event Start"},
125    {kDequeueEventEnd,              "CIrLSAP: Event End"}
126
127
128
129};
130
131#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, gTraceEvents, true )
132
133#else
134    #define XTRACE(x, y, z) ((void)0)
135#endif
136
137
138#define super TIrStream
139    OSDefineMetaClassAndAbstractStructors(CIrLSAP, TIrStream);
140
141
142void
143CIrLSAP::free()
144{
145    TIASService  *nameService;      // glue's name service (if any)
146
147    XTRACE(kLogFree, 0, this);
148
149    if (fIrDA) {
150	nameService = fIrDA->GetNameService();      // get existing name service
151	if (nameService) {                          // if it exists, let's un-register outselves from IAS
152	    nameService->RemoveAttribute(fClassName, fAttrName, kIASDeleteAttribute);
153	}
154    }
155
156    if (fDscInfo)
157	fDscInfo->RemoveServiceHints(fHints);
158
159    if (fLSAP) {                // glue made this for us, but we need to release it
160	fLSAP->release();
161	fLSAP = nil;
162    }
163    else {                      // else lsapconn never alloc'd so WE need to release the lsap id
164	if (fIrDA)                              // sanity check
165	    fIrDA->ReleaseLSAPId(fMyLSAPId);    // cause lsapconn delete is what normally frees our lsap id
166    }
167
168    if (fNameClient) {                  // jdg: delete name client when we go away
169	fNameClient->release();
170	fNameClient = nil;
171    }
172
173    super::free();
174}
175
176
177Boolean CIrLSAP::Init(TIrGlue *irda, UInt32 desiredLSAPId, UInt8 * className, UInt8 * attributeName, ULong hints)
178{
179    IrDAErr err;
180
181    XTRACE(kLogInit, 0, this);
182    XTRACE(kLogInit, 0, desiredLSAPId);
183
184    fState          = kIrLSAPDisconnected;
185    fPeerAddr       = 0;
186    fMyLSAPId       = kAssignDynamicLSAPId;
187    fPeerLSAPId     = 0;
188
189    fClassName[0]   = 0;                        // ClassName is null string
190    fAttrName[0]    = 0;                        // attr name to null string
191    fConnectClassName[0] = 0;
192    fAttributeName[0] = 0;                      // peer names
193    fHints          = 0;
194
195    fConnected      = false;
196
197    fDiscoverCount = 0;
198    fDscInfo        = nil;
199
200    fNameClient     = nil;
201    fLSAP           = nil;
202    fDiscovery      = nil;
203    fPendingDisconnect  = false;
204    fDisconnectRequest = nil;       // jdg: disconnect request event we alloc'd
205
206
207#if (hasTracing > 0 && hasIrLSAPTracing > 0)
208    if (!super::Init(irda, gTraceEvents, kEnqueueEvent)) return false;
209#else
210    if (!super::Init(irda)) return false;
211#endif
212
213    fDiscovery = fIrDA->GetDiscovery();         // get the discovery stream client from glue
214    require(fDiscovery, Fail);                  // this could be deferred until later, but ...
215
216    fDscInfo = fDiscovery->GetDiscoveryInfo();  // get our own discovery info
217    require(fDscInfo, Fail);
218
219    fHints = hints;                             // remember our ("new") hint bits for clear later
220    fDscInfo->SetServiceHints(fHints);          // add our hits to the system's hint bits
221
222    fMyLSAPId = desiredLSAPId;
223
224    if (className)
225	strlcpy((char *)&fClassName[0], (char *)className, sizeof(fClassName));
226    if (attributeName)
227	strlcpy((char * )&fAttrName[0], (char *)attributeName, sizeof(fAttrName));
228
229
230    // FIXME - this should only be done if we set up a listener
231    err = fIrDA->RegisterMyNameAndLSAPId(fClassName, fAttrName, &fMyLSAPId);
232    nrequire(err, Fail);
233
234    XTRACE(kLogInit, 1, fMyLSAPId);
235
236    return true;
237
238Fail:
239    return false;
240
241} // CIrLSAP::InitCIrLSAP
242
243#pragma mark Client Accessors
244//--------------- Client Accessors ---------------
245
246void CIrLSAP::SetPeerLAPAddr( UInt32 addr )
247{
248    if( ! fConnected )          // This only makes sense before a connection is
249	fPeerAddr = addr;       // established.
250}
251
252
253#pragma mark Client Methods
254//--------------- Client Methods ---------------
255
256//--------------------------------------------------------------------------------------------
257//
258//  Discover:   Initiates a LAP XID Discovery
259//
260//--------------------------------------------------------------------------------------------
261IrDAErr CIrLSAP::Discover( UInt32 slots )
262{
263    TIrDiscoverRequest * request;
264
265    XTRACE(kDiscoverStartEvent, 0, this);
266
267    if (GetState() != kIrLSAPDisconnected) {    // sanity check
268	XTRACE(kDiscoverStartEvent, 0xffff, GetState());
269	return kIrDAErrWrongState;                  // bail if invalid state
270    }
271
272    request = (TIrDiscoverRequest *)fIrDA->GrabEventBlock(kIrDiscoverRequestEvent, sizeof(TIrDiscoverRequest));
273    require( request, Fail_NewDiscoverRequest );
274
275    request->fNumSlots  = slots;
276    request->fClient    = this;
277
278    SetState( kIrLSAPDiscoverStart);
279    fDiscovery->EnqueueEvent( request );
280
281    return noErr;
282
283Fail_NewDiscoverRequest:
284    return kIrDAErrNoMemory;
285
286} // CIrLSAP::Discover
287
288//--------------------------------------------------------------------------------------------
289//
290//  LSAPLookup: Queries remote device for an LSAP id of requested service
291//
292//--------------------------------------------------------------------------------------------
293
294IrDAErr CIrLSAP::LSAPLookup(UInt8 * className, UInt8 * attributeName, UInt32 remoteAddr)
295{
296
297    TIrConnLstnRequest  *   connectRequest;
298
299    XTRACE( kLookupStartEvent, remoteAddr >> 16, remoteAddr );
300
301    if (GetState() != kIrLSAPDisconnected) {    // sanity check
302	XTRACE(kLookupStartEvent, 0xffff, GetState());
303	return kIrDAErrWrongState;                  // bail if invalid state
304    }
305
306    fPeerAddr = remoteAddr;         // FIXME Client should supply address with connect request
307
308    // Save connect class name until we have connected to the peer devs name server
309    strlcpy( ( char * )&fConnectClassName, ( const char * )className, sizeof(fConnectClassName));
310    strlcpy( ( char * )&fAttributeName, ( const char * )attributeName, sizeof(fAttributeName));
311
312    // Create, init name server client
313    if (fNameClient == nil) {                       // jdg: if first time we've done a lookup
314	fNameClient = TIASClient::tIASClient(fIrDA, this);  // make an IAS name client to use
315	require( fNameClient, Fail_NewNameClient );
316    }
317
318    connectRequest = (TIrConnLstnRequest*)fIrDA->GrabEventBlock(kIrConnectRequestEvent, sizeof(TIrConnLstnRequest));
319    require( connectRequest, Fail_NewConnectRequest );
320
321    // Connect to name server on peer device
322    connectRequest->fDevAddr    = remoteAddr;
323    connectRequest->fMyQOS      = fIrDA->GetMyQOS();
324    connectRequest->fPeerQOS    = fIrDA->GetPeerQOS();
325    connectRequest->fData       = nil;
326    connectRequest->fClient     = this;
327
328    SetState( kIrLSAPLookupStart );                     // now doing a lookup
329    fNameClient->EnqueueEvent(connectRequest);
330    return noErr;
331
332    // Out of memory error exit points
333
334Fail_NewConnectRequest:
335Fail_NewNameClient:
336    return kIrDAErrNoMemory;
337} // CIrLSAP::LSAPLookup
338
339
340//--------------------------------------------------------------------------------------------
341//
342//  Connect:    Attempts to connect to remote device
343//
344//--------------------------------------------------------------------------------------------
345
346IrDAErr CIrLSAP::Connect( UInt32 remoteAddr, UInt32 lsapID, CBufferSegment *connectData )
347{
348    fPeerAddr = remoteAddr;
349    return this->Connect(lsapID, connectData);
350}
351
352IrDAErr CIrLSAP::Connect( UInt32 lsapID, CBufferSegment *connectData )
353{
354    fPeerLSAPId = lsapID;               // Punch in the user's lsap id and then connect
355    return this->Connect(connectData);
356}
357
358IrDAErr CIrLSAP::Connect( CBufferSegment *connectData )
359{
360    IrDAErr err;
361    XTRACE( kConnectStartEvent, fPeerLSAPId, fPeerAddr );
362    XTRACE( kConnectStartEvent, 0, this );
363
364    if (GetState() != kIrLSAPDisconnected) {    // sanity check
365	XTRACE(kConnectStartEvent, 0xffff, GetState());
366	return kIrDAErrWrongState;                  // bail if invalid state
367    }
368
369    SetState(kIrLSAPConnectStart);
370    // TODO --- allocate the lsapconn in our init and bypass glue here
371    err = fIrDA->ConnectStart(  this, fMyLSAPId, fPeerAddr, fPeerLSAPId,
372				    connectData, &fLSAP );
373
374    if (err != noErr) {                     // if connect start failed
375	SetState(kIrLSAPDisconnected);      // not connecting, we're disconnected
376    }
377    return err;
378
379} // CIrLSAP::Connect
380
381
382
383//--------------------------------------------------------------------------------------------
384//
385//  DataPut:    Writes one packet of data.
386//
387//--------------------------------------------------------------------------------------------
388
389IrDAErr CIrLSAP::DataPut( CBufferSegment * putBuffer )
390{
391    TIrPutRequest *putRequest;
392    XTRACE( kPutStartEvent, fMyLSAPId, fPeerLSAPId );
393    XTRACE( kPutStartEvent, 0, this );
394    XTRACE( kPutStartEvent, 0, putBuffer);
395
396    if (GetState() != kIrLSAPConnected) {
397	XTRACE(kPutStartEvent, 0xffff, GetState());
398	return kIrDAErrWrongState;                  // bail if invalid state
399    }
400    check(fConnected == true);  // checks should all pass since we're connected
401    check(putBuffer);
402    check(fLSAP);
403
404    fLastPutBuffer = putBuffer;         // temp debugging
405    putRequest = ( TIrPutRequest * )fIrDA->GrabEventBlock(kIrPutDataRequestEvent, sizeof(TIrPutRequest));
406    require( putRequest, AllocatePutRequestBlock );
407
408    putRequest->fData   = putBuffer;
409    putRequest->fOffset = 0;
410    putRequest->fLength = putBuffer->GetSize();
411    putRequest->fClient = this;
412    fLSAP->EnqueueEvent( putRequest );
413    return noErr;
414
415AllocatePutRequestBlock:
416
417    return kIrDAErrNoMemory;
418} // CIrLSAP::DataPut
419
420
421
422//--------------------------------------------------------------------------------------------
423//
424//  DataGet:    Reads one packet of data.
425//
426//--------------------------------------------------------------------------------------------
427
428
429IrDAErr CIrLSAP::DataGet( CBufferSegment * getBuffer )
430{
431    TIrGetRequest *getRequest;
432    XTRACE( kGetStartEvent, fMyLSAPId, fPeerLSAPId );
433    XTRACE( kGetStartEvent, 0, this );
434
435    if (GetState() != kIrLSAPConnected) {
436	XTRACE(kGetStartEvent, 0xffff, GetState());
437	return kIrDAErrWrongState;                  // bail if invalid state
438    }
439    check(getBuffer);
440
441    getRequest = ( TIrGetRequest * )fIrDA->GrabEventBlock(kIrGetDataRequestEvent, sizeof(TIrGetRequest));
442    require( getRequest, AllocatePutRequestBlock );
443
444    getRequest->fData   = getBuffer;
445    getRequest->fOffset = 0;
446    getRequest->fLength = getBuffer->GetSize();
447    getRequest->fClient = this;
448
449    fLSAP->EnqueueEvent( getRequest );
450
451    return noErr;
452
453AllocatePutRequestBlock:
454
455    return kIrDAErrNoMemory;
456} // CIrLSAP::DataGet
457
458
459
460//--------------------------------------------------------------------------------------------
461//
462//  Listen: Waits for a connection attempt from a remote device
463//
464//--------------------------------------------------------------------------------------------
465
466IrDAErr CIrLSAP::Listen(CBufferSegment *connectData)
467{
468    IrDAErr err;
469
470    XTRACE( kListenStartEvent, 0, fMyLSAPId);
471    XTRACE( kListenStartEvent, 0, this);
472    XTRACE( kListenStartEvent, 0, connectData);
473
474    if (GetState() != kIrLSAPDisconnected) {    // sanity check
475	XTRACE(kListenStartEvent, 0xffff, GetState());
476	return kIrDAErrWrongState;                  // bail if invalid state
477    }
478
479    fLastListenBuffer = connectData;        // temp debugging
480    SetState( kIrLSAPListenStart );
481    // TODO - get rid of glue
482    err = fIrDA->ListenStart( this, fMyLSAPId, connectData, &fLSAP );
483    if (err != noErr) {                     // if listen start failed
484	SetState(kIrLSAPDisconnected);      // not listening, we're disconnected
485    }
486    return err;
487
488} // CIrLSAP::Listen
489
490
491
492//--------------------------------------------------------------------------------------------
493//
494//  Accept: Accepts the remote devices connection attempt (or not)
495//
496//--------------------------------------------------------------------------------------------
497
498IrDAErr CIrLSAP::Accept(CBufferSegment *connectData)
499{
500    TIrConnLstnRequest  *acceptRequest;
501
502    XTRACE( kAcceptStartEvent, fMyLSAPId, fPeerLSAPId);
503    XTRACE( kAcceptStartEvent, fPeerAddr>>16, fPeerAddr );
504    XTRACE( kAcceptStartEvent, (uintptr_t)this>>16, this);
505
506    if (GetState() != kIrLSAPListenComplete) {  // sanity check
507	XTRACE(kAcceptStartEvent, 0xffff, GetState());
508	return kIrDAErrWrongState;                  // bail if invalid state
509    }
510
511    acceptRequest = ( TIrConnLstnRequest*)  fIrDA->GrabEventBlock(  kIrAcceptRequestEvent,
512							    sizeof( TIrConnLstnRequest ) );
513    require( acceptRequest, Fail_NewAcceptRequest );
514
515    SetState( kIrLSAPAcceptStart );
516    acceptRequest->fData = connectData;
517    fLSAP->EnqueueEvent( acceptRequest );
518
519    return noErr;
520
521Fail_NewAcceptRequest:
522    //Disconnect();         // jdg: if out of events, disconnect request will fail too
523    return kIrDAErrNoMemory;
524
525} // CIrLSAP::Accept
526
527
528
529//--------------------------------------------------------------------------------------------
530//
531//  DoDisconnect:   Disconnects the LSAP from remote
532//
533//--------------------------------------------------------------------------------------------
534
535void CIrLSAP::Disconnect()
536{
537    //TIrDisconnectRequest *disconnectRequest;
538
539    XTRACE( kDisconnectStartEvent, fMyLSAPId, fPeerLSAPId );
540    XTRACE( kDisconnectStartEvent, 0, this );
541
542    if (GetState() == kIrLSAPDisconnected) {        // if we're already disconnected
543	check(fConnected == false);                 // sanity check
544	XTRACE(kDisconnectStartEvent, 0xffff, GetState());
545	DisconnectComplete();                       // !! virtual callback to client (hmm)
546	return;                         // !! could do away w/above cb if we returned an err
547    }
548
549    // JDG: if we're in the middle of a discover or lookup, wait until they finish
550    // before doing a disconnect
551    if (GetState() == kIrLSAPDiscoverStart || GetState() == kIrLSAPLookupStart) {
552	fPendingDisconnect = true;
553	return;
554    }
555
556    // and if we've already issued a disconnect request on this, another
557    // one is just a nop
558    if (GetState() == kIrLSAPDisconnectStart)
559	return;                         // should return an error here
560
561    check(fDisconnectRequest == nil);   // shouldn't have a disconnect pending yet
562    fDisconnectRequest = (TIrDisconnectRequest*) fIrDA->GrabEventBlock(kIrDisconnectRequestEvent,
563								sizeof(TIrDisconnectRequest));
564    if (fDisconnectRequest == nil)      // out of memory
565	return;                         // should return an error code
566
567    SetState( kIrLSAPDisconnectStart );
568    fLSAP->EnqueueEvent(fDisconnectRequest);
569    return;
570
571} // CIrLSAP::Disconnect
572
573//--------------------------------------------------------------------------------------------
574//
575//  CancelPuts: Aborts all pending puts.
576//
577//--------------------------------------------------------------------------------------------
578
579IrDAErr CIrLSAP::CancelPuts( void )
580{
581    TIrCancelPutEvent *cancelRequest;
582    XTRACE( kCancelPuts, 0, this);
583
584    if (GetState() != kIrLSAPConnected) {   // if we're not connected
585	XTRACE(kCancelPuts, 0xffff, GetState());
586	return kIrDAErrWrongState;                  // bail if invalid state
587    }
588
589    cancelRequest = (TIrCancelPutEvent *)fIrDA->GrabEventBlock(kIrCancelPutRequestEvent,
590							    sizeof(TIrCancelPutEvent));
591    require(cancelRequest, AllocatePutRequestBlock);
592
593    cancelRequest->fClient = this;
594    fLSAP->EnqueueEvent(cancelRequest);
595
596    return noErr;
597
598AllocatePutRequestBlock:
599
600    return kIrDAErrNoMemory;
601
602}   // CIrLSAP::CancelPuts
603
604//--------------------------------------------------------------------------------------------
605//
606//  CancelGets: Aborts all pending gets.
607//
608//--------------------------------------------------------------------------------------------
609
610IrDAErr CIrLSAP::CancelGets( void )
611{
612    TIrCancelGetEvent *cancelRequest;
613
614    XTRACE( kCancelGets, 0, this);
615
616    if (GetState() != kIrLSAPConnected) {       // if we're not connected
617	XTRACE(kCancelGets, 0xffff, GetState());
618	return kIrDAErrWrongState;                  // bail if invalid state
619    }
620
621    cancelRequest = (TIrCancelGetEvent *)fIrDA->GrabEventBlock(kIrCancelGetRequestEvent,
622							    sizeof(TIrCancelGetEvent));
623    require(cancelRequest, AllocateRequestBlock);
624
625    cancelRequest->fClient = this;
626    fLSAP->EnqueueEvent(cancelRequest);
627
628    return noErr;
629
630AllocateRequestBlock:
631
632    return kIrDAErrNoMemory;
633
634}   // CIrLSAP::CancelGets
635
636
637#pragma mark
638//--------------- Internal Event Handlers ---------------
639
640//--------------------------------------------------------------------------------------------
641//
642//      NextState
643//
644//--------------------------------------------------------------------------------------------
645void CIrLSAP::NextState( UInt32 event )
646{
647    XTRACE( kLSAPEventProcess, ( UInt16 )event, GetState() );
648    XTRACE( kLSAPEventProcess, 0, this);
649
650    // The only overlap of state/events is ConnectReply, when the connect
651    // could be either at our client's request or as part of a client
652    // ias lookup sequence
653
654    if (event == kIrConnectReplyEvent && GetState() == kIrLSAPLookupStart) {
655	HandleNameServerConnectComplete();
656	return;
657    }
658
659    switch (event) {
660
661	case kIrDisconnectReplyEvent:
662	    HandleDisconnectComplete();
663	    break;
664
665	case kIrDiscoverReplyEvent:
666	    HandleDiscoverComplete();
667	    break;
668
669	case kIrLookupReplyEvent:
670	    HandleNameServerLookupComplete();
671	    break;
672
673	case kIrReleaseReplyEvent:
674	    HandleNameServerReleaseComplete();
675	    break;
676
677	case kIrConnectReplyEvent:
678	    HandleConnectComplete();
679	    break;
680
681	case kIrListenReplyEvent:
682	    HandleListenComplete();
683	    break;
684
685	case kIrAcceptReplyEvent:
686	    HandleAcceptComplete();
687	    break;
688
689	case kIrGetDataReplyEvent:
690	    HandleDataGetComplete();
691	    break;
692
693	case kIrPutDataReplyEvent:
694	    HandleDataPutComplete();
695	    break;
696
697	case kIrCancelGetReplyEvent:
698	    HandleCancelGetComplete();
699	    break;
700
701	case kIrCancelPutReplyEvent:
702	    HandleCancelPutComplete();
703	    break;
704
705	default:
706	    DebugLog("CIrLSAP::NextState: unexpected event");
707	    break;
708    }   // switch on event
709
710} // CIrLSAP::NextState
711
712
713
714//--------------------------------------------------------------------------------
715//
716//      DiscoverComplete
717//
718//--------------------------------------------------------------------------------
719void CIrLSAP::HandleDiscoverComplete()
720{
721    TIrDiscoverReply * reply = ( TIrDiscoverReply * )GetCurrentEvent();
722
723    UInt32                  numFound;           // number of peers discovered
724    TIrDscInfo          *   dscInfo;
725    CList               *   fDiscoverList;
726
727    if (reply->fResult == noErr) {          // if it worked
728	check (GetState() == kIrLSAPDiscoverStart);
729	if (GetState() != kIrLSAPDiscoverStart) {
730	    XTRACE(kLogDiscoverCompleteErr, reply->fResult, GetState());
731	}
732    } else {                                // else it could have async disconnected (?)
733	check (GetState() == kIrLSAPDiscoverStart ||
734	       GetState() == kIrLSAPDisconnected);
735	if (GetState() != kIrLSAPDiscoverStart && GetState() != kIrLSAPDisconnected)
736	    XTRACE(kLogDiscoverCompleteErr, reply->fResult, GetState());
737    }
738
739    fDiscoverList = reply->fDiscoveredDevices;
740
741    numFound = fDiscoverList->GetArraySize();
742    XTRACE( kDiscoverCompleteEvent, numFound, reply->fResult );
743    if( numFound > 0 ) {
744	SInt32 index;
745	for( index = 0; index < fDiscoverList->GetArraySize(); index++ ) {
746
747	    dscInfo = ( TIrDscInfo * )fDiscoverList->At( index );
748	    fDiscoverInfo[index].serviceHints   = dscInfo->GetServiceHints();
749	    fDiscoverInfo[index].addr           = dscInfo->GetDeviceAddr();
750	    dscInfo->GetNickname( fDiscoverInfo[index].name, sizeof(fDiscoverInfo[index].name) );
751	}
752    }
753    SetState( kIrLSAPDisconnected );        // discover done, disconnected again
754    DiscoverComplete( numFound, reply->fResult );       // virtual dispatch
755    fIrDA->ReleaseEventBlock( reply );
756
757    // If client asked for a disconnect while we were discovering, fake
758    // a disconnect complete now
759    if (fPendingDisconnect) {
760	XTRACE( kDiscoverCompleteEvent, 0xffff, 0xffff);
761	fPendingDisconnect = false;
762	DisconnectComplete();           // virtual callback to client
763    }
764
765} // HandleDiscoverComplete
766
767
768//--------------------------------------------------------------------------------
769//
770//      DisconnectComplete
771//
772//--------------------------------------------------------------------------------
773void CIrLSAP::HandleDisconnectComplete()
774{
775    TIrDisconnectReply * reply = ( TIrDisconnectReply * )GetCurrentEvent();
776
777    //UInt32 enterState = GetState();               // Remember what the state was
778
779    XTRACE( kDisconnectCompleteEvent, reply->fResult, GetState() );
780    fConnected = false;
781    SetState( kIrLSAPDisconnected );
782    DisconnectComplete();                   // virtual.  cb to client
783
784    // If someone else generated the disconnect then I don't want to release
785    // the event block.  LMP will do it for me.  Most likely, the beam was broken
786    // so LMP is notifing all the LSAPs of the disconnect.  It will release the
787    // event when it is done.
788    //if( enterState == kIrLSAPDisconnectStart )
789    //  fIrDA->ReleaseEventBlock( reply );
790
791    // JDG: if reply matches that of our disconnect request, free it.
792    // note: disconnect start state isn't particularly reliable ...
793    if (fDisconnectRequest == reply) {
794	fIrDA->ReleaseEventBlock( reply );
795	fDisconnectRequest = nil;
796    }
797
798} // CIrLSAP::HandleDisconnectComplete
799
800
801#pragma mark ----- LSAP Lookup Engine ---
802//--------------------------------------------------------------------------------
803//
804//      LSAPLookupComplete
805//
806//--------------------------------------------------------------------------------
807void CIrLSAP::HandleLSAPLookupComplete()
808{
809    TIrLookupEvent  *reply = (TIrLookupEvent*)GetCurrentEvent();
810    IrDAErr result = reply->fResult;
811    XTRACE(kLookupCompleteEvent, result, fPeerLSAPId );
812
813    if (result == noErr) {          // if it worked
814	check(GetState() == kIrLSAPLookupStart);
815    } else {                        // if it failed, we could have async disconnected
816	check(GetState() == kIrLSAPLookupStart
817	      ||  GetState() == kIrLSAPDisconnected);
818    }
819
820    if (result == noErr) {
821	fPeerLSAPId = reply->fPeerLSAPId;       // assume we want to talk to 'em!
822    }
823    else {
824	fPeerLSAPId = 0;
825    }
826    SetState(kIrLSAPDisconnected);          // we're not connecting yet ...
827
828    LSAPLookupComplete(result, fPeerLSAPId);        // virtual call back
829    fIrDA->ReleaseEventBlock( reply );
830
831    // If client asked for a disconnect while we were discovering, fake
832    // a disconnect complete now
833    if (fPendingDisconnect) {
834	XTRACE(kLookupCompleteEvent, 0xffff, 0xffff);
835	fPendingDisconnect = false;
836	DisconnectComplete();           // virtual callback to client
837    }
838} // CIrLSAP::HandleLSAPLookupComplete
839
840
841//--------------------------------------------------------------------------------
842//      HandleNameServerConnectComplete
843//--------------------------------------------------------------------------------
844void CIrLSAP::HandleNameServerConnectComplete()
845{
846    TIrConnLstnReply    * connectReply  = ( TIrConnLstnReply * )GetCurrentEvent();
847    TIrLookupRequest    * lookupRequest = ( TIrLookupRequest * )GetCurrentEvent();
848
849    XTRACE( kNSClientConnectedEvent, 0, connectReply->fResult );
850    check(GetState() == kIrLSAPLookupStart);
851
852    // Complete request early if an error is returned
853    if (connectReply->fResult != noErr) {
854	this->HandleLSAPLookupComplete();       // virtual dispatch to client
855    }
856    else {
857	// Issue a lookup to name server on peer device
858	// Note: re-using the connect request block
859	lookupRequest->fEvent       = kIrLookupRequestEvent;
860	lookupRequest->fClassName   = fConnectClassName;        // Client supplied
861	lookupRequest->fAttrName    = fAttributeName;           // Client supplied
862	fNameClient->EnqueueEvent(lookupRequest);
863    }
864
865} // TIrGlue::HandleNameServerConnectComplete
866
867
868//--------------------------------------------------------------------------------
869//      HandleNameServerLookupComplete
870//--------------------------------------------------------------------------------
871void CIrLSAP::HandleNameServerLookupComplete()
872{
873    TIrLookupReply          * lookupReply = ( TIrLookupReply * )GetCurrentEvent();
874    check(GetState() == kIrLSAPLookupStart);
875
876    fPeerLSAPId = 0;
877
878    if (lookupReply->fResult == noErr) {
879	// Did we successfully get the LSAPId of the remote connection end?
880	if( lookupReply->fAttribute ) {
881	    TIASElement * element = ( TIASElement * )lookupReply->fAttribute->First();
882	    if( element ) {
883		if( element->GetInteger( &fPeerLSAPId ) != noErr ) {
884		    fPeerLSAPId = 0;
885		}
886	    }
887	    //delete lookupReply->fAttribute;
888	    lookupReply->fAttribute->release();
889	}
890    }
891
892    XTRACE( kNSClientLookupReplyEvent, fPeerLSAPId, lookupReply->fResult );
893
894    TIrDisconnectRequest    * releaseRequest;
895    // Release the name server connection (re-use the reply event block)
896    releaseRequest = (TIrDisconnectRequest*)lookupReply;
897    releaseRequest->fEvent = kIrReleaseRequestEvent;
898    releaseRequest->fResult = noErr;
899    fNameClient->EnqueueEvent(releaseRequest);
900} // CIrLSAP::HandleNameServerLookupComplete
901
902
903//--------------------------------------------------------------------------------
904//      HandleNameServerReleaseComplete
905//--------------------------------------------------------------------------------
906void CIrLSAP::HandleNameServerReleaseComplete()
907{
908    TIrLookupReply * lookupReply = ( TIrLookupReply * )GetCurrentEvent();
909
910    XTRACE( kNSClientLookupDisconnectEvent, 0, fPeerLSAPId );
911    check(GetState() == kIrLSAPLookupStart);
912
913    lookupReply->fEvent         = kIrLookupReplyEvent;  // Reply back to the client
914    lookupReply->fPeerLSAPId    = fPeerLSAPId;
915    this->HandleLSAPLookupComplete();
916
917} // CIrLSAP::HandleNameServerReleaseComplete
918
919
920
921#pragma mark ----- Data Handlers ---
922
923//--------------------------------------------------------------------------------
924//
925//      ConnectComplete
926//
927//--------------------------------------------------------------------------------
928void CIrLSAP::HandleConnectComplete()
929{
930    TIrConnLstnReply *reply = (TIrConnLstnReply *)GetCurrentEvent();
931    IrDAErr result = reply->fResult;
932
933    XTRACE( kConnectCompleteEvent, result, 0 );
934
935    check( fLSAP == reply->fLSAPConn );
936
937    //if (result == noErr) {            // if it worked
938    //  check(GetState() == kIrLSAPConnectStart);       // this was failing ... sigh
939    //} else {                      // if aborted, could be in a disconnect state too
940	check(GetState() == kIrLSAPConnectStart ||
941	      GetState() == kIrLSAPDisconnectStart ||
942	      GetState() == kIrLSAPDisconnected);
943    //}
944
945    if( result == noErr ) {
946	SetState( kIrLSAPConnected );
947	fConnected = true;
948    }
949    else{
950	SetState( kIrLSAPDisconnected );
951	fConnected = false;
952    }
953
954    // "Bug" workaround.  Fixme?  We'd like the QOS values, but they're
955    // not getting set by the lower layers.  Grab 'em from glue and
956    // stuff 'em in.
957    reply->fPeerQOS = fIrDA->GetPeerQOS();
958    reply->fMyQOS   = fIrDA->GetMyQOS();
959
960    ConnectComplete(result, reply->fMyQOS, reply->fPeerQOS, (CBufferSegment *)reply->fData);
961    fIrDA->ReleaseEventBlock( reply );
962
963} // CIrLSAP::HandleConnectComplete
964
965
966
967//--------------------------------------------------------------------------------
968//
969//      DataPutComplete
970//
971//--------------------------------------------------------------------------------
972void CIrLSAP::HandleDataPutComplete()
973{
974    TIrPutReply * reply = ( TIrPutReply * )GetCurrentEvent();
975    IrDAErr result = reply->fResult;
976
977    XTRACE( kPutCompleteEvent, result, 0 );
978
979    //if (fLastListenBuffer == reply->fData)    // this is how it was failing
980    //  DebugPrintf("put buf done, %x %x %x", fLastListenBuffer, fLastPutBuffer, reply->fData);
981
982    DataPutComplete(result, (CBufferSegment *)reply->fData);    // virtual callback
983    fIrDA->ReleaseEventBlock( reply );
984
985} // CIrLSAP::HandleDataPutComplete
986
987
988//--------------------------------------------------------------------------------
989//
990//      ListenComplete
991//
992//--------------------------------------------------------------------------------
993void CIrLSAP::HandleListenComplete()
994{
995    TIrConnLstnReply    *reply = (TIrConnLstnReply*)GetCurrentEvent();
996    IrDAErr result = reply->fResult;
997
998    if (result == noErr) {              // if it worked, should be in listen start state
999	check(GetState() == kIrLSAPListenStart);
1000    } else {                            // else probably aborted by disconnect
1001	// FIXME -- ReUdo is hitting this check ... let's debugstr to see what's up
1002	// todo: we're getting here as a reject from discover start ... why?
1003	/*****/
1004#if defined(forDebug)
1005	int state = GetState();
1006	if (state != kIrLSAPListenStart &&
1007	    state != kIrLSAPDisconnectStart && state != kIrLSAPDisconnected)
1008	    DebugPrintf("CIrLSAP: listen complete %d, state %d", result, state);
1009	//****/
1010#endif  // forDebug
1011	//check(GetState() == kIrLSAPListenStart ||
1012	//    GetState() == kIrLSAPDisconnectStart ||
1013	//    GetState() == kIrLSAPDisconnected);
1014    }
1015
1016    if (result == noErr) {              // if it worked, pull out peer info
1017	fPeerLSAPId = reply->fLSAPId;
1018	fPeerAddr   = reply->fDevAddr;
1019    }
1020
1021    XTRACE( kListenCompleteEvent, fPeerLSAPId, fPeerAddr );
1022    XTRACE( kListenCompleteEvent, 0, this);
1023
1024    // "Bug" workaround.  Fixme?  We'd like the QOS values, but they're
1025    // not getting set by the lower layers.  Grab 'em from glue and
1026    // stuff 'em in.
1027    // UPDATE: this has almost been fixed but not verified.  Check out lsapconn's
1028    // clobbering of the listen request event record when reused as a GetRequest
1029    reply->fPeerQOS = fIrDA->GetPeerQOS();
1030    reply->fMyQOS   = fIrDA->GetMyQOS();
1031
1032    if (result == noErr)
1033	SetState( kIrLSAPListenComplete );
1034    else
1035	SetState(kIrLSAPDisconnected);
1036
1037    check(fLastListenBuffer == reply->fData);
1038    if (fLastListenBuffer != reply->fData) {
1039	XTRACE(kLogListenCompleteErr, 0, fLastListenBuffer);
1040	XTRACE(kLogListenCompleteErr, 0,      reply->fData);
1041    }
1042
1043    ListenComplete( result, fPeerAddr, fPeerLSAPId, reply->fMyQOS, reply->fPeerQOS, (CBufferSegment *)reply->fData);
1044    fIrDA->ReleaseEventBlock( reply );
1045
1046} // CIrLSAP::HandleListenComplete
1047
1048
1049//--------------------------------------------------------------------------------
1050//
1051//      AcceptComplete
1052//
1053//--------------------------------------------------------------------------------
1054void CIrLSAP::HandleAcceptComplete()
1055{
1056    TIrConnLstnReply *  reply = (TIrConnLstnReply*)GetCurrentEvent();
1057    IrDAErr         result = reply->fResult;
1058
1059    XTRACE( kAcceptCompleteEvent, result, 0 );
1060    check(GetState() == kIrLSAPAcceptStart);
1061
1062    if( result == noErr ) {
1063	SetState( kIrLSAPConnected );
1064	fConnected = true;
1065    }
1066    else {
1067	SetState( kIrLSAPDisconnected );
1068	fConnected = false;
1069    }
1070
1071    AcceptComplete(result, (CBufferSegment *)reply->fData);
1072    fIrDA->ReleaseEventBlock( reply );
1073
1074} // CIrLSAP::HandleAcceptComplete
1075
1076
1077//--------------------------------------------------------------------------------
1078//
1079//      DataGetComplete
1080//
1081//--------------------------------------------------------------------------------
1082void CIrLSAP::HandleDataGetComplete()
1083{
1084    TIrGetReply * reply = ( TIrGetReply * )GetCurrentEvent();
1085    IrDAErr     result = reply->fResult;
1086
1087    XTRACE( kGetCompleteEvent, result, 0 );
1088
1089    DataGetComplete(result, (CBufferSegment *)reply->fData);
1090    fIrDA->ReleaseEventBlock( reply );
1091
1092} // CIrLSAP::HandleDataGetComplete
1093
1094//--------------------------------------------------------------------------------
1095//
1096//      CancelPutComplete
1097//
1098//--------------------------------------------------------------------------------
1099void CIrLSAP::HandleCancelPutComplete()
1100{
1101    TIrCancelPutReply * reply = ( TIrCancelPutReply * )GetCurrentEvent();
1102    IrDAErr result = reply->fResult;
1103
1104    XTRACE( kCancelPutsComplete, 0, 0 );
1105
1106    CancelPutsComplete(result);             // virtual callback
1107    fIrDA->ReleaseEventBlock( reply );
1108} // CIrLSAP::HandleCancelPutComplete
1109
1110//--------------------------------------------------------------------------------
1111//
1112//      CancelGetComplete
1113//
1114//--------------------------------------------------------------------------------
1115void CIrLSAP::HandleCancelGetComplete()
1116{
1117    TIrCancelGetReply * reply = ( TIrCancelGetReply * )GetCurrentEvent();
1118    IrDAErr result = reply->fResult;
1119
1120    XTRACE( kCancelGetsComplete, 0, 0 );
1121
1122    CancelGetsComplete(result);             // virtual callback
1123    fIrDA->ReleaseEventBlock( reply );
1124
1125} // CIrLSAP::HandleCancelGetComplete
1126
1127