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