1/* 2 File: IrLAPConn.c 3 4 Contains: Implementation of the TIrLAPConn class 5 6 7*/ 8 9#include "IrLAPConn.h" 10#include "IrLSAPConn.h" 11#include "IrGlue.h" 12#include "IrLAP.h" 13#include "CList.h" 14#include "CListIterator.h" 15#include "IrDALog.h" 16 17#if (hasTracing > 0 && hasLAPConnTracing > 0) 18 19enum IrLAPConnTraceCodes 20{ 21 kNullEvent = 1, 22 kDestroy, 23 kInit, 24 kDeInit, 25 kUnexpectedEvent, 26 kLogStateEvent, 27 28 kStandbyConnLstnRequestEvent, 29 kStandbyDisconnectRequestEvent, 30 kStandbyDisconnectReplyEvent, 31 kStandbyDisconnectRequeue, 32 33 kPendingConnLstnRequestEvent, 34 kPendingConnLstnDeferRequest, // jdg 35 kPendingConnLstnReplyEvent, 36 kPendingDisconnectRequestEvent, 37 kPendingDisconnectReplyEvent, 38 kPendingDisconnectRequeue, // jdg 39 40 kActiveConnLstnRequestEvent, 41 kActiveConnLstnDeferRequest, // jdg 42 kActiveGetDataRequestEvent, 43 kActiveCancelGetRequestEvent, 44 kActiveDisconnectRequestEvent, 45 kActiveDisconnectReplyEvent, 46 kActiveDisconnectRequeue, // jdg 47 48 kDemuxInvalidHeaderEvent, 49 kDemuxGetPendingEvent, 50 kDemuxReplyPostedEvent, 51 kDemuxReplyPostedEvent2, 52 kDemuxNoReceiverEvent, 53 kDemuxReleaseBufferEvent, 54 55 kCancelPendingGetReqEvent, 56 kCleanupPendingRcvdBufEvent, 57 58 kWantToAdd, 59 kAddingToLSAPConnList, 60 kAddingLsapToList, 61 62 kLogStartIdleDisconnectTimer, 63 kLogStopIdleDisconnectTimer, 64 kLogDoIdleDisconnect, 65 66 kLogConnWatchDogFired, 67 kLogIdleDisconnectFired, 68 69 kLogReset, 70 kLogResetLsapConn, 71 kLogResetGetRequest, 72 kLogResetGetReply, 73 kLogResetPendingReq, 74 75 kLogDemux, 76 kLogDemuxCheckingGets1, 77 kLogDemuxCheckingGets2, 78 kLogAddingGetRequest1, 79 kLogAddingGetRequest2, 80 kLogAddingGetRequest3, 81 82 kLogCleanupPendingGetRequestsAndRepliesEntry, 83 kLogCleanupPendingGetRequestsAndReplies2, 84 kLogCleanupPendingGetRequestsAndReplies3, 85 86 kLogCancelPendingGetRequestsEntry, 87 kLogCancelPendingGetRequests, 88 kLogCancelPendingGetRequestsExit, 89 90 kLogFillInLMPDUHeader1, 91 kLogFillInLMPDUHeader2, 92 93 kEnqueueEvent, 94 kDequeueEventStart, 95 kDequeueEventEnd 96}; 97 98EventTraceCauseDesc IrLAPConnTraceEvents[] = { 99 {kNullEvent, "irlapconn: create obj="}, 100 {kDestroy, "irlapconn: destroy obj="}, 101 {kInit, "irlapconn: init"}, 102 {kDeInit, "irlapconn: deinit"}, 103 {kUnexpectedEvent, "irlapconn: unexpected event"}, 104 {kLogStateEvent, "irlapconn: next state, state=, event="}, 105 106 {kStandbyConnLstnRequestEvent, "irlapconn: standby conn/lstn request"}, 107 {kStandbyDisconnectRequestEvent,"irlapconn: standby disconnect request"}, 108 {kStandbyDisconnectReplyEvent, "irlapconn: standby disconnect reply"}, 109 {kStandbyDisconnectRequeue, "irlapconn: standby requeue pending requests"}, // jdg 110 111 {kPendingConnLstnRequestEvent, "irlapconn: uconnect conn/lstn request"}, 112 {kPendingConnLstnDeferRequest, "irlapconn: uconnect conn/lstn defer request"}, // jdg 113 {kPendingConnLstnReplyEvent, "irlapconn: uconnect conn/lstn reply"}, 114 {kPendingDisconnectRequestEvent,"irlapconn: uconnect disconnect request"}, 115 {kPendingDisconnectReplyEvent, "irlapconn: uconnect disconnect reply"}, 116 {kPendingDisconnectRequeue, "irlapconn: uconnect requeue pending request"}, 117 118 {kActiveConnLstnRequestEvent, "irlapconn: active conn/lstn request"}, 119 {kActiveConnLstnDeferRequest, "irlapconn: active conn/lstn defer request"}, // jdg 120 {kActiveGetDataRequestEvent, "irlapconn: active get data request"}, 121 {kActiveCancelGetRequestEvent, "irlapconn: active cancel get request"}, 122 {kActiveDisconnectRequestEvent, "irlapconn: active disconnect request"}, 123 {kActiveDisconnectReplyEvent, "irlapconn: active disconnect reply"}, 124 {kActiveDisconnectRequeue, "irlapconn: active requeue pending request"}, 125 126 {kDemuxInvalidHeaderEvent, "irlapconn: invalid header"}, 127 {kDemuxGetPendingEvent, "irlapconn: found get pending, event rec="}, 128 {kDemuxReplyPostedEvent, "irlapconn: found lsapconn, no get. buf="}, 129 {kDemuxReplyPostedEvent2, "irlapconn: found lsapconn, no get. lsapconn="}, 130 {kDemuxNoReceiverEvent, "irlapconn: no receiver"}, 131 {kDemuxReleaseBufferEvent, "irlapconn: release buffer"}, 132 133 {kCancelPendingGetReqEvent, "irlapconn: cancel pending get request, lsapconn="}, 134 {kCleanupPendingRcvdBufEvent, "irlapconn: cleaning up pending recd buffer"}, 135 136 {kWantToAdd, "irlapconn: ** want to add lsapconn to list"}, 137 {kAddingToLSAPConnList, "irlapconn: ** add/del to fLSAPConnList, add=, id="}, 138 {kAddingLsapToList, "irlapconn: ** add/del of lsap="}, 139 140 {kLogStartIdleDisconnectTimer, "irlapconn: starting idle disconnect timer"}, 141 {kLogStopIdleDisconnectTimer, "irlapconn: stoppng idle disconnect timer"}, 142 {kLogDoIdleDisconnect, "irlapconn: doing idle disconnect"}, 143 144 {kLogConnWatchDogFired, "irlapconn: conn watchdog timer fired"}, 145 {kLogIdleDisconnectFired, "irlapconn: idle disconnect timer fired"}, 146 147 {kLogReset, "irlapconn: reset. fConnected, fState"}, 148 {kLogResetLsapConn, "irlapconn: reset. lsapconn="}, 149 {kLogResetGetRequest, "irlapconn: reset. getrequest="}, 150 {kLogResetGetReply, "irlapconn: reset. getreply="}, 151 {kLogResetPendingReq, "irlapconn: reset. pending request"}, 152 153 {kLogDemux, "irlapconn: demux input packet, buf="}, 154 {kLogDemuxCheckingGets1, "irlapconn: demux, pending get count="}, 155 {kLogDemuxCheckingGets2, "irlapconn: demux, checking event rec="}, 156 {kLogAddingGetRequest1, "irlapconn: saving get req, event Rec="}, 157 {kLogAddingGetRequest2, "irlapconn: saving get req, lsapconn="}, 158 {kLogAddingGetRequest3, "irlapconn: saving get req, qlen=, lsapid="}, 159 160 {kLogCleanupPendingGetRequestsAndRepliesEntry, "irlapconn: CleanupPendingGetRequestsAndReplies entry, lsapConn="}, 161 {kLogCleanupPendingGetRequestsAndReplies2, "irlapconn: CleanupPendingGetRequestsAndReplies 2"}, 162 {kLogCleanupPendingGetRequestsAndReplies3, "irlapconn: CleanupPendingGetRequestsAndReplies, replyBuffer="}, 163 164 {kLogCancelPendingGetRequestsEntry, "irlapconn: CancelPendingGetRequestsEntry"}, 165 {kLogCancelPendingGetRequests, "irlapconn: CancelPendingGetRequests"}, 166 {kLogCancelPendingGetRequestsExit, "irlapconn: CancelPendingGetRequestsExit"}, 167 168 {kLogFillInLMPDUHeader1, "irlapconn: putRequest"}, 169 {kLogFillInLMPDUHeader2, "irlapconn: buffer"}, 170 171 172 {kEnqueueEvent, "irlapconn: Event Queued"}, 173 {kDequeueEventStart, "irlapconn: Event Start"}, 174 {kDequeueEventEnd, "irlapconn: Event End"} 175}; 176 177#define XTRACE(x, y, z) IrDALogAdd( x, y, (uintptr_t)z & 0xffff, IrLAPConnTraceEvents, true ) 178#else 179#define XTRACE(x, y, z) ((void)0) 180#endif 181 182#define GetLAP (fIrDA->GetLAP()) 183 184#define super TIrStream 185 OSDefineMetaClassAndStructors(TIrLAPConn, TIrStream); 186 187//-------------------------------------------------------------------------------- 188// tIrLAPConn 189//-------------------------------------------------------------------------------- 190/*static*/ 191TIrLAPConn * 192TIrLAPConn::tIrLAPConn(TIrGlue* irda) 193{ 194 TIrLAPConn *obj = new TIrLAPConn; 195 XTRACE(kNullEvent, 0, obj); 196 197 if (obj && !obj->Init(irda)) { 198 obj->release(); 199 obj = nil; 200 } 201 return obj; 202} 203 204 205 206//-------------------------------------------------------------------------------- 207// free 208//-------------------------------------------------------------------------------- 209void 210TIrLAPConn::free() 211{ 212 XTRACE(kDestroy, 0, this); 213 214 // Free things allocated by TIrLAPConn 215 StopIdleDisconnectTimer(); // make sure the timer is off 216 217#define FREE(x) { if (x) { (x)->release(); x = nil; } } 218 219 FREE(fLSAPConnList); // Free the LSAPConn list 220 FREE(fPendingGetRequests); // Free the pending get requests list 221 FREE(fUnmatchedGetReplys); // Free the unmatched get replys list 222 FREE(fPendingRequests); // Free the pending event list 223 224 225 super::free(); 226 227} // TIrLAPConn::free 228 229 230//-------------------------------------------------------------------------------- 231// Init 232//-------------------------------------------------------------------------------- 233Boolean TIrLAPConn::Init(TIrGlue* irda) 234{ 235 XTRACE(kInit, 0, this); 236 237 238 fState = kIrLAPConnStandby; 239 fConnected = false; 240 fPeerDevAddr = 0; 241 fLSAPConnList = nil; 242 fPendingGetRequests = nil; 243 fUnmatchedGetReplys = nil; 244 fPendingRequests = nil; 245 246 fDisconnectPending = false; 247 248 249 // Init IrStream 250#if (hasTracing > 0 && hasLAPConnTracing > 0) 251 if (!super::Init(irda, IrLAPConnTraceEvents, kEnqueueEvent)) return false; 252#else 253 if (!super::Init(irda)) return false; 254#endif 255 256 257 // Init LSAPConn list 258 fLSAPConnList = CList::cList(); 259 require(fLSAPConnList, Fail); 260 261 // Init the pending get requests list 262 fPendingGetRequests = CList::cList(); 263 require(fPendingGetRequests, Fail); 264 265 // Init the received (but unmatched) get replies 266 fUnmatchedGetReplys = CList::cList(); 267 require(fUnmatchedGetReplys, Fail); 268 269 // Init the list of deferred requests 270 fPendingRequests = CList::cList(); 271 require(fPendingRequests, Fail); 272 273 return true; 274 275Fail: 276 277 return false; 278 279} // TIrLAPConn::Init 280 281 282//-------------------------------------------------------------------------------- 283// Reset 284//-------------------------------------------------------------------------------- 285void TIrLAPConn::Reset() 286{ 287 288 XTRACE(kLogReset, fConnected, fState); 289 290 // This will force other asserts in HandleStandbyStateEvent which check 291 // to see that all of the other fields were properly reset at disconnect. 292 293 fState = kIrLAPConnStandby; // Using Reset for Aync disconnect. There 294 fConnected = false; // will be no disconnect reply (for now). 295 fPeerDevAddr = 0; 296 297 StopIdleDisconnectTimer(); // make sure the timer is off 298 299 // 300 // JDG: let's loop over our lsap conn list and purge everything. 301 // this should pick up pending get requests and pending get replies 302 // but for sanities sake, we'll check them too after this iteration. 303 // 304 if (fLSAPConnList && !fLSAPConnList->Empty()) { // get rid of all pending listen/connects 305 int index; 306 TLSAPConn* lsapConn; 307 308 XTRACE(kLogResetLsapConn, 1, fLSAPConnList->GetArraySize()); 309 for (index = fLSAPConnList->GetArraySize() - 1; index >= 0 ; index--) { 310 lsapConn = (TLSAPConn*)fLSAPConnList->At(index); 311 XTRACE(kLogResetLsapConn, 0, lsapConn); 312 // Complete pending get requests and delete any received buffers intended for this conn 313 CleanupPendingGetRequestsAndReplies(lsapConn, errCancel); 314 } 315 while (!fLSAPConnList->Empty()) 316 fLSAPConnList->RemoveLast(); 317 XTRACE(kLogResetLsapConn, 0xffff, 0xffff); 318 } 319 320 if (fPendingGetRequests && !fPendingGetRequests->Empty()) { // Cancel all pending Get requests 321 CListIterator *iter = CListIterator::cListIterator(fPendingGetRequests); 322 TIrGetRequest *getRequest; 323 324 DebugLog("IrLapConn: reset pending get request. how?"); // shouldn't get here 325 for (getRequest = (TIrGetRequest*)iter->FirstItem(); 326 iter->More(); getRequest = (TIrGetRequest*)iter->NextItem()) { 327 //for (getRequest = OSDynamicCast(TIrGetRequest, (OSObject *)iter->FirstItem()); 328 // iter->More(); getRequest = OSDynamicCast(TIrGetRequest, (OSObject *)iter->NextItem())) { 329 XTRACE(kLogResetGetRequest, 0, getRequest); 330 // This is somewhat inefficient, since Cleanup will loop through the pending list 331 // again to match the LSAP. But that's ok. 332 this->CleanupPendingGetRequestsAndReplies( getRequest->fLSAPConn, errCancel); 333 } 334 iter->release(); 335 } 336 337 // fUnmatchedGetReplys is a list of CBufferSegments that have come in, discard them 338 if (fUnmatchedGetReplys && !fUnmatchedGetReplys->Empty()) { 339 CListIterator *iter = CListIterator::cListIterator(fUnmatchedGetReplys); 340 CBufferSegment* replyBuffer; 341 342 DebugLog("IrLapConn: reset pending get replies. how?"); // shouldn't get here 343 for (replyBuffer = (CBufferSegment*)iter->FirstItem(); 344 iter->More(); replyBuffer = (CBufferSegment*)iter->NextItem()) { 345 XTRACE(kLogResetGetReply, 0, replyBuffer); 346 GetLAP->ReleaseInputBuffer(replyBuffer); // give the buffer back to lap 347 } 348 while (!fUnmatchedGetReplys->Empty()) 349 fUnmatchedGetReplys->RemoveLast(); 350 351 iter->release(); 352 } 353 354 // if we had pendingRequests, they were waiting for a disconnect, do 'em now! 355 if (fPendingRequests && !fPendingRequests->Empty()) { 356 CListIterator *iter = CListIterator::cListIterator(fPendingRequests); 357 for (TIrEvent* request = (TIrEvent*)iter->FirstItem(); 358 iter->More(); request = (TIrEvent*)iter->NextItem()) { 359 XTRACE(kLogResetPendingReq, 0, request); 360 check(request->fEvent == kIrListenRequestEvent || request->fEvent == kIrConnectRequestEvent); 361 this->EnqueueEvent(request); 362 } 363 while (!fPendingRequests->Empty()) 364 fPendingRequests->RemoveLast(); 365 366 iter->release(); 367 } 368 fDisconnectPending = false; // safe to connect/listen again 369 370 // Whew. I *think* we've fully reset LapConn. 371 372} // TIrLAPConn::Reset 373 374 375 376//-------------------------------------------------------------------------------- 377// NextState 378//-------------------------------------------------------------------------------- 379void TIrLAPConn::NextState(ULong event) 380{ 381 XTRACE(kLogStateEvent, fState, event); 382 383 switch (fState) { 384 case kIrLAPConnStandby: 385 HandleStandbyStateEvent(event); 386 break; 387 388 case kIrLAPConnConnectOrListen: 389 HandleConnectOrListenStateEvent(event); 390 break; 391 392 case kIrLAPConnActive: 393 HandleActiveStateEvent(event); 394 break; 395 396 default: 397 DebugLog("TIrLAPConn::NextState: bad fState"); 398 break; 399 } 400 401} // TIrLAPConn::NextState 402 403 404//-------------------------------------------------------------------------------- 405// HandleStandbyStateEvent 406//-------------------------------------------------------------------------------- 407void TIrLAPConn::HandleStandbyStateEvent(ULong event) 408{ 409 XASSERT(!fConnected); 410 XASSERT(fPeerDevAddr == 0); 411 412 switch (event) { 413 case kIrConnectRequestEvent: 414 case kIrListenRequestEvent: 415 { 416 TIrConnLstnRequest* request = (TIrConnLstnRequest*)GetCurrentEvent(); 417 XTRACE(kStandbyConnLstnRequestEvent, event, 0); 418 419 XTRACE(kWantToAdd, (uintptr_t)request->fLSAPConn>>16, request->fLSAPConn); 420 421 // Add the lsapConn to the list of pending conns to connect/listen 422 // jdg: the IAS server gets an error on it's listen and immediately issues another 423 // listen request. Since it didn't do a disconnect, it's LSAP is still on our list. 424 if (!fLSAPConnList->Contains(request->fLSAPConn)) { 425 fLSAPConnList->InsertLast(request->fLSAPConn); 426 } 427 428 // Keep track of the device that we will be connected to 429 if (event == kIrConnectRequestEvent) { 430 fPeerDevAddr = request->fDevAddr; 431 } 432 433 // Pass the request on to IrLAP 434 // ***This can be dangerous if the connect can be cancelled separately 435 // from all other pending requests and then the IrLAP will depend on a 436 // buffer that no longer is "allocated". In other words, maybe a separate 437 // req buffer should be allocated for this purpose. 438 fState = kIrLAPConnConnectOrListen; 439 GetLAP->EnqueueEvent(request); 440 } 441 break; 442 443 case kIrDisconnectRequestEvent: 444 { 445 // Pass the disconnect on to IrLAP ********* JDG: nope, this is not what we want. lap is already disconnected 446 XTRACE(kStandbyDisconnectRequestEvent, 0, 0); 447 448 if (1) { // jdg testing 449 TIrDisconnectRequest* disconnectRequest = (TIrDisconnectRequest*)GetCurrentEvent(); 450 // Remove this lsap from the lsap conn list -- if it's still there 451 if (fLSAPConnList->Contains(disconnectRequest->fLSAPConn)) { // sigh, it doesn't always ... 452 XTRACE(kAddingToLSAPConnList, 0, 453 disconnectRequest->fLSAPConn->GetMyLSAPId() << 8 | 99); 454 XTRACE(kAddingLsapToList, 0, disconnectRequest->fLSAPConn); // jdg 455 IrDAErr removeResult = fLSAPConnList->Remove(disconnectRequest->fLSAPConn); 456 ncheck(removeResult); 457 } 458 } 459 //fIrLAP->EnqueueEvent(GetCurrentEvent()); // no, don't do it -- jdg 460 if (1) { // jdg new 461 TIrDisconnectRequest* disconnectRequest = (TIrDisconnectRequest*)GetCurrentEvent(); 462 disconnectRequest->fEvent = kIrDisconnectReplyEvent; // turn into a reply 463 disconnectRequest->fResult = 0; 464 check(disconnectRequest->fLSAPConn); // internal disconnect? 465 disconnectRequest->fLSAPConn->EnqueueEvent(disconnectRequest); // send it back 466 } 467 } 468 break; 469 470 case kIrDisconnectReplyEvent: 471 { 472 // Use the request block for the reply 473 TIrDisconnectReply* disconnectReply = (TIrDisconnectReply*)GetCurrentEvent(); 474 XTRACE(kStandbyDisconnectReplyEvent, 0, 0); 475 // Already disconnected - nothing to do, except return the reply. 476 //check(disconnectReply->fLSAPConn); 477 if (disconnectReply->fLSAPConn == nil) // if internally generated event 478 fIrDA->ReleaseEventBlock(disconnectReply); // then release it here 479 else 480 disconnectReply->fLSAPConn->EnqueueEvent(disconnectReply); 481 482 // jdg: if any deferred events, requeue them now 483 if (fPendingRequests && !fPendingRequests->Empty()) { 484 CListIterator *iter = CListIterator::cListIterator(fPendingRequests); 485 for (TIrEvent* request = (TIrEvent*)iter->FirstItem(); 486 iter->More(); request = (TIrEvent*)iter->NextItem()) { 487 XTRACE(kStandbyDisconnectRequeue, 0, request); 488 check(request->fEvent == kIrListenRequestEvent || request->fEvent == kIrConnectRequestEvent); 489 this->EnqueueEvent(request); 490 } 491 while (!fPendingRequests->Empty()) 492 fPendingRequests->RemoveLast(); 493 494 iter->release(); 495 } 496 fDisconnectPending = false; // safe to connect/listen again 497 } 498 break; 499 500 case kIrGetDataRequestEvent: // if we get a get/put here, just reject it 501 case kIrPutDataRequestEvent: 502 { 503 XTRACE(kUnexpectedEvent, fState, event); 504 TIrGetRequest* rq = (TIrGetRequest*)GetCurrentEvent(); 505 if (rq->fEvent == kIrGetDataRequestEvent) // turn request into reply (could ++ it) 506 rq->fEvent = kIrGetDataReplyEvent; 507 else 508 rq->fEvent = kIrPutDataReplyEvent; 509 rq->fResult = kIrDAErrWrongState; // better than crashing, but why are we here? 510 check(rq->fLSAPConn); 511 rq->fLSAPConn->EnqueueEvent(rq); // return to sender, bad destination 512 } 513 break; 514 515 default: 516 XTRACE(kUnexpectedEvent, fState, event); 517 DebugLog("TIrLAPConn::HandleStandbyStateEvent: bad event"); 518 break; 519 } 520 521} // TIrLAPConn::HandleStandbyStateEvent 522 523 524//-------------------------------------------------------------------------------- 525// HandleConnectOrListenStateEvent 526//-------------------------------------------------------------------------------- 527void TIrLAPConn::HandleConnectOrListenStateEvent(ULong event) 528{ 529 XASSERT(!fConnected); 530 531 switch (event) { 532 case kIrConnectRequestEvent: 533 case kIrListenRequestEvent: 534 { 535 TIrConnLstnRequest* request = (TIrConnLstnRequest*)GetCurrentEvent(); 536 XTRACE(kPendingConnLstnRequestEvent, event, request->fEvent); 537 538 if (fDisconnectPending) { // oops, hold off on this request unti the disconnect is done 539 XTRACE(kPendingConnLstnDeferRequest, 0, GetCurrentEvent()); 540 fPendingRequests->InsertLast(GetCurrentEvent()); 541 check(GetCurrentEvent()->fEvent == kIrListenRequestEvent || GetCurrentEvent()->fEvent == kIrConnectRequestEvent); 542 return; 543 } 544 545 // ***Here is a problem that probably will have to be dealt with when the 546 // IrDA "stack" is used by a mux tool (i.e. multiple endpoints). If a listen 547 // was the first request to initiate a listen to LAP and then a connect request 548 // followed, you need to cancel the pending LAP listen request and replace it 549 // with a connect request. 550 551 // Shouldn't be called if connecting to a different device, reject the request if it comes in that way 552 if (event == kIrConnectRequestEvent) { 553 // This first one checks for the situation described above 554 //XASSERT(fPeerDevAddr != 0); 555 //XASSERT(fPeerDevAddr == request->fDevAddr); 556 // JDG: if 1st was connect & this is going to diff device 557 if (fPeerDevAddr && (fPeerDevAddr != request->fDevAddr)) { // then reject this connect request 558 request->fEvent = kIrConnectReplyEvent; 559 request->fResult = kIrDAErrGeneric; // better err available? 560 check(request->fLSAPConn); 561 request->fLSAPConn->EnqueueEvent(request); // return to sender, bad destination 562 return; 563 } 564 565 // JDG hacking ... won't it ever stop? 566 // we have a connect request, was the first request a listen? if so .... 567 // ask LAP to cancel the pending listen and then send in our connect request. 568 // Foo. Bletch. Ugh. 569 if (fPeerDevAddr == 0) { // if 1st request was a listen ... 570 if (GetLAP->CancelPendingListenRequest()) { // if the lap cancel worked 571 fPeerDevAddr = request->fDevAddr; // save the destination address 572 GetLAP->EnqueueEvent(request); // then send connect req to lap 573 // continue and add the lsapconn to our list 574 // note: the listen request is still on our queue and will finish with the connect 575 } 576 else { // the cancel of the listen failed, reject the connect request (or?) 577 request->fEvent = kIrConnectReplyEvent; 578 request->fResult = kIrDAErrGeneric; // better err available? 579 check(request->fLSAPConn); 580 request->fLSAPConn->EnqueueEvent(request); // return to sender, bad destination 581 return; 582 } 583 } // end first request a listen 584 } // end if connect request 585 586 // Add the lsapConn to the list of pending conns to connect/listen 587 XASSERT(!fLSAPConnList->IsEmpty()); 588 XASSERT(!fLSAPConnList->Contains(request->fLSAPConn)); 589 590 XTRACE(kAddingToLSAPConnList, 1, request->fLSAPConn->GetMyLSAPId() << 8 | 1); 591 XTRACE(kAddingLsapToList, 0, request->fLSAPConn); 592 fLSAPConnList->InsertLast(request->fLSAPConn); 593 594 // No state change 595 } 596 break; 597 598 case kIrConnectReplyEvent: 599 case kIrListenReplyEvent: 600 { 601 TIrConnLstnReply* reply = (TIrConnLstnReply*)GetCurrentEvent(); 602 XTRACE(kPendingConnLstnReplyEvent, event, reply->fResult); 603 { 604 CListIterator *iter = CListIterator::cListIterator(fLSAPConnList); 605 606 // Complete all pending connect/listen requests that are in the list 607 for (TLSAPConn* lsapConn = (TLSAPConn*)iter->FirstItem(); 608 iter->More(); lsapConn = (TLSAPConn*)iter->NextItem()) { 609 TIrConnLstnReply* pendingReply = (TIrConnLstnReply*)lsapConn->GetPendConnLstn(); 610 //check(pendingReply); // TEMP TEMP TEMP -- should track this down 611 if (pendingReply) { 612 // ***Oops, this mess is because some pending buffers are used for the 613 // ***actual request and others aren't - see other note earlier in the file. 614 if (pendingReply && pendingReply->fEvent == kIrConnectRequestEvent) { 615 pendingReply->fEvent = kIrConnectReplyEvent; 616 } 617 else if (pendingReply->fEvent == kIrListenRequestEvent){ 618 pendingReply->fEvent = kIrListenReplyEvent; 619 } 620 else { 621 // Assuming that reply has been set by IrLAP. 622 // I.e. this pendingReply == GetCurrentEvent() 623 XASSERT((pendingReply->fEvent == kIrConnectReplyEvent) || 624 (pendingReply->fEvent == kIrListenReplyEvent)); 625 } 626 pendingReply->fResult = reply->fResult; 627 pendingReply->fDevAddr = reply->fDevAddr; 628 lsapConn->EnqueueEvent(pendingReply); 629 } 630 } 631 iter->release(); 632 633 } // barney block 634 635 // If connect succeeded, move to the active state (California?) 636 if (reply->fResult == noErr) { 637 fPeerDevAddr = reply->fDevAddr; // For listen's benefit 638 fState = kIrLAPConnActive; 639 fConnected = true; 640 } 641 642 // If connect failed, clean up after responding to the requestors 643 // query: shouldn't the cleanup pending be done first? and isn't it a nop here? 644 else { 645 // Removing from end is much faster (and keeps indices valid as items are removed) 646 XTRACE(kAddingToLSAPConnList, 0, 2); // jdg 647 for (FastInt index = fLSAPConnList->GetArraySize() - 1; index >= 0 ; index--) { 648 TLSAPConn* lsapConn = (TLSAPConn*)fLSAPConnList->At(index); 649 // Remove this lsap from the lsap conn list 650 XTRACE(kAddingToLSAPConnList, 0, lsapConn->GetMyLSAPId() << 8 | 2); // jdg 651 XTRACE(kAddingLsapToList, 0, lsapConn); // jdg 652 fLSAPConnList->Remove(lsapConn); 653 // Complete pending get requests and delete any received buffers intended for this conn 654 CleanupPendingGetRequestsAndReplies(lsapConn, errCancel); 655 } 656 fPeerDevAddr = 0; 657 fState = kIrLAPConnStandby; 658 } 659 } 660 break; 661 662 case kIrDisconnectRequestEvent: 663 { 664 TIrDisconnectRequest* disconnectRequest = (TIrDisconnectRequest*)GetCurrentEvent(); 665 XTRACE(kPendingDisconnectRequestEvent, 0, disconnectRequest->fLSAPConn); 666 /*** this didn't work. Just do a lap disconnect, and we'll return all the pending listen/connect 667 requests. Anyone that want's to keep alive can re-issue. 668 ... let's try again 669 ***/ 670 // if the requesting lsapconn owns the event we sent to lap, do a lap disconnect 671 // else we're free to just take it off our tables w/out bothering lap 672 check(disconnectRequest->fLSAPConn); 673 if (GetLAP->GetCurrentRequest() == disconnectRequest->fLSAPConn->GetPendConnLstn()) { 674 fDisconnectPending = true; // hold off on any new listen/connect requests 675 GetLAP->EnqueueEvent(disconnectRequest); // tell lap to blow off the current listen/conn req 676 } 677 else { // lap doesn't have the event from this lsapconn 678 679 XTRACE(kAddingToLSAPConnList, 0, disconnectRequest->fLSAPConn->GetMyLSAPId() << 8 | 3); 680 XTRACE(kAddingLsapToList, 0, disconnectRequest->fLSAPConn); // jdg 681 // Remove this lsap from the lsap conn list and 682 // complete pending get requests and delete any received buffers intended for this conn 683 (void) fLSAPConnList->Remove(disconnectRequest->fLSAPConn); 684 CleanupPendingGetRequestsAndReplies(disconnectRequest->fLSAPConn, errCancel); 685 686 XTRACE(kPendingDisconnectRequestEvent, 2, (fLSAPConnList->IsEmpty()) << 1 ); 687 688 689 // now finish off their original listen/connect request 690 if (disconnectRequest->fLSAPConn->GetPendConnLstn()) { // if the event is there (should be) 691 TIrConnLstnReply* pendingReply = (TIrConnLstnReply*)disconnectRequest->fLSAPConn->GetPendConnLstn(); 692 if (pendingReply->fEvent == kIrConnectRequestEvent) { 693 pendingReply->fEvent = kIrConnectReplyEvent; 694 } 695 else if (pendingReply->fEvent == kIrListenRequestEvent) { 696 pendingReply->fEvent = kIrListenReplyEvent; 697 } 698 //else check(pendingReply->fEvent == 0x1234); // force debugger 699 pendingReply->fResult = errCancel; 700 pendingReply->fLSAPConn->EnqueueEvent(pendingReply); 701 } 702 703 // Use the request buffer for the reply 704 disconnectRequest->fEvent = kIrDisconnectReplyEvent; 705 disconnectRequest->fResult = errCancel; 706 disconnectRequest->fLSAPConn->EnqueueEvent(disconnectRequest); 707 } 708 } 709 break; 710 711 case kIrDisconnectReplyEvent: 712 { 713 TIrDisconnectReply* disconnectReply = (TIrDisconnectReply*)GetCurrentEvent(); 714 XTRACE(kPendingDisconnectReplyEvent, 0, 0); 715 fPeerDevAddr = 0; 716 fConnected = false; 717 fState = kIrLAPConnStandby; 718 //check(disconnectReply->fLSAPConn); // internal disconnect? 719 if (disconnectReply->fLSAPConn == nil) // if lapconn generated disconnect 720 fIrDA->ReleaseEventBlock(disconnectReply); // then release it here 721 else 722 disconnectReply->fLSAPConn->EnqueueEvent(disconnectReply); 723 724 // jdg: if any deferred events, requeue them now 725 if (fPendingRequests && !fPendingRequests->Empty()) { 726 CListIterator *iter = CListIterator::cListIterator(fPendingRequests); 727 for (TIrEvent* request = (TIrEvent*)iter->FirstItem(); 728 iter->More(); request = (TIrEvent*)iter->NextItem()) { 729 XTRACE(kPendingDisconnectRequeue, 0, request); 730 check(request->fEvent == kIrListenRequestEvent || request->fEvent == kIrConnectRequestEvent); 731 this->EnqueueEvent(request); 732 } 733 while (!fPendingRequests->Empty()) 734 fPendingRequests->RemoveLast(); 735 736 iter->release(); 737 } 738 fDisconnectPending = false; // safe to connect/listen again 739 } 740 break; 741 742 default: 743 XTRACE(kUnexpectedEvent, fState, event); 744 DebugLog("TIrLAPConn::HandleConnectOrListenStateEvent: bad event"); 745 break; 746 } 747 748} // TIrLAPConn::HandleConnectOrListenStateEvent 749 750 751//-------------------------------------------------------------------------------- 752// HandleActiveStateEvent 753//-------------------------------------------------------------------------------- 754void TIrLAPConn::HandleActiveStateEvent(ULong event) 755{ 756 XASSERT(fConnected); 757 XASSERT(fPeerDevAddr != 0); 758 759 StopIdleDisconnectTimer(); // always (?) stop the idle timer, we're doing something! 760 switch (event) { 761 case kIrConnectRequestEvent: 762 case kIrListenRequestEvent: 763 { 764 TIrConnLstnRequest* request = (TIrConnLstnRequest*)GetCurrentEvent(); 765 XTRACE(kActiveConnLstnRequestEvent, event, request->fEvent); 766 767 if (fDisconnectPending) { // oops, hold off on this request unti the disconnect is done 768 XTRACE(kActiveConnLstnDeferRequest, 0, GetCurrentEvent()); 769 fPendingRequests->InsertLast(GetCurrentEvent()); 770 check(GetCurrentEvent()->fEvent == kIrListenRequestEvent || GetCurrentEvent()->fEvent == kIrConnectRequestEvent); 771 return; 772 } 773 774 // Shouldn't be called if connecting to a different device 775 // jdg: this should reject the request, not punt. 776 if (event == kIrConnectRequestEvent) { 777 //XASSERT(fPeerDevAddr == request->fDevAddr); 778 if (fPeerDevAddr != request->fDevAddr) { 779 // FIXME -- should add logging here of both addresses to see why the confusion ... 780 request->fEvent = kIrConnectReplyEvent; 781 request->fResult = kIrDAErrGeneric; // better err available? 782 check(request->fLSAPConn); 783 request->fLSAPConn->EnqueueEvent(request); // return to sender, bad destination 784 break; // done with it now 785 } 786 } 787 788 // Add the lsapConn to the list of conns associated w/fPeerDevAddr 789 XASSERT(!fLSAPConnList->Contains(request->fLSAPConn)); 790 XTRACE(kAddingToLSAPConnList, 1, request->fLSAPConn->GetMyLSAPId() << 8 | 4); // jdg 791 XTRACE(kAddingLsapToList, 0, request->fLSAPConn); // jdg 792 fLSAPConnList->InsertLast(request->fLSAPConn); 793 794 // Already connected, reply to the requestor 795 request->fEvent = event == kIrConnectRequestEvent ? kIrConnectReplyEvent : kIrListenReplyEvent; 796 request->fDevAddr = fPeerDevAddr; 797 check(request->fLSAPConn); 798 request->fLSAPConn->EnqueueEvent(request); 799 800 // No state change 801 } 802 break; 803 804 case kIrGetDataRequestEvent: 805 XTRACE(kActiveGetDataRequestEvent, 0, 0); 806 HandleGetDataRequest(); 807 break; 808 809 case kIrCancelGetRequestEvent: 810 { 811 TIrCancelGetRequest* cancelGetRequest = (TIrCancelGetRequest*)GetCurrentEvent(); 812 XTRACE(kActiveCancelGetRequestEvent, 0, 0); 813 CancelPendingGetRequests(cancelGetRequest->fLSAPConn, kIrDAErrRequestCanceled); 814 // Use the request buffer for the reply 815 cancelGetRequest->fEvent = kIrCancelGetReplyEvent; 816 cancelGetRequest->fResult = noErr; 817 check(cancelGetRequest->fLSAPConn); 818 cancelGetRequest->fLSAPConn->EnqueueEvent(cancelGetRequest); 819 } 820 break; 821 822 case kIrDisconnectRequestEvent: 823 { 824 TIrDisconnectRequest* disconnectRequest = (TIrDisconnectRequest*)GetCurrentEvent(); 825 XTRACE(kActiveDisconnectRequestEvent, 0, 0); 826 827 XTRACE(kAddingToLSAPConnList, 0, disconnectRequest->fLSAPConn->GetMyLSAPId() << 8 | 5); // jdg 828 XTRACE(kAddingLsapToList, 0, disconnectRequest->fLSAPConn); // jdg 829 830 // Remove this lsap from the lsap conn list 831 IrDAErr removeResult = fLSAPConnList->Remove(disconnectRequest->fLSAPConn); 832 // Complete pending get requests and delete any received buffers intended for this conn 833 CleanupPendingGetRequestsAndReplies(disconnectRequest->fLSAPConn, kIrDAErrGeneric); 834 835 // Note: if I do a disconnect after getting a read complete, this gets called twice, once 836 // for the disconnect request, and (I think) once to clean up the pending get request. 837 /////////////////////////////////////////////////////////////////////////// 838 // start of ugly hack to kill off name server if it's all that's left 839 // this gets weird cause it's "the" pending event for LAP. Grrr. 840 if (removeResult == noErr && fLSAPConnList->GetArraySize() == 1) { // if only one thing left on the list 841 TLSAPConn* lsapConn = (TLSAPConn*)fLSAPConnList->At(0); // grab it 842 if (lsapConn->GetMyLSAPId() == kNameServerLSAPId) { // sigh, if the name server 843 TIrConnLstnReply* pendingReply = (TIrConnLstnReply*)lsapConn->GetPendConnLstn(); // get it's event 844 if (pendingReply && 845 (pendingReply->fEvent == kIrListenRequestEvent || // it was a listen request, but now that 846 pendingReply->fEvent == kIrGetDataRequestEvent)) { // we're active, it's a get request 847 // NEW: let's start a timer here and do the lap disconnect after N seconds of 848 // nothing going on ... 849 StartIdleDisconnectTimer(); // start the idle disconnect timer 850 // 851 // Nuke the name server's listen so we can do a LAP disconnect 852 // 853 // check(pendingReply->fEvent == kIrGetDataRequestEvent); // just making sure 854 // removeResult = fLSAPConnList->Remove(lsapConn); // get name server off our list 855 // CancelPendingGetRequests(lsapConn, errCancel); // this will q up the get response 856 } 857 } 858 } 859 //////// 860 //if ((removeResult == noErr) && fLSAPConnList->IsEmpty() && fIrDA->Disconnecting()) 861 if (disconnectRequest->fEvent == kIrDisconnectRequestEvent) { // if "the" event is still available 862 ////////*** with the idle disconnect timer, we never request a lap disconnect here anymore 863 if (((removeResult == noErr) && fLSAPConnList->IsEmpty())) { 864 // If no more connections [and shutting down] - disconnect IrLAP 865 fDisconnectPending = true; // hold off on any new listen/connect requests 866 GetLAP->EnqueueEvent(disconnectRequest); 867 } 868 else { 869 // Use the request buffer for the reply 870 disconnectRequest->fEvent = kIrDisconnectReplyEvent; 871 disconnectRequest->fResult = errCancel; 872 check(disconnectRequest->fLSAPConn); 873 disconnectRequest->fLSAPConn->EnqueueEvent(disconnectRequest); 874 } 875 } 876 // else the event was a get and turned into a get reply already by CleanupPendingGetRequestsAndReplies 877 } 878 break; 879 880 case kIrDisconnectReplyEvent: 881 { 882 TIrDisconnectReply* disconnectReply = (TIrDisconnectReply*)GetCurrentEvent(); 883 XTRACE(kActiveDisconnectReplyEvent, 0, 0); 884 fPeerDevAddr = 0; 885 fConnected = false; 886 fState = kIrLAPConnStandby; 887 888 // new - if this is a disconnect generated by our idle timer, then fLSAPConn will be nil 889 if (disconnectReply->fLSAPConn == nil) { // if we allocated the event 890 fIrDA->ReleaseEventBlock(disconnectReply); // then release it here 891 //DebugLog(" disconnect due to idle"); 892 } 893 else { // else send the disconnect complete back to the lsap 894 disconnectReply->fLSAPConn->EnqueueEvent(disconnectReply); 895 } 896 897 // jdg: if any deferred events, requeue them now 898 if (fPendingRequests && !fPendingRequests->Empty()) { 899 CListIterator *iter = CListIterator::cListIterator(fPendingRequests); 900 for (TIrEvent* request = (TIrEvent*)iter->FirstItem(); 901 iter->More(); request = (TIrEvent*)iter->NextItem()) { 902 XTRACE(kActiveDisconnectRequeue, 0, request); 903 check(request->fEvent == kIrListenRequestEvent || request->fEvent == kIrConnectRequestEvent); 904 this->EnqueueEvent(request); 905 } 906 while (!fPendingRequests->Empty()) 907 fPendingRequests->RemoveLast(); 908 909 iter->release(); 910 } 911 fDisconnectPending = false; // safe to connect/listen again 912 } 913 break; 914 915 case kIdleDisconnectEvent: // idle disconnect timer fired 916 { 917 if (fLSAPConnList->GetArraySize() == 1) { // if only one thing on the list 918 TLSAPConn* lsapConn = (TLSAPConn*)fLSAPConnList->At(0); // grab ias server entry 919 if (lsapConn && 920 lsapConn->GetMyLSAPId() == kNameServerLSAPId) { // ifthe name server 921 TIrConnLstnReply* pendingReply = (TIrConnLstnReply*)lsapConn->GetPendConnLstn(); // get it's event 922 if (pendingReply && // a listen is really a get 923 (pendingReply->fEvent == kIrGetDataRequestEvent)) { // we're active, it's a get request 924 IrDAErr removeResult; 925 removeResult = fLSAPConnList->Remove(lsapConn); // get name server off our list 926 CancelPendingGetRequests(lsapConn, errCancel); // this will q up the get response 927 928 TIrDisconnectRequest* disconnectRequest = (TIrDisconnectRequest*) 929 fIrDA->GrabEventBlock(kIrDisconnectRequestEvent, 930 sizeof(TIrDisconnectRequest)); 931 check(disconnectRequest); // pretty sad if no events and idle! 932 if (disconnectRequest) { 933 disconnectRequest->fLSAPConn = nil; // lapconn generated event (not LSAPConn) 934 fDisconnectPending = true; // hold off on any new listen/connect requests 935 GetLAP->EnqueueEvent(disconnectRequest); 936 } 937 } 938 } 939 } 940 } 941 break; 942 943 default: 944 XTRACE(kUnexpectedEvent, fState, event); 945 DebugLog("TIrLAPConn::HandleActiveStateEvent: bad event"); 946 break; 947 } 948 949} // TIrLAPConn::HandleActiveStateEvent 950 951 952//================================ Helper methods ================================ 953 954 955//-------------------------------------------------------------------------------- 956// HandleGetDataRequest 957//-------------------------------------------------------------------------------- 958void TIrLAPConn::HandleGetDataRequest() 959{ 960 Boolean matchFound = false; 961 TIrGetRequest* getRequest = (TIrGetRequest*)GetCurrentEvent(); 962 963 // Data may have already arrived and is in the unmatched get replys list 964 // If it is, then the get data request can complete right now 965 CListIterator *iter = CListIterator::cListIterator(fUnmatchedGetReplys); 966 for (CBufferSegment* replyBuffer = (CBufferSegment*)iter->FirstItem(); 967 iter->More(); replyBuffer = (CBufferSegment*)iter->NextItem()) { 968 TLMPDUHeader header; 969 ULong headerLength; 970 Boolean validFormat; 971 972 validFormat = ExtractHeader(replyBuffer, header, headerLength); 973 XASSERT(validFormat); 974 975 if (DataDelivered(getRequest, header, headerLength, replyBuffer)) { 976 fUnmatchedGetReplys->Remove(replyBuffer); 977 matchFound = true; 978 break; 979 } 980 } 981 iter->release(); 982 983 // Data is not in one of the buffers, add the request to the pending get requests. 984 if (!matchFound) { 985 XTRACE(kLogAddingGetRequest1, 0, getRequest); 986 XTRACE(kLogAddingGetRequest2, 0, getRequest->fLSAPConn); 987 fPendingGetRequests->InsertLast(getRequest); 988 XTRACE(kLogAddingGetRequest3, fPendingGetRequests->Count(), getRequest->fLSAPConn->GetMyLSAPId()); 989 } 990 991} // TIrLAPConn::HandleGetDataRequest 992 993 994//-------------------------------------------------------------------------------- 995// CleanupPendingGetRequestsAndReplies 996//-------------------------------------------------------------------------------- 997void TIrLAPConn::CleanupPendingGetRequestsAndReplies(TLSAPConn* lsapConn, IrDAErr returnCode) 998{ 999 XTRACE(kLogCleanupPendingGetRequestsAndRepliesEntry, 0, lsapConn); 1000 1001 // Complete any pending get requests with an error. Default is kIRErrGeneric 1002 CancelPendingGetRequests( lsapConn, returnCode ); // ***FIXME: Better error return? 1003 1004 XTRACE(kLogCleanupPendingGetRequestsAndReplies2, 0, fUnmatchedGetReplys); 1005 1006 // Free any pending received buffers for this lsap connection 1007 if (fUnmatchedGetReplys) { 1008 CListIterator *iter = CListIterator::cListIterator(fUnmatchedGetReplys); 1009 for (CBufferSegment* replyBuffer = (CBufferSegment*)iter->FirstItem(); 1010 iter->More(); replyBuffer = (CBufferSegment*)iter->NextItem()) { 1011 TLMPDUHeader header; 1012 ULong headerLength; 1013 1014 //Boolean validFormat = ExtractHeader(replyBuffer, header, headerLength); 1015 Boolean validFormat; 1016 1017 XTRACE(kLogCleanupPendingGetRequestsAndReplies3, 0, replyBuffer); 1018 1019 validFormat = ExtractHeader(replyBuffer, header, headerLength); 1020 XASSERT(validFormat); 1021 1022 // If this buffer is/was for the lsapConn being removed 1023 if (lsapConn->YourData(header, true /*justChecking*/)) { 1024 XTRACE( kCleanupPendingRcvdBufEvent, 0, returnCode ); 1025 fUnmatchedGetReplys->Remove(replyBuffer); 1026 // Release the buffer. 1027 GetLAP->ReleaseInputBuffer(replyBuffer); // give the buffer back to lap 1028 } 1029 } 1030 iter->release(); 1031 } 1032 1033} // TIrLAPConn::CleanupPendingGetRequestsAndReplies 1034 1035 1036//-------------------------------------------------------------------------------- 1037// CancelPendingGetRequests 1038//-------------------------------------------------------------------------------- 1039void TIrLAPConn::CancelPendingGetRequests(TLSAPConn* lsapConn, IrDAErr returnCode) 1040{ 1041 // Complete any pending get requests with an error 1042 XTRACE(kLogCancelPendingGetRequestsEntry, 0, lsapConn); 1043 1044 check(lsapConn); 1045 if (fPendingGetRequests && !fPendingGetRequests->Empty()) { 1046 CListIterator *iter = CListIterator::cListIterator(fPendingGetRequests); 1047 for (TIrGetRequest* getRequest = (TIrGetRequest*)iter->FirstItem(); 1048 iter->More(); getRequest = (TIrGetRequest*)iter->NextItem()) { 1049 if (getRequest->fLSAPConn == lsapConn) { 1050 XTRACE(kLogCancelPendingGetRequests, 0, lsapConn); 1051 fPendingGetRequests->Remove(getRequest); // get this req off the list 1052 // Send the reply 1053 getRequest->fEvent = kIrGetDataReplyEvent; 1054 getRequest->fResult = returnCode; 1055 lsapConn->EnqueueEvent(getRequest); 1056 // Theoretically there should only be one outstanding get request for 1057 // this lsapConn, so you should be able to break out of the loop here. 1058 // But, who ever believed in theory besides Albert Einstein? 1059 // Could add some debug only logic and an assert to test this... 1060 // 1061 // jdg: I don't trust remove in the middle of an iterate, so let's 1062 // recurse and return instead of finishing the iteration. Note this 1063 // only recurses when we've found and processed an event for this 1064 // lsapconn, so we're not going to recurse forever. 1065 iter->release(); // we're done with this iteration engine 1066 CancelPendingGetRequests(lsapConn, returnCode); 1067 return; 1068 } 1069 } 1070 iter->release(); 1071 } 1072 XTRACE(kLogCancelPendingGetRequestsExit, 0, lsapConn); 1073 1074} // TIrLAPConn::CancelPendingGetRequests 1075 1076 1077//-------------------------------------------------------------------------------- 1078// Demultiplexor 1079//-------------------------------------------------------------------------------- 1080void TIrLAPConn::Demultiplexor(CBufferSegment* inputBuffer) 1081{ 1082 TLMPDUHeader header; 1083 ULong headerLength; 1084 Boolean validFormat; 1085 Boolean matchFound = false; 1086 1087 XTRACE(kLogDemux, 0, inputBuffer); 1088 1089 validFormat = ExtractHeader(inputBuffer, header, headerLength); 1090 1091 if (!validFormat || ((header.fOpCode & ~kLMPDUReplyFlag) == kLMPDUAccessModeRequest)) { 1092 XTRACE(kDemuxInvalidHeaderEvent, 0, 0); 1093 // We're responding. Don't keep looking. 1094 matchFound = true; 1095 // Release the buffer 1096 GetLAP->ReleaseInputBuffer(inputBuffer); 1097 // Send a response for access requests (ignore the erroneous access confirms) 1098 if (validFormat && (header.fOpCode == kLMPDUAccessModeRequest) && (header.fMode <= kIrLMPExclusiveMode)) { 1099 ReplyToInvalidFrame(header, kLMPDUAccessModeReply, kIrLMPDUControlUnsupported); 1100 } 1101 } 1102 1103 // Some received data has arrived. If a match can be found in the pending get requests 1104 // then that request can be completed and the buffer can be freed up for reuse. 1105 if (!matchFound) { 1106 XTRACE(kLogDemuxCheckingGets1, 0, fPendingGetRequests->Count()); 1107 CListIterator *iter = CListIterator::cListIterator(fPendingGetRequests); 1108 for (TIrGetRequest* getRequest = (TIrGetRequest*)iter->FirstItem(); 1109 iter->More(); getRequest = (TIrGetRequest*)iter->NextItem()) { 1110 XTRACE(kLogDemuxCheckingGets2, 0, getRequest); 1111 1112 if (DataDelivered(getRequest, header, headerLength, inputBuffer)) { 1113 fPendingGetRequests->Remove(getRequest); 1114 XTRACE(kDemuxGetPendingEvent, 0, getRequest); 1115 matchFound = true; 1116 break; 1117 } 1118 } 1119 iter->release(); 1120 } 1121 1122 // No one is waiting for the data. Is it a potential reply? - cache it until its requested. 1123 if (!matchFound) { 1124 CListIterator *iter = CListIterator::cListIterator(fLSAPConnList); 1125 for (TLSAPConn* lsapConn = (TLSAPConn*)iter->FirstItem(); 1126 iter->More(); lsapConn = (TLSAPConn*)iter->NextItem()) { 1127 if (lsapConn->YourData(header, true /*justChecking*/)) { 1128 fUnmatchedGetReplys->InsertLast(inputBuffer); 1129 XTRACE(kDemuxReplyPostedEvent, 0, inputBuffer); 1130 XTRACE(kDemuxReplyPostedEvent2, 0, lsapConn); 1131 matchFound = true; 1132 break; 1133 } 1134 } 1135 iter->release(); 1136 } 1137 1138 // No one connected that this could belong to. 1139 if (!matchFound) { 1140 XTRACE(kDemuxNoReceiverEvent, 0, 0); 1141 // Release the buffer 1142 GetLAP->ReleaseInputBuffer(inputBuffer); 1143 // Send a disconnect response 1144 UByte respCode; 1145 if (header.fOpCode == kLMPDUDataEvent) { 1146 respCode = kIrDataSentOnDiscLSAPConn; 1147 } 1148 else if (header.fOpCode == kLMPDUConnectRequest) { 1149 respCode = kIrNoAvailableLMMuxClient; 1150 } 1151 else { 1152 respCode = kIrUserRequestedDisconnect; 1153 } 1154 ReplyToInvalidFrame(header, kLMPDUDisconnectEvent, respCode); 1155 } 1156 1157} // TIrLAPConn::Demultiplexor 1158 1159 1160//-------------------------------------------------------------------------------- 1161// ReplyToInvalidFrame 1162//-------------------------------------------------------------------------------- 1163void TIrLAPConn::ReplyToInvalidFrame(TLMPDUHeader& header, UByte replyOpCode, UByte replyInfo) 1164{ 1165 TIrPutRequest* putRequest; 1166 1167 // jdg: note that the check for nil fLSAPConn for this case is 1168 // in the PutComplete routine of IrLAP 1169 1170 putRequest = (TIrPutRequest*)fIrDA->GrabEventBlock(kIrPutDataRequestEvent, sizeof(TIrPutRequest)); 1171 // Ignore this if no memory to get request block 1172 if (putRequest != nil) { 1173 putRequest->fLSAPConn = nil; // Don't respond to putRequest, just free the block 1174 putRequest->fData = nil; 1175 putRequest->fOffset = 0; 1176 putRequest->fLength = 0; 1177 putRequest->fDstLSAPId = header.fSrcLSAPId | kLMPDUControlFlag; 1178 putRequest->fSrcLSAPId = header.fDstLSAPId & ~kLMPDUControlFlag; 1179 putRequest->fCtrlOpCode = replyOpCode; 1180 putRequest->fCtrlInfo = replyInfo; 1181 GetLAP->EnqueueEvent(putRequest); 1182 } 1183 1184} // TIrLAPConn::ReplyToInvalidFrame 1185 1186 1187//-------------------------------------------------------------------------------- 1188// ExtractHeader 1189//-------------------------------------------------------------------------------- 1190Boolean TIrLAPConn::ExtractHeader(CBufferSegment* inputBuffer, TLMPDUHeader& header, ULong& length) 1191{ 1192 ULong headerLength; 1193 1194 // Need to reseek to 0 as this may be called multiple times 1195 inputBuffer->Seek(0, kPosBeg); 1196 1197 // Get the header info 1198 headerLength = inputBuffer->Getn(&header.fDstLSAPId, sizeof(TLMPDUHeader)); 1199 XASSERT(headerLength >= 2); 1200 if (headerLength < 2) { 1201 // LM-PDU header requires dst/src minimum 1202 return false; 1203 } 1204 else if (header.fDstLSAPId & kLMPDUControlFlag) { 1205 header.fDstLSAPId &= ~kLMPDUControlFlag; 1206 if (headerLength == 2) { 1207 // Control header requires opcode minimum 1208 return false; 1209 } else if (headerLength == 3) { 1210 // Set unspecified info field to 0 1211 header.fInfo = 0; 1212 } 1213 switch (header.fOpCode) { 1214 case kLMPDUConnectRequest: 1215 case kLMPDUConnectReply: 1216 case kLMPDUDisconnectEvent: 1217 headerLength = Min(headerLength, 4); 1218 break; 1219 1220 case kLMPDUAccessModeRequest: 1221 case kLMPDUAccessModeReply: 1222 break; 1223 1224 default: 1225 return false; 1226 } 1227 } 1228 else { 1229 headerLength = 2; 1230 header.fOpCode = kLMPDUDataEvent; 1231 header.fInfo = 0; 1232 } 1233 1234 // Invalid lsap ids 1235 if ((header.fDstLSAPId > kLastValidLSAPId) || (header.fSrcLSAPId > kLastValidLSAPId)) { 1236 return false; 1237 } 1238 1239 length = headerLength; 1240 return true; 1241 1242} // TIrLAPConn::ExtractHeader 1243 1244 1245//-------------------------------------------------------------------------------- 1246// DataDelivered 1247//-------------------------------------------------------------------------------- 1248Boolean TIrLAPConn::DataDelivered(TIrGetRequest* getRequest, TLMPDUHeader& header, ULong headerLength, CBufferSegment* dataBuffer) 1249{ 1250 if (getRequest->fLSAPConn->YourData(header, false /*justChecking*/)) { 1251 ULong written = 0; 1252 1253 UInt32 dataLength = dataBuffer->GetBufferSize() - headerLength; 1254 if (getRequest->fData && (dataLength > 0)) { 1255 //if (getRequest->fLength < dataLength) { // jdg 1256 // DebugPrintf("About to die, fLength=%d, datalength %d", 1257 // getRequest->fLength, dataLength); 1258 //} 1259 XASSERT(getRequest->fLength >= dataLength); 1260 getRequest->fData->Seek(getRequest->fOffset, kPosBeg); 1261 written = getRequest->fData->Putn(dataBuffer->GetBufferPtr() + headerLength, dataLength); 1262 XASSERT(written == dataLength); 1263 } 1264 1265 // Fill in the fields for the reply 1266 getRequest->fEvent = kIrGetDataReplyEvent; 1267 getRequest->fResult = noErr; 1268 getRequest->fLength = written; 1269 getRequest->fCtrlOpCode = header.fOpCode; 1270 getRequest->fCtrlInfo = header.fInfo; 1271 1272 // Send the reply 1273 check(getRequest->fLSAPConn); 1274 getRequest->fLSAPConn->EnqueueEvent(getRequest); 1275 1276 // Release the buffer 1277 XTRACE(kDemuxReleaseBufferEvent, 0, dataBuffer); 1278 GetLAP->ReleaseInputBuffer(dataBuffer); 1279 1280 return true; 1281 } 1282 1283 return false; 1284 1285} // TIrLAPConn::DataDelivered 1286 1287 1288//-------------------------------------------------------------------------------- 1289// FillInLMPDUHeader 1290//-------------------------------------------------------------------------------- 1291ULong TIrLAPConn::FillInLMPDUHeader(TIrPutRequest* putRequest, UByte* buffer) 1292{ 1293 ULong infoLength; 1294 TLMPDUHeader* lmPDUHeader = (TLMPDUHeader*)buffer; 1295 1296 XTRACE(kLogFillInLMPDUHeader1, 0, putRequest); 1297 XTRACE(kLogFillInLMPDUHeader2, 0, buffer); 1298 1299 // Fill out the info 1300 lmPDUHeader->fDstLSAPId = putRequest->fDstLSAPId; 1301 lmPDUHeader->fSrcLSAPId = putRequest->fSrcLSAPId; 1302 1303 if (putRequest->fCtrlOpCode != kLMPDUDataEvent) { 1304 lmPDUHeader->fDstLSAPId |= kLMPDUControlFlag; 1305 lmPDUHeader->fOpCode = putRequest->fCtrlOpCode; 1306 lmPDUHeader->fInfo = putRequest->fCtrlInfo; 1307 if (putRequest->fCtrlOpCode != kLMPDUAccessModeReply) { 1308 infoLength = 4; 1309 } 1310 else { 1311 // Access mode follows "header" for access mode reply frame 1312 buffer[4] = kIrLMPMultiplexedMode; 1313 infoLength = 5; 1314 } 1315 } 1316 else { 1317 infoLength = 2; 1318 } 1319 1320 return infoLength; 1321 1322} // TIrLAPConn::FillInLMPDUHeader 1323 1324//-------------------------------------------------------------------------------- 1325// StartIdleDisconnectTimer 1326//-------------------------------------------------------------------------------- 1327void TIrLAPConn::StartIdleDisconnectTimer() 1328{ 1329 XTRACE(kLogStartIdleDisconnectTimer, 0, 0); 1330 // could just overload timer2, but this keeps sanity a little longer 1331 fIrDA->StartTimer(kTimer_LAPConn, 1 * kSeconds, kIdleDisconnectEvent); 1332 1333} // TIrLAPConn::StartIdleDisconnectTimer 1334 1335 1336//-------------------------------------------------------------------------------- 1337// StopIdleDisconnectTimer 1338//-------------------------------------------------------------------------------- 1339void TIrLAPConn::StopIdleDisconnectTimer() 1340{ 1341 XTRACE(kLogStopIdleDisconnectTimer, 0, 0); 1342 if (fIrDA) // if init'd 1343 fIrDA->StopTimer(kTimer_LAPConn); 1344} // TIrLAPConn::StopIdleDisconnectTimer 1345 1346// 1347// Do idle disconnect ... now, don't wait for the timer 1348// 1349void TIrLAPConn::DoIdleDisconnect() 1350{ 1351 XTRACE(kLogDoIdleDisconnect, 0, 0); 1352 1353 StopIdleDisconnectTimer(); // first stop the real timer 1354 if (fState == kIrLAPConnActive) // and if there is an active connect 1355 NextState(kIdleDisconnectEvent); // do the idle disconnect logic 1356} 1357 1358//-------------------------------------------------------------------------------- 1359// TimerComplete 1360//-------------------------------------------------------------------------------- 1361void TIrLAPConn::TimerComplete(ULong refCon) 1362{ 1363//#pragma unused(refCon) 1364 XASSERT(refCon == kIrConnWatchdogExpiredEvent || refCon == kIdleDisconnectEvent); 1365 1366 if (refCon == kIrConnWatchdogExpiredEvent) { // one second timer has fired 1367 CListIterator *iter = CListIterator::cListIterator(fLSAPConnList); 1368 XTRACE(kLogConnWatchDogFired, 0, 0); 1369 1370 // Let all of the active lsap conn's know that the timer has fired 1371 for (TLSAPConn* lsapConn = (TLSAPConn*)iter->FirstItem(); iter->More(); lsapConn = (TLSAPConn*)iter->NextItem()) { 1372 lsapConn->OneSecTickerComplete(); 1373 } 1374 iter->release(); 1375 } 1376 else { 1377 XTRACE(kLogIdleDisconnectFired, 0, 0); 1378 if (refCon == kIdleDisconnectEvent) // the idle disconnect timer has fired 1379 if (fState == kIrLAPConnActive) // just another sanity check 1380 NextState(refCon); 1381 } 1382 1383} // TIrLAPConn::TimerComplete 1384 1385