(file) Return to protocol.c CVS log (file) (dir) Up to [OMI] / omi / protocol

   1 mike  1.1 /*
   2           **==============================================================================
   3           **
   4           ** Open Management Infrastructure (OMI)
   5           **
   6           ** Copyright (c) Microsoft Corporation
   7           **
   8 krisbash 1.4 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
   9              ** use this file except in compliance with the License. You may obtain a copy
  10              ** of the License at
  11              **
  12              **     http://www.apache.org/licenses/LICENSE-2.0
  13 mike     1.1 **
  14              ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15 krisbash 1.4 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  16              ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  17              ** MERCHANTABLITY OR NON-INFRINGEMENT.
  18 mike     1.1 **
  19 krisbash 1.4 ** See the Apache 2 License for the specific language governing permissions
  20 mike     1.1 ** and limitations under the License.
  21              **
  22              **==============================================================================
  23              */
  24              
  25              #include <assert.h>
  26              #include "protocol.h"
  27 mike     1.2 #include <sock/addr.h>
  28              #include <sock/sock.h>
  29              #include <sock/selector.h>
  30 mike     1.1 #include <base/buf.h>
  31              #include <base/log.h>
  32              #include <base/result.h>
  33              #include <base/user.h>
  34 krisbash 1.4 #include <pal/strings.h>
  35              #include <pal/format.h>
  36              #include <pal/file.h>
  37              #include <pal/sleep.h>
  38              
  39              // #define  ENABLE_TRACING 1
  40              #ifdef ENABLE_TRACING
  41              # define TRACING_LEVEL 4
  42              # include <deprecated/logging/logging.h>
  43 mike     1.1 #else
  44 krisbash 1.4 # define LOGE2(a)
  45              # define LOGW2(a)
  46              # define LOGD2(a)
  47              # define LOGX2(a)
  48 mike     1.1 #endif
  49              
  50              /*
  51              **==============================================================================
  52              **
  53              ** Local definitions:
  54              **
  55              **==============================================================================
  56              */
  57              
  58              static const MI_Uint32 _MAGIC = 0xC764445E;
  59              
  60 krisbash 1.4 /*
  61              **==============================================================================
  62              */
  63              STRAND_DEBUGNAME1( ProtocolSocketServer, PostMsg );
  64              STRAND_DEBUGNAME2( ProtocolFromSocket, PostMsg, ReadyToFinish );
  65              STRAND_DEBUGNAME3( ProtocolConnector, PostMsg, ReadyToFinish, ConnectEvent );
  66              
  67              /*
  68              **==============================================================================
  69              */
  70              
  71              ProtocolSocket* _ProtocolSocket_Server_New(
  72                  _In_        ProtocolBase *          protocolBase,
  73                  _In_        Sock                    sock );
  74              
  75              /* helper functions result */
  76              typedef enum _Protocol_CallbackResult
  77              {
  78                  PRT_CONTINUE,
  79                  PRT_RETURN_TRUE,
  80                  PRT_RETURN_FALSE
  81 krisbash 1.4 }
  82              Protocol_CallbackResult;
  83              
  84              /* Forward declaration */
  85              static void _PrepareMessageForSending(
  86                  ProtocolSocket *handler);
  87              
  88              static MI_Boolean _RequestCallbackWrite(
  89                  ProtocolSocket* handler);
  90              
  91              static MI_Result _ProtocolSocketAndBase_Delete(
  92                  ProtocolSocketAndBase* self);
  93              
  94              
  95              
  96              /*
  97              **==============================================================================
  98              */
  99              
 100              static MI_Result _SendIN_IO_thread(
 101                  ProtocolBase* self,
 102 krisbash 1.4     ProtocolSocket* sendSock,
 103                  Message* message);
 104              
 105              static void _FreeAuthData(
 106                  ProtocolSocket* h);
 107              
 108              static void _ProtocolSocket_Cleanup(ProtocolSocket* handler);
 109              
 110              /* Signature must not have return type so we created this wrapper */
 111              static void _SendIN_IO_thread_wrapper(void* self_, Message* message)
 112              {
 113                  ProtocolSocket* self = (ProtocolSocket*) self_;
 114                  ProtocolBase* protocolBase = (ProtocolBase*)self->base.data;
 115                  MI_Result result;
 116              
 117                  result = _SendIN_IO_thread( protocolBase, self, message);
 118              
 119                  if(result != MI_RESULT_OK)
 120                  {
 121                      trace_ProtocolSocket_PostFailed( &self->strand.info.interaction, self->strand.info.interaction.other );
 122                      // This will do following things
 123 krisbash 1.4         // 1. cleaning up the message if any and acking it
 124                      // 2. closing the other side
 125                      // 3. Setting the closeOtherScheduled flag which will drop all further Posts after this one and also skip this logic in the SELECTOR_REMOVE callback
 126                      _ProtocolSocket_Cleanup(self);
 127                  }
 128              }
 129              
 130              MI_INLINE
 131              void _ProtocolSocket_Release(
 132                  _In_ ProtocolSocket* self,
 133                  _In_ CallSite cs)
 134              {
 135                  ptrdiff_t ref = Atomic_Dec(&self->refCount);
 136              
 137              #if defined(CONFIG_ENABLE_DEBUG)
 138                  {
 139                      trace_ProtocolSocket_Release(cs.file, (MI_Uint32)cs.line, self, (unsigned int)ref);
 140                  }
 141              #endif /* defined(CONFIG_ENABLE_DEBUG) */
 142              
 143                  if (0 == ref)
 144 krisbash 1.4         /* Free self pointer */
 145                      PAL_Free(self);
 146              
 147                  (void)cs;
 148              }
 149              
 150              #define ProtocolSocket_Release(self) \
 151                  _ProtocolSocket_Release(self, CALLSITE)
 152              
 153              #ifdef _PREFAST_
 154              #pragma prefast (push)
 155              #pragma prefast (disable: 28931) // unused assignment of variable ref
 156              #endif /* _PREFAST_ */
 157              
 158              MI_INLINE
 159              void _ProtocolSocket_Addref(
 160                  _In_ ProtocolSocket* self,
 161                  _In_ CallSite cs)
 162              {
 163                  ptrdiff_t ref = Atomic_Inc(&self->refCount);
 164              
 165 krisbash 1.4     (void)cs;
 166                  ((void)ref);
 167              #if defined(CONFIG_ENABLE_DEBUG)
 168                  {
 169                      trace_ProtocolSocket_Addref(cs.file, (MI_Uint32)cs.line, self, (unsigned int)ref);
 170                  }
 171              #endif /* defined(CONFIG_ENABLE_DEBUG) */
 172              }
 173              
 174              #ifdef _PREFAST_
 175              #pragma prefast (pop)
 176              #endif /* _PREFAST_ */
 177              
 178              #define ProtocolSocket_Addref(self) \
 179                  _ProtocolSocket_Addref(self, CALLSITE)
 180              
 181              MI_INLINE
 182              void _ProtocolSocket_Delete(
 183                  _In_ ProtocolSocket* self)
 184              {
 185                  ProtocolSocket_Release(self);
 186 krisbash 1.4 }
 187              
 188              MI_Result _AddProtocolSocket_Handler(
 189                  Selector* self,
 190                  ProtocolSocket* protocolSocket)
 191              {
 192                  MI_Result r = MI_RESULT_OK;
 193                  ProtocolSocket_Addref(protocolSocket);
 194                  r = Selector_AddHandler(self, &(protocolSocket->base));
 195                  return r;
 196              }
 197              
 198              static void _ProtocolSocket_Cleanup(ProtocolSocket* handler)
 199 mike     1.1 {
 200 krisbash 1.4     if(handler->closeOtherScheduled)
 201                      return;
 202              
 203                  handler->closeOtherScheduled = MI_TRUE;
 204              
 205                  _FreeAuthData(handler);
 206              
 207                  /* free outstanding messages, batch */
 208                  if (handler->receivingBatch)
 209                      Batch_Destroy( handler->receivingBatch );
 210              
 211                  handler->receivingBatch = 0;
 212              
 213                  if (handler->message)
 214                  {
 215                      MI_Boolean internalMessage = Message_IsInternalMessage( handler->message );
 216              
 217                      Message_Release(handler->message);
 218                      handler->message = 0;
 219              
 220                      //ACK up if the message just sent was posted from up
 221 krisbash 1.4         if (!internalMessage)
 222                          Strand_ScheduleAck( &handler->strand );
 223                  }
 224              
 225                  Sock_Close(handler->base.sock);
 226              
 227                  /* Mark handler as closed */
 228                  handler->base.sock = INVALID_SOCK;
 229 mike     1.1 
 230 krisbash 1.4     Strand_ScheduleClose( &handler->strand );
 231              }
 232 mike     1.1 
 233 krisbash 1.4 /*
 234              **==============================================================================
 235              */
 236 mike     1.1 
 237 krisbash 1.4 void _ProtocolSocket_CheckAbort( _In_ ProtocolSocket* self )
 238              {
 239                  if( !self->strand.info.thisClosedOther )
 240                  {
 241                      MI_Uint64 currentTimeUsec = 0;
 242                      ProtocolBase* protocolBase = (ProtocolBase*)self->base.data;
 243 mike     1.1 
 244 krisbash 1.4         trace_ProtocolSocket_TimeoutTrigger( self );
 245                      // provoke a timeout to close/delete the socket
 246                      PAL_Time(&currentTimeUsec);
 247                      self->base.fireTimeoutAt = currentTimeUsec;
 248                      Selector_Wakeup( protocolBase->selector, MI_TRUE );
 249                  }
 250 mike     1.1 }
 251              
 252 krisbash 1.4 #ifdef _PREFAST_
 253              #pragma prefast (push)
 254              #pragma prefast (disable: 26001) // bogus "we know the strand points to the middle of the ProtocolSocket struct" and Linux sal parser doesnt recognize something like _Readable_elements_(_Inexpressible_(ProtocolSocket))
 255              #endif /* _PREFAST_ */
 256              
 257              void _ProtocolSocket_Post( _In_ Strand* self_, _In_ Message* msg)
 258 mike     1.1 {
 259 krisbash 1.4     ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 260                  ProtocolBase* protocolBase = (ProtocolBase*)self->base.data;
 261              
 262                  DEBUG_ASSERT( NULL != self_ );
 263              
 264                  DEBUG_ASSERT(self->message == NULL);
 265                  self->base.mask &= ~SELECTOR_READ;
 266              
 267                  trace_ProtocolSocket_PostingOnInteraction( &self->strand.info.interaction, self->strand.info.interaction.other );
 268              
 269                  if( self->closeOtherScheduled ||
 270                      ( MI_RESULT_OK != Selector_CallInIOThread(
 271                      protocolBase->selector, _SendIN_IO_thread_wrapper, self, msg ) ))
 272                  {
 273                      trace_ProtocolSocket_PostFailed( &self->strand.info.interaction, self->strand.info.interaction.other );
 274                      Strand_ScheduleAck( &self->strand );
 275                  }
 276              }
 277              
 278              void _ProtocolSocket_PostControl( _In_ Strand* self, _In_ Message* msg)
 279              {
 280 krisbash 1.4     DEBUG_ASSERT( MI_FALSE );  // not used yet
 281              }
 282              
 283              void _ProtocolSocket_Cancel( _In_ Strand* self_)
 284              {
 285                  ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 286              
 287                  trace_ProtocolSocket_CancelReceived(
 288                      self->strand.info.thisClosedOther,
 289                      &self->strand.info.interaction,
 290                      self->strand.info.interaction.other );
 291              
 292                  // Abort the socket
 293                  _ProtocolSocket_CheckAbort( self );
 294              }
 295              
 296              void _ProtocolSocket_Ack( _In_ Strand* self_)
 297              {
 298                  ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 299                  ProtocolBase* protocolBase = (ProtocolBase*)self->base.data;
 300                  DEBUG_ASSERT( NULL != self_ );
 301 krisbash 1.4 
 302                  trace_ProtocolSocket_Ack( &self_->info.interaction, self_->info.interaction.other );
 303                  if (!(self->base.mask & SELECTOR_WRITE))
 304                      self->base.mask |= SELECTOR_READ;
 305                  Selector_Wakeup( protocolBase->selector, MI_FALSE );
 306              }
 307              
 308              void _ProtocolSocket_Close( _In_ Strand* self_)
 309              {
 310                  ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 311              
 312                  trace_ProtocolSocket_Close(
 313                      self->strand.info.thisClosedOther,
 314                      &self->strand.info.interaction,
 315                      self->strand.info.interaction.other );
 316              
 317                  if( !self->strand.canceled )
 318                  {
 319                      _ProtocolSocket_CheckAbort( self );
 320                  }
 321              }
 322 krisbash 1.4 
 323              void _ProtocolSocket_Finish( _In_ Strand* self_)
 324              {
 325                  ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 326                  ProtocolBase* protocolBase = (ProtocolBase*)self->base.data;
 327                  DEBUG_ASSERT( NULL != self_ );
 328              
 329                  trace_ProtocolSocket_Finish( self );
 330              
 331                  if( protocolBase->type == PRT_TYPE_LISTENER )
 332                  {
 333                      _ProtocolSocket_Delete( self );
 334                  }
 335                  else
 336                  {
 337                      _ProtocolSocketAndBase_Delete( (ProtocolSocketAndBase*)self );
 338                  }
 339 mike     1.1 }
 340              
 341 krisbash 1.4 // PROTOCOLSOCKET_STRANDAUX_POSTMSG
 342              void _ProtocolSocket_Aux_PostMsg( _In_ Strand* self_)
 343 mike     1.1 {
 344 krisbash 1.4     ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 345                  ProtocolBase* protocolBase = (ProtocolBase*)self->base.data;
 346                  Message * msg = self->strand.info.otherMsg;
 347              
 348                  self->strand.info.otherMsg = NULL;
 349              
 350                  if( !self->strand.info.thisClosedOther )
 351                  {
 352                      // process the case where the interaction for the connection has not been opened yet
 353                      if( NULL != protocolBase->callback && NULL == self->strand.info.interaction.other )
 354                      {
 355                          Strand_Open( self_, protocolBase->callback, protocolBase->callbackData, NULL, MI_FALSE );
 356                      }
 357              
 358                      if( Message_IsRequest(msg) )
 359                      {
 360                          RequestMsg* request = (RequestMsg*)msg;
 361                          AuthInfo_Copy( &request->authInfo, &self->authInfo );
 362                      }
 363              
 364                      DEBUG_ASSERT( NULL != self->strand.info.interaction.other );
 365 mike     1.1 
 366 krisbash 1.4         // Leave the strand for the case where this is a new request on server
 367                      // and the provider is in-proc and takes over the thread
 368                      Strand_PostAndLeaveStrand( &self->strand, msg );
 369                  }
 370 mike     1.1 
 371 krisbash 1.4     // now we can remove the reference added before Strand_ScheduleAux( PROTOCOLSOCKET_STRANDAUX_POSTMSG )
 372                  Message_Release( msg );
 373              }
 374 mike     1.1 
 375 krisbash 1.4 // PROTOCOLSOCKET_STRANDAUX_READYTOFINISH
 376              void _ProtocolSocket_Aux_ReadyToFinish( _In_ Strand* self_)
 377              {
 378                  Strand_ResetDelayFinish(self_);
 379              }
 380 mike     1.1 
 381 krisbash 1.4 // PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT
 382              void _ProtocolSocket_Aux_ConnectEvent( _In_ Strand* self_)
 383 mike     1.1 {
 384 krisbash 1.4     ProtocolSocket* self = FromOffset( ProtocolSocket, strand, self_ );
 385                  ProtocolEventConnect* msg = ProtocolEventConnect_New(self->isConnected);
 386              
 387                  DEBUG_ASSERT( NULL != self->strand.info.interaction.other );
 388              
 389                  Strand_PostControl( &self->strand, &msg->base );
 390                  Message_Release(&msg->base);
 391 mike     1.1 }
 392              
 393 krisbash 1.4 #ifdef _PREFAST_
 394              #pragma prefast (pop)
 395              #endif /* _PREFAST_ */
 396 mike     1.1 
 397 krisbash 1.4 /*
 398                  Object that implements the binary protocol endpoint on a TCP Socket
 399                  There are 3 different types of objects that can be created:
 400                  - ProtocolSocketServer each client connection ON server side
 401                  - ProtocolConnector client connection TO the server
 402                  - ProtocolFromSocket either side of the out-of-proc (agent) connection
 403              
 404                  Behaviour:
 405                  - Post tries to schedule the operation on the IO thread (thru selector)
 406                     if that fails it sends the Ack immediately
 407                  - Post control is not implemented
 408                  - both Cancel and Close check if the connection has already been closed and
 409                     if not it triggers a timeout that will close it
 410                  - Ack reactivates keep reading by setting SELECTOR_READ (if no
 411                     write is in progress)
 412                  - Shutdown:
 413                     The ProtocolSocketServer objects are shutdown/deleted thru the normal
 414                     Strand logic (once the interaction is closed).
 415                     However the other Protocol objects are not deleted that way and instead
 416                     they are deleted manually by the object that uses them once it has
 417                     finished its Protocol_Run execution. That works by setting Strand_SetDelayFinish
 418 krisbash 1.4        (which sets the delayFinish flag on the strand)  on object creation,
 419                     and then calling ProtocolSocketAndBase_ReadyToFinish which schedules
 420                     the auxiliary function PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT
 421                     which in turn disables that flag allowing the object to be deleted.
 422              
 423                  Unique features and special Behavour:
 424                  - When a complete message has been read instead of scheduling a post
 425                     the auxiliary function PROTOCOLSOCKET_STRANDAUX_POSTMSG is
 426                     scheduled instead. That function takes care of opening the interaction
 427                     (if not opened already) and posting using Strand_PostAndLeaveStrand
 428                     (which avoids holding the strand in case the thread is going to be hijacked
 429                     by the provider in the processing of that post).
 430                  - On the ProtocolConnector type once the connection succeds of fails
 431                     a PostControl notifies of that event by scheduling the auxiliary function
 432                     PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT
 433              */
 434              static StrandFT _ProtocolSocket_FT = {
 435                  _ProtocolSocket_Post,
 436                  _ProtocolSocket_PostControl,
 437                  _ProtocolSocket_Ack,
 438                  _ProtocolSocket_Cancel,
 439 krisbash 1.4     _ProtocolSocket_Close,
 440                  _ProtocolSocket_Finish,
 441                  NULL,
 442                  _ProtocolSocket_Aux_PostMsg,
 443                  _ProtocolSocket_Aux_ReadyToFinish,
 444                  _ProtocolSocket_Aux_ConnectEvent,
 445                  NULL,
 446                  NULL };
 447 mike     1.1 
 448              /**************** Auth-support **********************************************************/
 449              /* remove auth file and free auth data */
 450              static void _FreeAuthData(
 451 krisbash 1.4     ProtocolSocket* h)
 452 mike     1.1 {
 453                  if (h->authData)
 454                  {
 455              #if defined(CONFIG_POSIX)
 456                      unlink(h->authData->path);
 457              #endif
 458 krisbash 1.4         PAL_Free(h->authData);
 459 mike     1.1         h->authData = 0;
 460                  }
 461              }
 462              
 463              /* Creates and sends authentication request message */
 464              static MI_Boolean _SendAuthRequest(
 465 krisbash 1.4     ProtocolSocket* h,
 466 mike     1.1     const char* user,
 467                  const char* password,
 468                  const char* fileContent)
 469              {
 470                  BinProtocolNotification* req;
 471 krisbash 1.4     MI_Boolean retVal = MI_TRUE;
 472 mike     1.1 
 473                  req = BinProtocolNotification_New(BinNotificationConnectRequest);
 474              
 475                  if (!req)
 476                      return MI_FALSE;
 477              
 478                  if (user && *user)
 479 krisbash 1.4     {
 480 mike     1.1         req->user = Batch_Strdup(req->base.batch, user);
 481 krisbash 1.4         if (!req->user)
 482                      {
 483                          BinProtocolNotification_Release(req);
 484                          return MI_FALSE;
 485                      }
 486                  }
 487 mike     1.1 
 488                  if (password && *password)
 489 krisbash 1.4     {
 490 mike     1.1         req->password = Batch_Strdup(req->base.batch, password);
 491 krisbash 1.4         if (!req->password)
 492                      {
 493                          BinProtocolNotification_Release(req);
 494                          return MI_FALSE;
 495                      }
 496                  }
 497 mike     1.1 
 498                  req->uid = geteuid();
 499                  req->gid = getegid();
 500              
 501                  if (fileContent)
 502                  {
 503                      memcpy(req->authData, fileContent, sizeof(req->authData));
 504                  }
 505              
 506                  /* send message */
 507                  {
 508 krisbash 1.4         DEBUG_ASSERT(h->message == NULL);
 509                      h->message = (Message*) req;
 510 mike     1.1 
 511                      Message_AddRef(&req->base);
 512              
 513                      _PrepareMessageForSending(h);
 514 krisbash 1.4         retVal = _RequestCallbackWrite(h);
 515 mike     1.1     }
 516              
 517                  BinProtocolNotification_Release(req);
 518              
 519 krisbash 1.4     return retVal;
 520 mike     1.1 }
 521              
 522              static MI_Boolean _SendAuthResponse(
 523 krisbash 1.4     ProtocolSocket* h,
 524 mike     1.1     MI_Result result,
 525                  const char* path)
 526              {
 527                  BinProtocolNotification* req;
 528 krisbash 1.4     MI_Boolean retVal = MI_TRUE;
 529 mike     1.1 
 530                  req = BinProtocolNotification_New(BinNotificationConnectResponse);
 531              
 532                  if (!req)
 533                      return MI_FALSE;
 534              
 535                  req->result = result;
 536                  if (path && *path)
 537 krisbash 1.4     {
 538 mike     1.1         req->authFile = Batch_Strdup(req->base.batch, path);
 539 krisbash 1.4         if (!req->authFile)
 540                      {
 541                          BinProtocolNotification_Release(req);
 542                          return MI_FALSE;
 543                      }
 544                  }
 545 mike     1.1 
 546                  /* send message */
 547                  {
 548 krisbash 1.4         DEBUG_ASSERT(h->message == NULL);
 549                      h->message = (Message*)req;
 550 mike     1.1         Message_AddRef(&req->base);
 551              
 552                      _PrepareMessageForSending(h);
 553 krisbash 1.4         retVal = _RequestCallbackWrite(h);
 554 mike     1.1     }
 555              
 556                  BinProtocolNotification_Release(req);
 557              
 558 krisbash 1.4     return retVal;
 559 mike     1.1 }
 560              
 561              /*
 562 krisbash 1.4     Processes auht message while waiting second connect request
 563 mike     1.1     with content of the file.
 564                  Updates auth states correspondingly.
 565                  Parameters:
 566                  handler - socket handler
 567                  binMsg - BinProtocolNotification message with connect request/response
 568              
 569                  Return:
 570                  "TRUE" if connection should stay open; "FALSE" if auth failed
 571                      and conneciton should be closed immediately
 572              */
 573              static MI_Boolean _ProcessAuthMessageWaitingConnectRequestFileData(
 574 krisbash 1.4     ProtocolSocket* handler,
 575 mike     1.1     BinProtocolNotification* binMsg)
 576              {
 577                  /* un-expected message */
 578                  if (BinNotificationConnectRequest != binMsg->type)
 579                      return MI_FALSE;
 580              
 581                  /* Check internal state */
 582                  if (!handler->authData)
 583                      return MI_FALSE;
 584              
 585                  if (0 == memcmp(binMsg->authData, handler->authData->authRandom, AUTH_RANDOM_DATA_SIZE))
 586                  {
 587                      if (!_SendAuthResponse(handler, MI_RESULT_OK, NULL))
 588                          return MI_FALSE;
 589              
 590                      /* Auth ok */
 591                      handler->authState = PRT_AUTH_OK;
 592                      _FreeAuthData(handler);
 593              
 594                      /* Get gid from user name */
 595 krisbash 1.4         if (0 != GetUserGidByUid(handler->authInfo.uid, &handler->authInfo.gid))
 596 mike     1.1         {
 597 krisbash 1.4             trace_CannotGetUserGidForUid((int)handler->authInfo.uid);
 598 mike     1.1             return MI_FALSE;
 599                      }
 600              
 601                      return MI_TRUE;
 602                  }
 603              
 604 krisbash 1.4     trace_AuthFailed_RandomDataMismatch();
 605 mike     1.1 
 606                  /* Auth failed */
 607                  _SendAuthResponse(handler, MI_RESULT_ACCESS_DENIED, NULL);
 608                  handler->authState = PRT_AUTH_FAILED;
 609                  return MI_FALSE;
 610              }
 611              
 612              /*
 613 krisbash 1.4     Processes auht message while waiting connect request
 614 mike     1.1     Updates auth states correspondingly.
 615                  Parameters:
 616                  handler - socket handler
 617                  binMsg - BinProtocolNotification message with connect request/response
 618              
 619                  Return:
 620                  "TRUE" if connection should stay open; "FALSE" if auth failed
 621 krisbash 1.4         and connection should be closed immediately
 622 mike     1.1 */
 623              static MI_Boolean _ProcessAuthMessageWaitingConnectRequest(
 624 krisbash 1.4     ProtocolSocket* handler,
 625 mike     1.1     BinProtocolNotification* binMsg)
 626              {
 627                  /* un-expected message */
 628                  if (BinNotificationConnectRequest != binMsg->type)
 629                      return MI_FALSE;
 630              
 631                  /* Use explicit credentials if provided */
 632                  if (binMsg->user)
 633                  {
 634                      /* use empty password if not set */
 635                      if (!binMsg->password)
 636                          binMsg->password = "";
 637              
 638 krisbash 1.4         if (0 == AuthenticateUser(binMsg->user, binMsg->password) &&
 639                          0 == LookupUser(binMsg->user, &handler->authInfo.uid, &handler->authInfo.gid))
 640 mike     1.1         {
 641                          if (!_SendAuthResponse(handler, MI_RESULT_OK, NULL))
 642                              return MI_FALSE;
 643              
 644                          /* Auth ok */
 645                          handler->authState = PRT_AUTH_OK;
 646                          _FreeAuthData(handler);
 647                          return MI_TRUE;
 648                      }
 649              
 650 krisbash 1.4         trace_AuthFailed_ForUser(scs(binMsg->user));
 651 mike     1.1 
 652                      /* Auth failed */
 653                      _SendAuthResponse(handler, MI_RESULT_ACCESS_DENIED, NULL);
 654                      handler->authState = PRT_AUTH_FAILED;
 655                      return MI_FALSE;
 656                  }
 657              
 658 krisbash 1.4     /* If system supports connection-based auth, use it for
 659 mike     1.1         implicit auth */
 660 krisbash 1.4     if (0 == GetUIDByConnection((int)handler->base.sock, &handler->authInfo.uid, &handler->authInfo.gid))
 661 mike     1.1     {
 662                      if (!_SendAuthResponse(handler, MI_RESULT_OK, NULL))
 663                          return MI_FALSE;
 664              
 665                      /* Auth ok */
 666                      handler->authState = PRT_AUTH_OK;
 667                      return MI_TRUE;
 668                  }
 669              #if defined(CONFIG_OS_WINDOWS)
 670                  {
 671                      if (!_SendAuthResponse(handler, MI_RESULT_OK, NULL))
 672                          return MI_FALSE;
 673              
 674 krisbash 1.4         /* Ignore Auth by setting it to OK */
 675                      handler->authInfo.uid = -1;
 676                      handler->authInfo.gid = -1;
 677 mike     1.1         handler->authState = PRT_AUTH_OK;
 678                      return MI_TRUE;
 679                  }
 680              #else
 681              
 682 krisbash 1.4     /* If valid uid provided, try implicit credentials (file-based)
 683 mike     1.1         gid will be taken from user name */
 684                  {
 685 krisbash 1.4         handler->authData = (Protocol_AuthData*)PAL_Calloc(1, sizeof(Protocol_AuthData));
 686 mike     1.1 
 687                      if (!handler->authData)
 688                      {
 689                          /* Auth failed */
 690                          _SendAuthResponse(handler, MI_RESULT_ACCESS_DENIED, NULL);
 691                          handler->authState = PRT_AUTH_FAILED;
 692                          return MI_FALSE;
 693                      }
 694              
 695                      if (0 != CreateAuthFile(binMsg->uid, handler->authData->authRandom, AUTH_RANDOM_DATA_SIZE, handler->authData->path))
 696                      {
 697 krisbash 1.4             trace_CannotCreateFileForUser((int)binMsg->uid);
 698 mike     1.1 
 699                          /* Auth failed */
 700                          _SendAuthResponse(handler, MI_RESULT_ACCESS_DENIED, NULL);
 701                          handler->authState = PRT_AUTH_FAILED;
 702                          return MI_FALSE;
 703                      }
 704              
 705                      /* send file name to the client */
 706                      if (!_SendAuthResponse(handler, MI_RESULT_IN_PROGRESS, handler->authData->path))
 707                          return MI_FALSE;
 708              
 709                      /* Auth posponed */
 710                      handler->authState = PRT_AUTH_WAIT_CONNECTION_REQUEST_WITH_FILE_DATA;
 711              
 712                      /* Remember uid we used to create file */
 713 krisbash 1.4         handler->authInfo.uid = binMsg->uid;
 714                      handler->authInfo.gid = -1;
 715 mike     1.1 
 716                      return MI_TRUE;
 717              
 718                  }
 719              #endif
 720              }
 721              
 722              /*
 723                  Processes auht message (either connect request or connect-response)
 724                  Updates auth states correspondingly.
 725                  Parameters:
 726                  handler - socket handler
 727                  msg - BinProtocolNotification message with connect request/response
 728              
 729                  Return:
 730                  "TRUE" if connection should stay open; "FALSE" if auth failed
 731                      and conneciton should be closed immediately
 732              */
 733              static MI_Boolean _ProcessAuthMessage(
 734 krisbash 1.4     ProtocolSocket* handler,
 735 mike     1.1     Message *msg)
 736              {
 737 krisbash 1.4     ProtocolBase* protocolBase = (ProtocolBase*)handler->base.data;
 738 mike     1.1     BinProtocolNotification* binMsg;
 739              
 740                  if (msg->tag != BinProtocolNotificationTag)
 741                      return MI_FALSE;
 742              
 743                  binMsg = (BinProtocolNotification*) msg;
 744              
 745                  /* server waiting client's first request? */
 746                  if (PRT_AUTH_WAIT_CONNECTION_REQUEST == handler->authState)
 747                  {
 748                      return _ProcessAuthMessageWaitingConnectRequest(handler, binMsg);
 749                  }
 750              
 751                  /* server waiting for client's file's content request? */
 752                  if (PRT_AUTH_WAIT_CONNECTION_REQUEST_WITH_FILE_DATA == handler->authState)
 753                  {
 754                      return _ProcessAuthMessageWaitingConnectRequestFileData(handler, binMsg);
 755                  }
 756              
 757                  /* client waiting for server's response? */
 758                  if (PRT_AUTH_WAIT_CONNECTION_RESPONSE == handler->authState)
 759 mike     1.1     {
 760                      /* un-expected message */
 761                      if (BinNotificationConnectResponse != binMsg->type)
 762                          return MI_FALSE;
 763              
 764                      if (binMsg->result == MI_RESULT_OK)
 765                      {
 766                          handler->authState = PRT_AUTH_OK;
 767              
 768 krisbash 1.4             if( Atomic_Swap(&handler->connectEventSent, 1) == 0 )
 769                          {
 770                              DEBUG_ASSERT( PRT_TYPE_CONNECTOR == protocolBase->type );
 771                              handler->isConnected = MI_TRUE;
 772                              Strand_ScheduleAux( &handler->strand, PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT );
 773                          }
 774              
 775 mike     1.1             return MI_TRUE;
 776                      }
 777                      else if (binMsg->result == MI_RESULT_IN_PROGRESS && binMsg->authFile)
 778                      {
 779                          /* send back file's content */
 780                          char buf[AUTH_RANDOM_DATA_SIZE];
 781 krisbash 1.4             FILE* is = File_Open(binMsg->authFile, "r");
 782 mike     1.1 
 783                          if (!is)
 784                          {
 785 krisbash 1.4                 trace_CannotOpenAuthFile(scs(binMsg->authFile));
 786 mike     1.1                 return MI_FALSE;
 787                          }
 788              
 789                          /* Read auth data from the file. */
 790                          if (sizeof(buf) != fread(buf, 1, sizeof(buf), is))
 791                          {
 792 krisbash 1.4                 trace_CannotReadAuthFile(scs(binMsg->authFile));
 793                              File_Close(is);
 794 mike     1.1                 return MI_FALSE;
 795                          }
 796              
 797 krisbash 1.4             File_Close(is);
 798 mike     1.1             return _SendAuthRequest(handler, 0, 0, buf);
 799                      }
 800                      else
 801                      {
 802 krisbash 1.4             // PROTOCOLEVENT_DISCONNECT
 803                          if( PRT_TYPE_CONNECTOR == protocolBase->type )
 804 mike     1.1             {
 805 krisbash 1.4                 if( Atomic_Swap(&handler->connectEventSent, 1) == 0 )
 806 mike     1.1                 {
 807 krisbash 1.4                     DEBUG_ASSERT( !handler->isConnected );
 808                                  Strand_ScheduleAux( &handler->strand, PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT );
 809 mike     1.1                 }
 810                          }
 811                      }
 812              
 813                      return MI_FALSE;
 814                  }
 815              
 816                  /* unknown state? */
 817                  return MI_FALSE;
 818              }
 819              
 820              static void _PrepareMessageForSending(
 821 krisbash 1.4     ProtocolSocket *handler)
 822 mike     1.1 {
 823 krisbash 1.4     DEBUG_ASSERT(handler->message != NULL);
 824 mike     1.1 
 825                  /* reset sending attributes */
 826                  handler->sendingPageIndex = 0;
 827                  handler->sentCurrentBlockBytes = 0;
 828              
 829                  memset(&handler->send_buffer,0,sizeof(handler->send_buffer));
 830                  handler->send_buffer.base.magic = PROTOCOL_MAGIC;
 831                  handler->send_buffer.base.version = PROTOCOL_VERSION;
 832                  handler->send_buffer.base.pageCount = (MI_Uint32)Batch_GetPageCount(handler->message->batch);
 833                  handler->send_buffer.base.originalMessagePointer = handler->message;
 834              
 835                  /* ATTN! */
 836 krisbash 1.4     DEBUG_ASSERT (handler->send_buffer.base.pageCount <= PROTOCOL_HEADER_MAX_PAGES);
 837 mike     1.1 
 838                  /* get page info */
 839              
 840                  Batch_GetPageInfo(
 841                      handler->message->batch, handler->send_buffer.batchInfo);
 842              
 843                  /* mark handler as 'want-write' */
 844                  handler->base.mask |= SELECTOR_WRITE;
 845              
 846              }
 847              
 848              static MI_Boolean _RequestCallbackWrite(
 849 krisbash 1.4     ProtocolSocket* handler)
 850 mike     1.1 {
 851                  /* try to write to socket as much as possible */
 852                  size_t sent;
 853                  MI_Result r;
 854 krisbash 1.4     size_t retries = 0;
 855 mike     1.1 
 856 krisbash 1.4     for (;;)
 857 mike     1.1     {
 858                      /* buffers to write */
 859 krisbash 1.4         IOVec buffers[32];
 860 mike     1.1         size_t counter;
 861              
 862                      if ( !handler->message )
 863                      { /* nothing to send */
 864                          handler->base.mask &= ~SELECTOR_WRITE;
 865 krisbash 1.4             if (!handler->strand.info.thisAckPending)
 866                              handler->base.mask |= SELECTOR_READ;
 867                          trace_SocketSendCompleted(handler);
 868 mike     1.1             return MI_TRUE;
 869                      }
 870              
 871                      for ( counter = 0; counter < MI_COUNT(buffers); counter++ )
 872                      {
 873                          const char* buf;
 874                          MI_Uint32 index = (MI_Uint32)(handler->sendingPageIndex + counter);
 875              
 876 krisbash 1.4             buf = (index == 0) ?
 877                              &handler->send_buffer :
 878 mike     1.1                 handler->send_buffer.batchInfo[index - 1].pagePointer;
 879              
 880                          if (!counter)
 881                              buf += handler->sentCurrentBlockBytes;
 882              
 883                          buffers[counter].ptr = (void*)buf;
 884              
 885                          buffers[counter].len = (index == 0) ? (sizeof(HeaderBase) + sizeof(Header_BatchInfoItem) * handler->send_buffer.base.pageCount)
 886                              : handler->send_buffer.batchInfo[index - 1].pageSize;
 887              
 888                          if (!counter)
 889                              buffers[counter].len -= handler->sentCurrentBlockBytes;
 890              
 891 krisbash 1.4             if (index == handler->send_buffer.base.pageCount)
 892 mike     1.1             {
 893                              counter++;
 894                              break;
 895                          }
 896                      }
 897              
 898                      sent = 0;
 899              
 900 krisbash 1.4         do
 901                      {
 902                          r = Sock_WriteV(handler->base.sock, buffers, counter, &sent);
 903 mike     1.1 
 904 krisbash 1.4             LOGD2((ZT("_RequestCallbackWrite - Sent %lu bytes with result %d (%s)"), sent, (int)r, mistrerror(r)));
 905 mike     1.1 
 906 krisbash 1.4             if ( r == MI_RESULT_OK && 0 == sent )
 907                          {
 908                              trace_Socket_ConnectionClosed(handler);
 909                              return MI_FALSE; /* connection closed */
 910                          }
 911 mike     1.1 
 912 krisbash 1.4             if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
 913                          {
 914                              trace_Socket_Sending_Error(handler, r);
 915                              if( r == MI_RESULT_NOT_FOUND && retries < 5 )
 916                              {
 917                                  ++retries;
 918                                  Sleep_Milliseconds(100);
 919                                  continue;
 920                              }
 921                              return MI_FALSE;
 922                          }
 923                      }
 924                      while (r == MI_RESULT_NOT_FOUND);
 925 mike     1.1 
 926                      if (!sent)
 927 krisbash 1.4         {
 928                          /* trace_QueueingSocket(handler); */
 929 mike     1.1             return MI_TRUE;
 930 krisbash 1.4         }
 931 mike     1.1 
 932                      /* update index */
 933                      for ( counter = 0; counter < MI_COUNT(buffers); counter++ )
 934                      {
 935                          if (!sent)
 936                              break;
 937              
 938                          if (sent >= buffers[counter].len)
 939                          {
 940                              sent -= buffers[counter].len;
 941                              handler->sendingPageIndex++;
 942                              handler->sentCurrentBlockBytes = 0;
 943                              continue;
 944                          }
 945              
 946                          handler->sentCurrentBlockBytes += sent;
 947                          break;
 948                      }
 949              
 950 krisbash 1.4         if (handler->sendingPageIndex - 1 == (int)handler->send_buffer.base.pageCount)
 951 mike     1.1         {
 952 krisbash 1.4             MI_Boolean internalMessage = Message_IsInternalMessage( handler->message );
 953              
 954                          LOGD2((ZT("_RequestCallbackWrite - Message sent. tag %d (%s)"), handler->message->tag, messagetagnamestr(handler->message->tag)));
 955 mike     1.1 
 956 krisbash 1.4             //for all protocol internal messages, i.e messages that were not posted from up
 957 mike     1.1             /* next message */
 958                          Message_Release(handler->message);
 959                          handler->message = 0;
 960              
 961 krisbash 1.4             //ACK up if the message just sent was posted from up
 962                          if (!internalMessage)
 963                              Strand_ScheduleAck( &handler->strand );
 964 mike     1.1         }
 965                  }
 966              }
 967              
 968              /*
 969                  Processes incoming message, including:
 970                      - decoding message from batch
 971                      - invoking callback to process message
 972              
 973                  Parameters:
 974                      handler - pointer to received data
 975                  Returns:
 976                      it returns result if 'callback' with the followinf meaning:
 977                      MI_TRUE - to continue normal operations
 978                      MI_FALSE - to close connection
 979              */
 980 krisbash 1.4 static Protocol_CallbackResult _ProcessReceivedMessage(
 981                  ProtocolSocket* handler)
 982 mike     1.1 {
 983                  MI_Result r;
 984                  Message* msg = 0;
 985 krisbash 1.4     ProtocolBase* protocolBase = (ProtocolBase*)handler->base.data;
 986                  Protocol_CallbackResult ret = PRT_RETURN_FALSE;
 987 mike     1.1 
 988                  /* create a message from a batch */
 989                  r = MessageFromBatch(
 990                      handler->receivingBatch,
 991                      handler->recv_buffer.base.originalMessagePointer,
 992                      handler->recv_buffer.batchInfo,
 993                      handler->recv_buffer.base.pageCount,
 994 krisbash 1.4         protocolBase->skipInstanceUnpack,
 995 mike     1.1         &msg);
 996              
 997 krisbash 1.4     if(MI_RESULT_OK != r)
 998                  {
 999                      trace_RestoreMessage_Failed(r, tcs(Result_ToString(r)));
1000                      Batch_Destroy( handler->receivingBatch );
1001                  }
1002              
1003                  /* clean up the state */
1004                  handler->receivingBatch = 0;
1005                  handler->receivingPageIndex = 0;
1006                  memset(&handler->recv_buffer,0,sizeof(handler->recv_buffer));
1007              
1008 mike     1.1     if (MI_RESULT_OK == r)
1009                  {
1010 krisbash 1.4         trace_Socket_ReceivedMessage(
1011                          msg,
1012                          msg->tag,
1013                          MessageName(msg->tag),
1014                          msg->operationId );
1015 mike     1.1 
1016                      if (PRT_AUTH_OK != handler->authState)
1017                      {
1018 krisbash 1.4             if( _ProcessAuthMessage(handler, msg) )
1019                              ret = PRT_CONTINUE;
1020 mike     1.1         }
1021                      else
1022                      {
1023 krisbash 1.4             //disable receiving anything else until this message is ack'ed
1024                          handler->base.mask &= ~SELECTOR_READ;
1025                          // We cannot use Strand_SchedulePost becase we have to do
1026                          // special treatment here (leave the strand in post)
1027                          // We can use otherMsg to store this though
1028                          Message_AddRef( msg );  // since the actual message use can be delayed
1029                          handler->strand.info.otherMsg = msg;
1030                          Strand_ScheduleAux( &handler->strand, PROTOCOLSOCKET_STRANDAUX_POSTMSG );
1031                          ret = PRT_RETURN_TRUE;
1032 mike     1.1         }
1033              
1034                      Message_Release(msg);
1035                  }
1036              
1037                  return ret;
1038              }
1039              
1040              static Protocol_CallbackResult _ReadHeader(
1041 krisbash 1.4     ProtocolSocket* handler)
1042 mike     1.1 {
1043                  char* buf;
1044                  size_t buf_size, received;
1045                  MI_Result r;
1046                  MI_Uint32 index;
1047              
1048                  /* are we done with header? */
1049 krisbash 1.4     if (0 != handler->receivingPageIndex)
1050 mike     1.1         return PRT_CONTINUE;
1051              
1052 krisbash 1.4     for ( ; ; )
1053 mike     1.1     {
1054                      buf = (char*)&handler->recv_buffer;
1055                      buf_size = (sizeof(HeaderBase) + sizeof(Header_BatchInfoItem) * handler->recv_buffer.base.pageCount);
1056                      received = 0;
1057              
1058                      r = Sock_Read(handler->base.sock, buf + handler->receivedCurrentBlockBytes, buf_size - handler->receivedCurrentBlockBytes, &received);
1059              
1060 krisbash 1.4         LOGD2((ZT("_ReadHeader - Read %lu bytes with result %d (%s)"), received, (int)r, mistrerror(r)));
1061 mike     1.1 
1062                      if ( r == MI_RESULT_OK && 0 == received )
1063 krisbash 1.4         {
1064                          trace_Socket_ReadHeader_ConnectionClosed(handler);
1065                          return PRT_RETURN_FALSE; /* connection closed */
1066                      }
1067 mike     1.1 
1068                      if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
1069 krisbash 1.4         {
1070                          trace_Socket_ReadingHeader_Error(handler, r);
1071 mike     1.1             return PRT_RETURN_FALSE;
1072 krisbash 1.4         }
1073 mike     1.1 
1074                      if (!received)
1075                          return PRT_RETURN_TRUE;
1076              
1077                      handler->receivedCurrentBlockBytes += received;
1078              
1079                      if (handler->receivedCurrentBlockBytes == buf_size)
1080                      {
1081                          /* got header - validate/allocate as required */
1082                          if (handler->recv_buffer.base.pageCount > PROTOCOL_HEADER_MAX_PAGES)
1083 krisbash 1.4             {
1084                              trace_Socket_ReadingHeader_ErrorPageCount(handler);
1085 mike     1.1                 return PRT_RETURN_FALSE;
1086 krisbash 1.4             }
1087 mike     1.1 
1088                          if (handler->recv_buffer.base.magic != PROTOCOL_MAGIC)
1089 krisbash 1.4             {
1090                              trace_Socket_ReadingHeader_ErrorMagic(handler);
1091 mike     1.1                 return PRT_RETURN_FALSE;
1092 krisbash 1.4             }
1093 mike     1.1 
1094                          for (index =0; index < handler->recv_buffer.base.pageCount; index++)
1095                          {
1096 krisbash 1.4                 if (handler->recv_buffer.batchInfo[index].pageSize > MAX_ENVELOPE_SIZE)
1097                              {
1098                                  trace_Socket_ReadingHeader_ErrorBatchSize(handler);
1099 mike     1.1                     return PRT_RETURN_FALSE;
1100 krisbash 1.4                 }
1101 mike     1.1             }
1102              
1103                          /* check if page info is also retrieved */
1104 krisbash 1.4             if (buf_size != ((sizeof(HeaderBase) + sizeof(Header_BatchInfoItem) * handler->recv_buffer.base.pageCount)))
1105 mike     1.1                 continue;
1106              
1107                          /* create a batch */
1108                          if (!Batch_CreateBatchByPageInfo(
1109 krisbash 1.4                 &handler->receivingBatch,
1110 mike     1.1                 handler->recv_buffer.batchInfo,
1111                              handler->recv_buffer.base.pageCount))
1112 krisbash 1.4             {
1113                              trace_Socket_ReadingHeader_ErrorCreatingBatch(handler);
1114 mike     1.1                 return PRT_RETURN_FALSE;
1115 krisbash 1.4             }
1116 mike     1.1 
1117                          /* skip to next page */
1118                          handler->receivingPageIndex++;
1119                          handler->receivedCurrentBlockBytes = 0;
1120              
1121                          if ( (handler->receivingPageIndex - 1) == (int)handler->recv_buffer.base.pageCount )
1122                          {   /* received the whole message - process it */
1123 krisbash 1.4                 return _ProcessReceivedMessage(handler);
1124 mike     1.1             }
1125                          break;
1126                      } /* if we read the whole buffer */
1127 krisbash 1.4     } /* for(;;) */
1128 mike     1.1     return PRT_CONTINUE;
1129              }
1130              
1131              static Protocol_CallbackResult _ReadAllPages(
1132 krisbash 1.4     ProtocolSocket* handler)
1133 mike     1.1 {
1134                  size_t received;
1135                  MI_Result r;
1136                  /* buffers to write */
1137                  IOVec   buffers[32];
1138                  size_t counter;
1139              
1140                  /* are we done with header? - if not, return 'continue' */
1141 krisbash 1.4     if (0 == handler->receivingPageIndex)
1142 mike     1.1         return PRT_CONTINUE;
1143              
1144              
1145                  for ( counter = 0; counter < MI_COUNT(buffers); counter++ )
1146                  {
1147                      const char* buf;
1148                      MI_Uint32 index = (MI_Uint32)(handler->receivingPageIndex + counter);
1149              
1150                      buf = Batch_GetPageByIndex(handler->receivingBatch, index - 1);
1151 krisbash 1.4 
1152 mike     1.1         if (!counter)
1153                          buf += handler->receivedCurrentBlockBytes;
1154              
1155                      buffers[counter].ptr = (void*)buf;
1156                      buffers[counter].len = handler->recv_buffer.batchInfo[index - 1].pageSize;
1157              
1158                      if (!counter)
1159                          buffers[counter].len -= handler->receivedCurrentBlockBytes;
1160              
1161 krisbash 1.4         if (index == handler->recv_buffer.base.pageCount)
1162 mike     1.1         {
1163                          counter++;
1164                          break;
1165                      }
1166                  }
1167              
1168                  received = 0;
1169              
1170                  r = Sock_ReadV(handler->base.sock, buffers, counter, &received);
1171              
1172 krisbash 1.4     LOGD2((ZT("_ReadAllPages - Read %lu bytes with result %d (%s)"), received, (int)r, mistrerror(r)));
1173 mike     1.1 
1174                  if ( r == MI_RESULT_OK && 0 == received )
1175 krisbash 1.4     {
1176                      trace_Socket_Read_ConnectionClosed(handler);
1177                      return PRT_RETURN_FALSE; /* connection closed */
1178                  }
1179 mike     1.1 
1180                  if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
1181 krisbash 1.4     {
1182                      trace_Socket_Read_Error(handler, r);
1183 mike     1.1         return PRT_RETURN_FALSE;
1184 krisbash 1.4     }
1185 mike     1.1 
1186                  if (!received)
1187                      return PRT_RETURN_TRUE;
1188              
1189                  /* update index */
1190                  for ( counter = 0; counter < MI_COUNT(buffers); counter++ )
1191                  {
1192                      if (!received)
1193                          break;
1194              
1195                      if (received >= buffers[counter].len)
1196                      {
1197                          received -= buffers[counter].len;
1198                          handler->receivingPageIndex++;
1199                          handler->receivedCurrentBlockBytes = 0;
1200                          continue;
1201                      }
1202              
1203                      handler->receivedCurrentBlockBytes += received;
1204                      break;
1205                  }
1206 mike     1.1 
1207                  if ( (handler->receivingPageIndex - 1) == (int)handler->recv_buffer.base.pageCount )
1208                  {   /* received the whole message - process it */
1209 krisbash 1.4         return _ProcessReceivedMessage(handler);
1210 mike     1.1     }
1211              
1212                  return PRT_CONTINUE;
1213              }
1214              
1215              static MI_Boolean _RequestCallbackRead(
1216 krisbash 1.4     ProtocolSocket* handler)
1217 mike     1.1 {
1218                  int fullMessagesREceived = 0;
1219              
1220                  /* we have to keep repeating read until 'WOULD_BLOCK is returned;
1221                      windows does not reset event until read buffer is empty */
1222                  for (;fullMessagesREceived < 3;)
1223                  {
1224                      switch (_ReadHeader(handler))
1225                      {
1226                      case PRT_CONTINUE: break;
1227                      case PRT_RETURN_TRUE: return MI_TRUE;
1228                      case PRT_RETURN_FALSE: return MI_FALSE;
1229                      }
1230              
1231                      switch (_ReadAllPages(handler))
1232                      {
1233                      case PRT_CONTINUE: break;
1234                      case PRT_RETURN_TRUE: return MI_TRUE;
1235                      case PRT_RETURN_FALSE: return MI_FALSE;
1236                      }
1237                  } /* for(;;)*/
1238 mike     1.1     return MI_TRUE;
1239              }
1240              
1241              static MI_Boolean _RequestCallback(
1242                  Selector* sel,
1243                  Handler* handlerIn,
1244 krisbash 1.4     MI_Uint32 mask,
1245 mike     1.1     MI_Uint64 currentTimeUsec)
1246              {
1247 krisbash 1.4     ProtocolSocket* handler = (ProtocolSocket*)handlerIn;
1248                  ProtocolBase* protocolBase = (ProtocolBase*)handler->base.data;
1249 mike     1.1 
1250                  MI_UNUSED(sel);
1251                  MI_UNUSED(currentTimeUsec);
1252              
1253                  if (mask & SELECTOR_READ)
1254                  {
1255                      if (!_RequestCallbackRead(handler))
1256                      {
1257 krisbash 1.4             trace_RequestCallbackRead_Failed( handler );
1258                          if( !handler->isConnected && PRT_TYPE_CONNECTOR == protocolBase->type )
1259 mike     1.1             {
1260 krisbash 1.4                 Strand_ScheduleAux( &handler->strand, PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT );
1261 mike     1.1             }
1262                          goto closeConnection;
1263                      }
1264 krisbash 1.4         else
1265 mike     1.1         {
1266 krisbash 1.4             handler->isConnected = MI_TRUE;
1267                          if( PRT_TYPE_CONNECTOR == protocolBase->type && PRT_AUTH_OK == handler->authState )
1268 mike     1.1             {
1269 krisbash 1.4                 if( Atomic_Swap(&handler->connectEventSent, 1) == 0 )
1270                              {
1271                                  trace_RequestCallback_Connect_OnFirstRead(handler);
1272                                  Strand_ScheduleAux( &handler->strand, PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT );
1273                              }
1274 mike     1.1             }
1275                      }
1276                  }
1277              
1278                  if (mask & SELECTOR_WRITE)
1279                  {
1280                      if (!_RequestCallbackWrite(handler))
1281                      {
1282 krisbash 1.4             trace_RequestCallbackRead_Failed( handler );
1283 mike     1.1             goto closeConnection;
1284                      }
1285 krisbash 1.4         else
1286 mike     1.1         {
1287 krisbash 1.4             if( !handler->isConnected )
1288 mike     1.1             {
1289 krisbash 1.4                 handler->isConnected = MI_TRUE;
1290                              if( PRT_TYPE_CONNECTOR == protocolBase->type && PRT_AUTH_OK == handler->authState )
1291                              {
1292                                  if( Atomic_Swap(&handler->connectEventSent, 1) == 0 )
1293                                  {
1294                                      trace_RequestCallback_Connect_OnFirstWrite( handler );
1295                                      Strand_ScheduleAux( &handler->strand, PROTOCOLSOCKET_STRANDAUX_CONNECTEVENT );
1296                                  }
1297                              }
1298 mike     1.1             }
1299                      }
1300                  }
1301              
1302 krisbash 1.4     /* Close connection by timeout or error */
1303                  if( (mask & SELECTOR_TIMEOUT) || (mask & SELECTOR_EXCEPTION) )
1304                  {
1305                      trace_RequestCallback_Connect_ClosingAfterMask( handler, mask );
1306                      goto closeConnection;
1307                  }
1308 mike     1.1 
1309                  if ((mask & SELECTOR_REMOVE) != 0 ||
1310                      (mask & SELECTOR_DESTROY) != 0)
1311                  {
1312 krisbash 1.4         trace_RequestCallback_Connect_RemovingHandler( handler, mask, handler->base.mask );
1313              
1314                      _ProtocolSocket_Cleanup(handler);
1315 mike     1.1 
1316 krisbash 1.4         ProtocolSocket_Release(handler);
1317                  }
1318 mike     1.1 
1319 krisbash 1.4     return MI_TRUE;
1320 mike     1.1 
1321 krisbash 1.4 closeConnection:
1322 mike     1.1 
1323 krisbash 1.4     //release message and post ack if required
1324                  if (handler->message)
1325                  {
1326                      MI_Boolean internalMessage = Message_IsInternalMessage( handler->message );
1327 mike     1.1 
1328 krisbash 1.4         Message_Release(handler->message);
1329 mike     1.1         handler->message = 0;
1330              
1331 krisbash 1.4         //ACK up if the message just sent was posted from up
1332                      if (!internalMessage)
1333                          Strand_ScheduleAck( &handler->strand );
1334 mike     1.1     }
1335              
1336 krisbash 1.4     LOGD2((ZT("_RequestCallback - closed client connection")));
1337                  trace_Socket_ClosingConnection( handler, mask );
1338 mike     1.1 
1339                  return MI_FALSE;
1340              }
1341              
1342              static MI_Boolean _ListenerCallback(
1343                  Selector* sel,
1344                  Handler* handler,
1345 krisbash 1.4     MI_Uint32 mask,
1346 mike     1.1     MI_Uint64 currentTimeUsec)
1347              {
1348 krisbash 1.4     ProtocolBase* self = (ProtocolBase*)handler->data;
1349 mike     1.1     MI_Result r;
1350                  Sock s;
1351                  Addr addr;
1352 krisbash 1.4     ProtocolSocket* h;
1353 mike     1.1 
1354 krisbash 1.4     MI_UNUSED(sel);
1355                  MI_UNUSED(currentTimeUsec);
1356 mike     1.1 
1357                  if (mask & SELECTOR_READ)
1358                  {
1359                      /* Accept the incoming connection */
1360                      r = Sock_Accept(handler->sock, &s, &addr);
1361              
1362                      if (MI_RESULT_WOULD_BLOCK == r)
1363                          return MI_TRUE;
1364              
1365                      if (r != MI_RESULT_OK)
1366                      {
1367 krisbash 1.4             trace_SockAccept_Failed(Sock_GetLastError());
1368 mike     1.1             return MI_TRUE;
1369                      }
1370              
1371                      r = Sock_SetBlocking(s, MI_FALSE);
1372                      if (r != MI_RESULT_OK)
1373                      {
1374 krisbash 1.4             trace_SockSetBlocking_Failed();
1375 mike     1.1             Sock_Close(s);
1376                          return MI_TRUE;
1377                      }
1378              
1379                      /* Create handler */
1380 krisbash 1.4         h =  _ProtocolSocket_Server_New(self,s);
1381 mike     1.1 
1382                      if (!h)
1383                      {
1384                          Sock_Close(s);
1385                          return MI_TRUE;
1386                      }
1387              
1388 krisbash 1.4         Strand_Leave( &h->strand );
1389 mike     1.1 
1390                      /* Watch for read events on the incoming connection */
1391 krisbash 1.4         r = _AddProtocolSocket_Handler(self->selector, h);
1392 mike     1.1 
1393                      if (r != MI_RESULT_OK)
1394                      {
1395 krisbash 1.4             ProtocolSocket_Release(h);
1396                          trace_SelectorAddHandler_Failed();
1397 mike     1.1             return MI_TRUE;
1398                      }
1399                  }
1400              
1401                  if ((mask & SELECTOR_REMOVE) != 0 ||
1402                      (mask & SELECTOR_DESTROY) != 0)
1403                  {
1404                      Sock_Close(handler->sock);
1405 krisbash 1.4         PAL_Free(handler);
1406 mike     1.1     }
1407              
1408                  return MI_TRUE;
1409              }
1410              
1411              static MI_Result _CreateListener(
1412                  Sock* s,
1413                  const char* locator)
1414              {
1415                  const char* posColon;
1416              
1417                  posColon = strchr(locator, ':');
1418              
1419                  if (!posColon)
1420                      return Sock_CreateLocalListener(s, locator);
1421              
1422                  /* create listener for remote address like host:port or :port (ANYADDR) */
1423                  {
1424                      unsigned short port = (unsigned short)atol(posColon+1);
1425                      char host[128];
1426                      unsigned int len = (unsigned int)(posColon - locator);
1427 mike     1.1         Addr addr;
1428                      MI_Result r;
1429              
1430                      if (len > 0)
1431                      {
1432                          if (len >= sizeof(host))
1433                              return MI_RESULT_FAILED;
1434              
1435                          memcpy(host, locator, len);
1436                          host[len] = 0;
1437              
1438                          // Initialize address.
1439 krisbash 1.4             r = Addr_Init(&addr, host, port, MI_FALSE);
1440 mike     1.1             if (r != MI_RESULT_OK)
1441                              return MI_RESULT_FAILED;
1442                      }
1443                      else
1444                      {
1445                          Addr_InitAny(&addr, port);
1446                      }
1447              
1448                      return Sock_CreateListener(s, &addr);
1449                  }
1450              }
1451              
1452              static MI_Result _CreateConnector(
1453                  Sock* s,
1454                  const char* locator)
1455              {
1456                  const char* posColon;
1457              
1458 krisbash 1.4     /* This function expects a locator in the form "_host_:_port_", for HTTP */
1459              	/* connections, or in the form of a file name, for local connections */
1460              	/* using a socket. In the latter case, the file name is the nsme of the */
1461              	/* socket special file. Thus, socket special files used with this code */
1462              	/* may not contain a colon in their names. Servers with IPv6 addresses */
1463              	/* must use symbolic names, because IPv6 addresses use a colon as a separator */
1464              
1465 mike     1.1     posColon = strchr(locator, ':');
1466                  if (!posColon)
1467                      return Sock_CreateLocalConnector(s, locator);
1468 krisbash 1.4     return Sock_CreateIPConnector(s, locator);
1469 mike     1.1 }
1470              
1471 krisbash 1.4 static MI_Result _ProtocolBase_Init(
1472                  _In_        ProtocolBase*   self,
1473                  _In_opt_    Selector*       selector, /*optional, maybe NULL*/
1474                  _In_opt_    OpenCallback    callback,
1475                  _In_opt_    void*           callbackData,
1476                              Protocol_Type   protocolType)
1477 mike     1.1 {
1478                  /* Check parameters */
1479 krisbash 1.4     if (!self)
1480 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
1481              
1482                  if (selector)
1483                  {   /* attach the exisiting selector */
1484                      self->selector = selector;
1485                      self->internal_selector_used = MI_FALSE;
1486                  }
1487                  else
1488 krisbash 1.4     {   /* create a new selector */
1489 mike     1.1         /* Initialize the network */
1490                      Sock_Start();
1491              
1492                      /* Initialize the selector */
1493                      if (Selector_Init(&self->internal_selector) != MI_RESULT_OK)
1494                      {
1495                          return MI_RESULT_FAILED;
1496                      }
1497                      self->selector = &self->internal_selector;
1498                      self->internal_selector_used = MI_TRUE;
1499                  }
1500              
1501                  /* Save the callback and callbackData */
1502                  self->callback = callback;
1503                  self->callbackData = callbackData;
1504 krisbash 1.4     self->skipInstanceUnpack = MI_FALSE;
1505                  self->type = protocolType;
1506 mike     1.1 
1507                  /* Set the magic number */
1508                  self->magic = _MAGIC;
1509              
1510                  return MI_RESULT_OK;
1511              }
1512              
1513              /*
1514              **==============================================================================
1515              **
1516              ** Public definitions:
1517              **
1518              **==============================================================================
1519              */
1520              
1521 krisbash 1.4 MI_Result ProtocolBase_New_Listener(
1522                  _Out_       ProtocolBase** selfOut,
1523                  _In_opt_    Selector* selector, /*optional, maybe NULL*/
1524                  _In_        const char* locator,
1525                  _In_        OpenCallback callback,
1526                  _In_        void* callbackData)
1527 mike     1.1 {
1528 krisbash 1.4     ProtocolBase* self;
1529 mike     1.1     MI_Result r;
1530                  Sock listener;
1531              
1532 krisbash 1.4     /* Allocate structure */
1533                  {
1534                      self = (ProtocolBase*)PAL_Calloc(1, sizeof(ProtocolBase));
1535              
1536                      if (!self)
1537                          return MI_RESULT_FAILED;
1538                  }
1539              
1540                  r = _ProtocolBase_Init(self, selector, callback, callbackData, PRT_TYPE_LISTENER);
1541 mike     1.1 
1542                  if (MI_RESULT_OK != r)
1543 krisbash 1.4     {
1544                      PAL_Free(self);
1545 mike     1.1         return r;
1546 krisbash 1.4     }
1547 mike     1.1 
1548 krisbash 1.4     /* Set output parameter */
1549                  *selfOut = self;
1550 mike     1.1 
1551                  /* Create listener socket */
1552                  {
1553                      r = _CreateListener(&listener, locator);
1554              
1555                      if (r != MI_RESULT_OK)
1556                      {
1557 krisbash 1.4             ProtocolBase_Delete(self);
1558 mike     1.1             return r;
1559                      }
1560              
1561                      r = Sock_SetBlocking(listener, MI_FALSE);
1562              
1563                      if (r != MI_RESULT_OK)
1564                      {
1565                          Sock_Close(listener);
1566 krisbash 1.4             ProtocolBase_Delete(self);
1567 mike     1.1             return r;
1568                      }
1569                  }
1570              
1571                  /* Watch for read events on the listener socket (client connections) */
1572                  {
1573 krisbash 1.4         Handler* h = (Handler*)PAL_Calloc(1, sizeof(Handler));
1574 mike     1.1 
1575                      if (!h)
1576                      {
1577                          Sock_Close(listener);
1578 krisbash 1.4             ProtocolBase_Delete(self);
1579 mike     1.1             return MI_RESULT_FAILED;
1580                      }
1581              
1582                      h->sock = listener;
1583                      h->mask = SELECTOR_READ | SELECTOR_EXCEPTION;
1584                      h->callback = _ListenerCallback;
1585                      h->data = self;
1586              
1587                      r = Selector_AddHandler(self->selector, h);
1588              
1589                      if (r != MI_RESULT_OK)
1590                      {
1591                          Sock_Close(listener);
1592 krisbash 1.4             PAL_Free(h);
1593                          ProtocolBase_Delete(self);
1594 mike     1.1             return r;
1595                      }
1596                  }
1597              
1598                  return MI_RESULT_OK;
1599              }
1600              
1601 krisbash 1.4 MI_Result _ProtocolSocket_New(
1602              #if defined(STRAND_ENABLE_DEBUG)
1603                  _In_        StrandDebugInfo         debug,
1604              #endif
1605                  _Out_       ProtocolSocket**        selfOut,
1606                  _In_opt_    InteractionOpenParams*  params,         // Only used on connector types
1607                              size_t                  structSize)     // if 0 then sizeof(ProtocolSocket) is assumed
1608              {
1609                  ProtocolSocket* self;
1610              
1611                  DEBUG_ASSERT( 0 == structSize || structSize >= sizeof(ProtocolSocket) );
1612              
1613                  *selfOut = NULL;
1614              
1615                  if( 0 == structSize )
1616                      structSize = sizeof(ProtocolSocket);
1617              
1618                  /* Allocate structure */
1619                  {
1620                      self = (ProtocolSocket*)PAL_Calloc(1, structSize);
1621              
1622 krisbash 1.4         if (!self)
1623                          return MI_RESULT_FAILED;
1624                  }
1625              
1626                  Strand_Init( STRAND_PASSDEBUG(debug) &self->strand, &_ProtocolSocket_FT, STRAND_FLAG_ENTERSTRAND, params);
1627                  self->refCount = 1; //ref associated with Strand. Released on Strand_Finish
1628                  self->closeOtherScheduled = MI_FALSE;
1629              
1630                  self->base.callback = _RequestCallback;
1631              
1632                  /* Set output parameter */
1633                  *selfOut = self;
1634                  return MI_RESULT_OK;
1635              }
1636              
1637              ProtocolSocket* _ProtocolSocket_Server_New(
1638                  _In_        ProtocolBase *          protocolBase,
1639                  _In_        Sock                    sock )
1640              {
1641                  ProtocolSocket* self = NULL;
1642              
1643 krisbash 1.4     if( MI_RESULT_OK == _ProtocolSocket_New( STRAND_DEBUG(ProtocolSocketServer) &self, NULL, 0) )
1644                  {
1645                      self->base.data = protocolBase;
1646                      self->base.sock = sock;
1647                      self->base.mask = SELECTOR_READ | SELECTOR_EXCEPTION;
1648              
1649                      /* waiting for connect-request */
1650                      self->authState = PRT_AUTH_WAIT_CONNECTION_REQUEST;
1651                  }
1652              
1653                  return self;
1654              }
1655              
1656              MI_Result _ProtocolSocketAndBase_New(
1657              #if defined(STRAND_ENABLE_DEBUG)
1658                  _In_        StrandDebugInfo         debug,
1659              #endif
1660                  _Out_       ProtocolSocketAndBase** selfOut,
1661                  _In_opt_    InteractionOpenParams*  params,             // Only used on connector types
1662                  _In_opt_    Selector*               selector,           // optional, maybe NULL
1663                  _In_opt_    OpenCallback            callback,           // only used on Agent
1664 krisbash 1.4     _In_opt_    void*                   callbackData,       // used along with callback
1665                              Protocol_Type           protocolType)
1666 mike     1.1 {
1667 krisbash 1.4     ProtocolSocketAndBase* self;
1668 mike     1.1     MI_Result r;
1669              
1670 krisbash 1.4     DEBUG_ASSERT( ( NULL != params && callback == NULL ) || ( NULL == params && callback != NULL ) );
1671              
1672                  *selfOut = NULL;
1673              
1674                  r = _ProtocolSocket_New( STRAND_PASSDEBUG(debug) (ProtocolSocket**)&self, params, sizeof( ProtocolSocketAndBase ) );
1675              
1676                  if( MI_RESULT_OK != r )
1677                      return r;
1678              
1679                  r = _ProtocolBase_Init(&self->internalProtocolBase, selector, callback, callbackData, protocolType);
1680 mike     1.1 
1681                  if (MI_RESULT_OK != r)
1682 krisbash 1.4     {
1683                      PAL_Free(self);
1684 mike     1.1         return r;
1685 krisbash 1.4     }
1686              
1687                  self->protocolSocket.base.data = &self->internalProtocolBase;
1688              
1689                  // ProtocolSocketAndBase objects need to delay wait until protocol run is done
1690                  Strand_SetDelayFinish(&self->protocolSocket.strand);
1691              
1692                  Strand_Leave( &self->protocolSocket.strand );
1693              
1694                  // Set output parameter
1695                  *selfOut = self;
1696                  return MI_RESULT_OK;
1697              }
1698              
1699              MI_Result ProtocolSocketAndBase_New_Connector(
1700                  _Out_       ProtocolSocketAndBase** selfOut,
1701                  _In_opt_    Selector*               selector,       // optional, maybe NULL
1702                  _In_        const char*             locator,
1703                  _In_        InteractionOpenParams*  params,
1704                  _In_        const char*             user,
1705                  _In_        const char*             password )
1706 krisbash 1.4 {
1707                  ProtocolSocketAndBase* self;
1708                  MI_Result r;
1709                  Sock connector;
1710              
1711                  DEBUG_ASSERT( NULL != params && NULL != params->interaction && NULL == params->callbackData );
1712 mike     1.1 
1713                  *selfOut = 0;
1714              
1715 krisbash 1.4     r = _ProtocolSocketAndBase_New( STRAND_DEBUG(ProtocolConnector) &self, params, selector, NULL, NULL, PRT_TYPE_CONNECTOR );
1716              
1717                  if( r != MI_RESULT_OK )
1718                      return r;
1719 mike     1.1 
1720                  /* Create connector socket */
1721                  {
1722                      // Connect to server.
1723                      r = _CreateConnector(&connector, locator);
1724                      if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1725                      {
1726 krisbash 1.4             trace_SocketConnectorFailed(locator);
1727                          _ProtocolSocketAndBase_Delete(self);
1728                          return r;
1729 mike     1.1         }
1730                  }
1731              
1732 krisbash 1.4     /* setting connector's structure */
1733 mike     1.1     {
1734 krisbash 1.4         ProtocolSocket* h = &self->protocolSocket;
1735 mike     1.1 
1736                      h->base.sock = connector;
1737                      h->base.mask = SELECTOR_READ | SELECTOR_WRITE | SELECTOR_EXCEPTION;
1738                      h->authState = PRT_AUTH_WAIT_CONNECTION_RESPONSE;
1739              
1740 krisbash 1.4         r = _AddProtocolSocket_Handler(self->internalProtocolBase.selector, h);
1741 mike     1.1 
1742                      if (r != MI_RESULT_OK)
1743                      {
1744                          Sock_Close(connector);
1745 krisbash 1.4             _ProtocolSocketAndBase_Delete(self);
1746                          return r;
1747 mike     1.1         }
1748              
1749                      /* send connect request */
1750 krisbash 1.4         if( !_SendAuthRequest(h, user, password, NULL) )
1751 mike     1.1         {
1752 krisbash 1.4             // this will call _RequestCallback which will schedule a CloseOther,
1753                          // but that is not going delete the object (since it is not even truly opened),
1754                          // so do it explicitely
1755                          Selector_RemoveHandler(self->internalProtocolBase.selector, &h->base);
1756                          _ProtocolSocketAndBase_Delete(self);
1757 mike     1.1             return MI_RESULT_FAILED;
1758                      }
1759                  }
1760              
1761                  /* Set output parameter */
1762                  *selfOut = self;
1763                  return MI_RESULT_OK;
1764              }
1765              
1766 krisbash 1.4 /*
1767                  Creates a new protocol object from connected stream socket
1768                  (typically a pipe from server to agent).
1769              
1770                  Parameters:
1771                  self - [out] protocol object
1772                  selector - [opt] selector to use for socket monitoring
1773                  s - socket; if protocol created successfully, socket will be closed in Protocol_Delete.
1774                      If operation failed, socket is not closed.
1775                  skipInstanceUnpack - flag to skip instance un-packing; used
1776                      to skip unpacking instances from agent
1777                  callback - function that protocol calls to inform about new connection
1778                  callbackData -
1779              
1780                  Returns:
1781                  'OK' if succefful, error otherwise
1782              */
1783              MI_Result _ProtocolSocketAndBase_New_From_Socket(
1784                  _Out_       ProtocolSocketAndBase** selfOut,
1785                  _In_opt_    InteractionOpenParams*  params,         // Only used on connector type
1786                  _In_opt_    Selector*               selector,       // optional, maybe NULL
1787 krisbash 1.4     _In_        Sock                    sock,
1788                              MI_Boolean              skipInstanceUnpack,
1789                  _In_opt_    OpenCallback            callback,       // only used on Agent
1790                  _In_opt_    void*                   callbackData)   // used along with callback
1791 mike     1.1 {
1792 krisbash 1.4     ProtocolSocketAndBase* self;
1793 mike     1.1     MI_Result r;
1794              
1795 krisbash 1.4     *selfOut = 0;
1796              
1797                  r = _ProtocolSocketAndBase_New( STRAND_DEBUG(ProtocolFromSocket) &self, params, selector, callback, callbackData, PRT_TYPE_FROM_SOCKET );
1798 mike     1.1 
1799 krisbash 1.4     if( r != MI_RESULT_OK )
1800 mike     1.1         return r;
1801              
1802 krisbash 1.4     self->internalProtocolBase.skipInstanceUnpack = skipInstanceUnpack;
1803 mike     1.1 
1804 krisbash 1.4     /* setup provided socket */
1805 mike     1.1     {
1806 krisbash 1.4         ProtocolSocket* h = &self->protocolSocket;
1807 mike     1.1 
1808 krisbash 1.4         h->base.sock = sock;
1809 mike     1.1         h->base.mask = SELECTOR_READ  | SELECTOR_EXCEPTION;
1810              
1811                      if (skipInstanceUnpack)
1812                      {
1813                          /* skipInstanceUnpack indicates that call made from server
1814                              and socket connected to the agent
1815                              In that case we can use back=pressure feature and
1816                              ignore socket operations under stress */
1817 krisbash 1.4             //no more used - as flow control is implemented in protocol and wsman layers
1818                          //h->base.mask |= SELECTOR_IGNORE_READ_OVERLOAD;
1819 mike     1.1         }
1820              
1821                      h->isConnected = MI_TRUE;
1822 krisbash 1.4         /* skip authentication for established connections
1823 mike     1.1             (only used in server/agent communication) */
1824                      h->authState = PRT_AUTH_OK;
1825              
1826 krisbash 1.4         r = _AddProtocolSocket_Handler(self->internalProtocolBase.selector, h);
1827 mike     1.1 
1828                      if (r != MI_RESULT_OK)
1829                      {
1830 krisbash 1.4             _ProtocolSocketAndBase_Delete(self);
1831                          return r;
1832 mike     1.1         }
1833                  }
1834              
1835                  /* Set output parameter */
1836                  *selfOut = self;
1837                  return MI_RESULT_OK;
1838              }
1839              
1840 krisbash 1.4 MI_Result ProtocolSocketAndBase_New_AgentConnector(
1841                  _Out_       ProtocolSocketAndBase** selfOut,
1842                  _In_opt_    Selector*               selector,       // optional, maybe NULL
1843                  _In_        Sock                    s,
1844                  _In_        InteractionOpenParams*  params )
1845              {
1846                  return _ProtocolSocketAndBase_New_From_Socket( selfOut, params, selector, s, MI_TRUE, NULL, NULL );
1847              }
1848              
1849              MI_Result ProtocolSocketAndBase_New_Agent(
1850                  _Out_       ProtocolSocketAndBase** selfOut,
1851                  _In_opt_    Selector*               selector,       // optional, maybe NULL
1852                  _In_        Sock                    s,
1853                  _In_        OpenCallback            callback,
1854                  _In_        void*                   callbackData)   // used along with callback
1855              {
1856                  return _ProtocolSocketAndBase_New_From_Socket( selfOut, NULL, selector, s, MI_FALSE, callback, callbackData );
1857              }
1858              
1859              MI_Result _ProtocolBase_Finish(
1860                  ProtocolBase* self)
1861 mike     1.1 {
1862                  /* Check parameters */
1863                  if (!self)
1864                      return MI_RESULT_INVALID_PARAMETER;
1865              
1866                  /* Check magic number */
1867                  if (self->magic != _MAGIC)
1868                      return MI_RESULT_INVALID_PARAMETER;
1869              
1870                  if (self->internal_selector_used)
1871                  {
1872                      /* Release selector;
1873                      Note: selector-destory closes all sockects in a list including connector and listener */
1874                      Selector_Destroy(self->selector);
1875              
1876                      /* Shutdown the network */
1877                      Sock_Stop();
1878                  }
1879              
1880                  /* Clear magic number */
1881                  self->magic = 0xDDDDDDDD;
1882 mike     1.1 
1883 krisbash 1.4     return MI_RESULT_OK;
1884              }
1885              
1886              MI_Result ProtocolBase_Delete(
1887                  ProtocolBase* self)
1888              {
1889                  MI_Result r = _ProtocolBase_Finish( self );
1890              
1891                  if( MI_RESULT_OK != r )
1892                      return r;
1893              
1894 mike     1.1     /* Free self pointer */
1895 krisbash 1.4     PAL_Free(self);
1896 mike     1.1 
1897 krisbash 1.4     return MI_RESULT_OK;
1898              }
1899              
1900              MI_Result _ProtocolSocketAndBase_Delete(
1901                  ProtocolSocketAndBase* self)
1902              {
1903                  MI_Result r = _ProtocolBase_Finish( &self->internalProtocolBase );
1904              
1905                  if( MI_RESULT_OK != r )
1906                      return r;
1907              
1908                  /* Free self pointer */
1909                  PAL_Free(self);
1910 mike     1.1 
1911                  return MI_RESULT_OK;
1912              }
1913              
1914              MI_Result Protocol_Run(
1915 krisbash 1.4     ProtocolBase* self,
1916 mike     1.1     MI_Uint64 timeoutUsec)
1917              {
1918                  /* Run the selector */
1919 krisbash 1.4     return Selector_Run(self->selector, timeoutUsec, MI_FALSE);
1920 mike     1.1 }
1921              
1922              static MI_Result _SendIN_IO_thread(
1923 krisbash 1.4     ProtocolBase* self,
1924                  ProtocolSocket* sendSock,
1925 mike     1.1     Message* message)
1926              {
1927                  /* check params */
1928                  if (!self || !message )
1929                      return MI_RESULT_INVALID_PARAMETER;
1930              
1931                  if (self->magic != _MAGIC)
1932                  {
1933 krisbash 1.4         trace_Message_InvalidMagic();
1934 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
1935                  }
1936              
1937                  /* validate handler */
1938 krisbash 1.4     if (!sendSock || INVALID_SOCK == sendSock->base.sock)
1939 mike     1.1     {
1940 krisbash 1.4         trace_Message_ExpiredHandler(sendSock);
1941 mike     1.1 
1942                      return MI_RESULT_FAILED;
1943                  }
1944              
1945 krisbash 1.4     DEBUG_ASSERT(sendSock->message == NULL);
1946                  sendSock->message = message;
1947 mike     1.1     Message_AddRef(message);
1948              
1949                  _PrepareMessageForSending(sendSock);
1950 krisbash 1.4 
1951                  if( !_RequestCallbackWrite(sendSock) && PRT_TYPE_LISTENER == self->type )
1952 mike     1.1     {
1953 krisbash 1.4         trace_QueueOverflowOrConnectionAbort(sendSock);
1954                       return MI_RESULT_FAILED;
1955 mike     1.1     }
1956              
1957                  return MI_RESULT_OK;
1958              }

ViewCVS 0.9.2