1/*
2    File:       IrDiscovery.cpp
3
4    Contains:   xxx put contents here xxx
5*/
6#include "IrDiscovery.h"
7#include "CList.h"
8#include "IrDscInfo.h"
9#include "IrGlue.h"
10#include "IrLMP.h"
11#include "CListIterator.h"
12
13#if (hasTracing > 0 && hasIrDiscoveryTracing > 0)
14
15enum IrDiscoverTraceCodes
16{
17    kLogNew = 1,
18    kLogFree,
19    kLogInit,
20    kLogNextState,
21    kLogExtDiscStart,
22    kLogDiscoveryStart,
23    kLogDiscoverComplete,
24    kIrExtDiscoverComplete,
25    kLogDiscoverDeleteList,
26
27    kEnqueueEvent,
28    kDequeueEventStart,
29    kDequeueEventEnd
30
31};
32
33static
34EventTraceCauseDesc IrDiscoverEvents[] = {
35    {kLogNew,                   "IrDiscovery: new object="},
36    {kLogFree,                  "IrDiscovery: free object"},
37    {kLogInit,                  "IrDiscovery: init"},
38    {kLogNextState,             "IrDiscovery: next state, event=, state="},
39    {kLogExtDiscStart,          "IrDiscovery: Ext start, numSlots="},
40    {kLogDiscoveryStart,        "IrDiscovery: start, slots=, state="},
41    {kLogDiscoverComplete,      "IrDiscovery: complete, obj="},
42    {kIrExtDiscoverComplete,    "IrDiscovery: Ext complete count="},
43    {kLogDiscoverDeleteList,    "IrDiscovery: delete discovered list, all="},
44
45    {kEnqueueEvent,             "IrDiscovery: Event Queued"},
46    {kDequeueEventStart,        "IrDiscovery: Event Start"},
47    {kDequeueEventEnd,          "IrDiscovery: Event End"}
48};
49
50#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, IrDiscoverEvents, true )
51
52#else
53    #define XTRACE(x, y, z) ((void)0)
54#endif
55
56enum {
57    kMaxDiscoverListSize = 16           // Limit the discovered list size
58};
59
60#define super TIrStream
61    OSDefineMetaClassAndStructors(CIrDiscovery, TIrStream);
62
63/*static*/
64CIrDiscovery *
65CIrDiscovery::cIrDiscovery(TIrGlue * glue)
66{
67    CIrDiscovery *obj = new CIrDiscovery;
68
69    XTRACE(kLogNew, 0, obj);
70
71    if (obj && !obj->Init(glue)) {
72	obj->release();
73	obj = nil;
74    }
75    return obj;
76}
77
78void
79CIrDiscovery::free()
80{
81    //int Review_Event_Usage;     // release events on the pendng discover list?
82
83    XTRACE(kLogFree, 0, this);
84
85    DeleteDiscoveredDevicesList();      // free the objects on the list
86
87#define FREE(x) { if (x) { (x)->release(); x = nil; }}
88    FREE(fDiscoveredDevices);
89    FREE(fPendingDiscoverList);
90    FREE(fMyDscInfo);
91
92
93    super::free();
94    return;
95}
96
97
98Boolean
99CIrDiscovery::Init(TIrGlue * glue)
100{
101    XTRACE(kLogInit, 0, this);
102
103    fState  = kDiscoverIdle;
104    fPendingDiscoverList = nil;
105    fDiscoveredDevices = nil;
106    fMyDscInfo = nil;
107
108
109#if (hasTracing > 0 && hasIrDiscoveryTracing > 0)
110    if (!super::Init(glue, IrDiscoverEvents, kEnqueueEvent)) return false;
111#else
112    if (!super::Init(glue)) return false;
113#endif
114
115
116    fPendingDiscoverList = CList::cList();
117    require(fPendingDiscoverList, Fail);
118
119    fDiscoveredDevices = CList::cList();
120    require(fDiscoveredDevices, Fail);
121
122    fMyDscInfo = TIrDscInfo::tIrDscInfo();
123    require(fMyDscInfo, Fail);
124
125    fMyDscInfo->SetNickname("Mac/OS-X");                    // hostname unavailable to kext's.  foo.
126    fMyDscInfo->SetServiceHints(kDevInfoHintComputer);      // clients can now add/delete from this set
127
128    return true;
129
130Fail:
131
132    if (fPendingDiscoverList) {
133	fPendingDiscoverList->release();
134	fPendingDiscoverList = nil;
135    }
136
137    if (fDiscoveredDevices) {
138	fDiscoveredDevices->release();
139	fDiscoveredDevices = nil;
140    }
141
142    if (fMyDscInfo) {
143	fMyDscInfo->release();
144	fMyDscInfo = nil;
145    }
146    return false;
147}
148
149
150//--------------------------------------------------------------------------------
151//      NextState
152//--------------------------------------------------------------------------------
153void CIrDiscovery::NextState( ULong event )
154{
155    XTRACE(kLogNextState, event, fState);
156
157    require(event == kIrDiscoverRequestEvent || event == kIrDiscoverReplyEvent || event == kIrDisconnectReplyEvent, Fail);
158
159    switch (event) {
160	case kIrDiscoverRequestEvent:
161	    DiscoverStart();
162	    break;
163
164	case kIrDiscoverReplyEvent:
165	    HandleDiscoverComplete();
166	    break;
167
168	case kIrDisconnectReplyEvent:
169//          HandleDisconnectComplete( nil );
170	    break;
171    }
172
173Fail:
174    return;
175
176} // CIrDiscovery::NextState
177
178
179
180//--------------------------------------------------------------------------------
181//      DiscoverStart
182//--------------------------------------------------------------------------------
183void CIrDiscovery::DiscoverStart()
184{
185    TIrDiscoverRequest * request = (TIrDiscoverRequest *)this->GetCurrentEvent();
186    IrDAErr err = noErr;
187
188    XTRACE(kLogDiscoveryStart, request->fNumSlots, fState);
189
190    require(request->fClient, Fail);
191
192    if( request->fNumSlots > kMaxDiscoverSlots )
193	err = errDiscoveryTooManySlots;                 // Range check the slot count
194
195    if( err ) {                                         // Bounce it back to the client
196	request->fResult    = err;
197	request->fEvent     = kIrDiscoverReplyEvent;
198	request->fClient->EnqueueEvent( request );
199	return;
200    }
201
202    if( request->fNumSlots == 0 )                   // Use the default
203	request->fNumSlots = kDiscoverDefaultSlotCount;
204
205    // Can I do a discovery ?
206    if( fState == kDiscoverActive ) {       // There's a pending discover.  Push on the list
207	if( fPendingDiscoverList )          // Queue up the request
208	    fPendingDiscoverList->InsertLast( request );
209	return;
210    }
211
212    // If there is a LAP connection then respond to client with the current
213    // discovery info.
214
215    if( fIrDA->IsLAPConnected() ) {
216	// Remove every response except the connected device's
217	request->fResult                = errDiscoveryInConnection;
218	request->fDiscoveredDevices     = fDiscoveredDevices;
219	request->fEvent =  kIrDiscoverReplyEvent;           // jdg, it's a reply event, not a request
220	request->fClient->EnqueueEvent( request );
221    }
222    // Issue request to LMP to perform a XID discovery
223    else {
224	fState = kDiscoverActive;                   // Set flag we are in progress
225	DeleteDiscoveredDevicesList();              // JDG: reset list of discovered devices
226	request->fDiscoveredDevices = fDiscoveredDevices;
227
228	// All done - until discover completes
229
230	// Note: fMyDscInfo fields initialized by caller (oh yeah???????)
231	fIrDA->GetLMP()->EnqueueEvent( request );
232    }
233    return;
234
235Fail:
236    // free event?
237    return;
238} // CIrDiscovery::DiscoverStart
239
240//--------------------------------------------------------------------------------
241//      HandleDiscoverComplete
242//--------------------------------------------------------------------------------
243void CIrDiscovery::HandleDiscoverComplete()
244{
245    TIrDiscoverReply    *   discoverReply = (TIrDiscoverReply*)GetCurrentEvent();
246    TIrDiscoverReply    *   pendingRequest;
247
248    XTRACE( kLogDiscoverComplete, 0, this);
249    check( fDiscoveredDevices == discoverReply->fDiscoveredDevices );
250
251    // Complete discover request (let caller pick a device to connect to)
252    fState = kDiscoverIdle;
253
254    if( discoverReply->fClient == this )
255	this->HandleExtDiscoverComplete( discoverReply );
256    else
257	discoverReply->fClient->EnqueueEvent( discoverReply );
258
259    if( fPendingDiscoverList->Count() ) {       // Notify all pendingrequestors if necessary
260	CListIterator *iter = CListIterator::cListIterator(fPendingDiscoverList);
261	require(iter, Fail);
262	for( pendingRequest = ( TIrDiscoverReply * )iter->FirstItem(); iter->More();
263	     pendingRequest = ( TIrDiscoverReply * )iter->NextItem() ) {
264
265	     // Its a response now.
266	     pendingRequest->fEvent = kIrDiscoverReplyEvent;
267
268	     // Copy the results from the reply to each pending reply
269	     pendingRequest->fResult            = discoverReply->fResult;
270	     pendingRequest->fNumSlots          = discoverReply->fNumSlots;
271	     pendingRequest->fConflictDevAddr   = discoverReply->fConflictDevAddr;
272	     pendingRequest->fDiscoveredDevices = discoverReply->fDiscoveredDevices;
273	     pendingRequest->fPassiveDiscovery  = discoverReply->fPassiveDiscovery;
274
275	    // return pending request
276	    if( pendingRequest->fClient == this )
277		this->HandleExtDiscoverComplete( pendingRequest );
278	    else
279		pendingRequest->fClient->EnqueueEvent( pendingRequest );
280	}
281	iter->release();
282    }
283    // This response if complete so clear the pending list
284    fPendingDiscoverList->RemoveAll();
285    return;
286
287Fail:
288    return;
289
290} // CIrDiscovery::HandleDiscoverComplete
291
292
293//--------------------------------------------------------------------------------
294//      ExtDiscoverStart
295//--------------------------------------------------------------------------------
296IrDAErr CIrDiscovery::ExtDiscoverStart(     UInt32                          numSlots)
297					//ExtDiscoveryUserCallBackUPP       callback,
298					//ExtDiscoveryBlock         *   userData        )
299{
300    TIrExtDiscoverRequest *request;
301
302    XTRACE(kLogExtDiscStart, 0, numSlots);
303
304    request = (TIrExtDiscoverRequest *)fIrDA->GrabEventBlock(0, 0);
305    require(request, Fail);
306    request->fEvent     = kIrDiscoverRequestEvent;
307    request->fResult    = noErr;
308
309    if( numSlots > kMaxDiscoverSlots )
310	request->fNumSlots = kMaxDiscoverSlots;         // Limit the max slot count
311    else
312	request->fNumSlots = numSlots;
313
314    //userData->count = 0;                              // Set it to a safe value
315
316    request->fClient    = this;                         // Fill in the fields and
317    //request->fCallBack    = callback;                     // send it off to myself
318    //request->fUserData    = userData;
319
320    this->EnqueueEvent(request);
321
322    return noErr;
323
324Fail:
325    return errNoMemory;
326
327} // CIrDiscovery::ExtDiscoverStart
328
329
330//--------------------------------------------------------------------------------
331//      DeleteDiscoveredDevicesList
332//--------------------------------------------------------------------------------
333void CIrDiscovery::DeleteDiscoveredDevicesList()
334{
335    XTRACE(kLogDiscoverDeleteList, 0, 0);
336
337    if (fDiscoveredDevices) {
338	while (true) {
339	    TIrDscInfo *dscInfo = (TIrDscInfo *)fDiscoveredDevices->Last();
340	    if (dscInfo != nil) {
341		dscInfo->release();
342		fDiscoveredDevices->RemoveLast();
343	    }
344	    else {
345		break;
346	    }
347	}
348    }
349
350} // CIrDiscovery::DeleteDiscoveredDevicesList
351
352//--------------------------------------------------------------------------------
353//      PassiveDiscovery
354//--------------------------------------------------------------------------------
355void CIrDiscovery::PassiveDiscovery(TIrDscInfo * dscInfo)
356{
357    if (fDiscoveredDevices) {
358//
359//  Limit the list size to the predetermined size (16).
360//
361	SInt16  discCount = fDiscoveredDevices->Count();
362	if (discCount > kMaxDiscoverListSize) {         // Trim it back so the new one
363							// will fit.
364	    SInt16 deleteCount = discCount - kMaxDiscoverListSize;
365
366	    while (deleteCount--) {
367		TIrDscInfo* dscInfo = (TIrDscInfo *)fDiscoveredDevices->First();
368		if (dscInfo != nil) {
369		    dscInfo->release();
370		    fDiscoveredDevices->RemoveFirst();
371		}
372	    }
373	}
374//
375// Now scan the list for a duplicate entry.  The LAP address is used for the test
376//
377	TIrDscInfo *oldInfo;
378
379	discCount = fDiscoveredDevices->Count();
380	for( SInt16 index = 0; index < discCount; index++ ) {
381	    oldInfo = ( TIrDscInfo *)fDiscoveredDevices->At(index);
382	    if (oldInfo && (oldInfo->GetDeviceAddr() == dscInfo->GetDeviceAddr())) {
383		fDiscoveredDevices->RemoveAt(index);
384		oldInfo->release();
385		break;			// found it in list, quit searching
386	    }
387	}
388	fDiscoveredDevices->InsertFirst( dscInfo );         // jdg, was insertlast ...
389    }
390}
391
392//--------------------------------------------------------------------------------
393//      GetRemoteDeviceName
394//--------------------------------------------------------------------------------
395void CIrDiscovery::GetRemoteDeviceName( UInt32 lapAddr, UInt8 * name, int maxnamelen )
396{
397    TIrDscInfo  *   oldInfo;
398    SInt16          discCount = fDiscoveredDevices->Count();
399    Boolean         found = false;
400
401    name[0] = 0;
402
403    for( SInt16 index = 0; index < discCount; index++ ) {
404	oldInfo = ( TIrDscInfo * )fDiscoveredDevices->At( index );
405	if( oldInfo->GetDeviceAddr() == lapAddr ) {
406	    oldInfo->GetNickname( name, maxnamelen );
407	    found = true;
408	    break;
409	}
410    }
411    if(!found)  {
412	name[0] = 0;
413    }
414}
415
416
417//--------------------------------------------------------------------------------
418//      HandleExtDiscoverComplete
419//--------------------------------------------------------------------------------
420void CIrDiscovery::HandleExtDiscoverComplete( TIrDiscoverReply * reply )
421{
422    //TIrExtDiscoverReply           *   myReply     = ( TIrExtDiscoverReply * )reply;
423    //ExtDiscoveryBlock         *   userResults = ( ExtDiscoveryBlock * )myReply->fUserData;
424    //ExtDiscoveryUserCallBackUPP       callback    = ( ExtDiscoveryUserCallBackUPP )myReply->fCallBack;
425    //TIrDscInfo                    *   dscInfo;
426
427    //userResults->count = fDiscoveredDevices->GetArraySize();
428    XTRACE(kIrExtDiscoverComplete, 0, fDiscoveredDevices->GetArraySize());      // Log the count.
429
430    /*****
431    if( userResults->count > kMaxDiscoverSlots )                // Check if the count is within
432	userResults->count = 0;                                 // bounds.  If not then something
433								// bad has happened.  Bag it.
434    userResults->passiveDiscovery   = myReply->fPassiveDiscovery > 0;
435
436    // Copy the results into the caller's block.
437    if( userResults->count > 0 ) {
438	for( UInt16 index = 0; index < userResults->count; index++ ) {
439
440	    dscInfo = ( TIrDscInfo * )fDiscoveredDevices->At( index );
441	    userResults->discoverResult[index].serviceHints         = dscInfo->GetServiceHints();
442	    userResults->discoverResult[index].addr                 = dscInfo->GetDeviceAddr();
443	    dscInfo->GetNickname( userResults->discoverResult[index].name );
444	}
445    }
446    reply->fEvent = nil;                                        // Free the event
447
448    CallExtDiscoveryCallBackProc( callback, myReply->fResult );
449    ****/
450
451    TIrEvent::ReleaseEventBlock(reply);         // release the event
452
453} // CIrDiscovery::HandleMyDiscoverComplete
454
455