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