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

   1 mike  1.1 /*
   2           **==============================================================================
   3           **
   4           ** Open Management Infrastructure (OMI)
   5           **
   6           ** Copyright (c) Microsoft Corporation
   7           **
   8 krisbash 1.3 ** 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.3 ** 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.3 ** 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 krisbash 1.3 #include <pal/strings.h>
  26 mike     1.1 #include <base/messages.h>
  27              #include <base/log.h>
  28 krisbash 1.3 #include <pal/strings.h>
  29 mike     1.1 #include <base/paths.h>
  30 krisbash 1.3 #include <pal/format.h>
  31              #include <base/Strand.h>
  32 mike     1.1 #include <protocol/protocol.h>
  33              #include "agentmgr.h"
  34 krisbash 1.3 #include <omi_error/errorutil.h>
  35 mike     1.1 
  36              #if defined(CONFIG_POSIX)
  37              # include <unistd.h>
  38              # include <errno.h>
  39              # include <sys/socket.h>
  40              # include <netinet/tcp.h>
  41              # include <netinet/in.h>
  42              # include <sys/time.h>
  43              # include <sys/types.h>
  44              # include <netdb.h>
  45              # include <fcntl.h>
  46              # include <arpa/inet.h>
  47              # include <signal.h>
  48              # include <sys/wait.h>
  49              #endif
  50              
  51              /*
  52              **==============================================================================
  53              **
  54              ** Data structures
  55              **
  56 mike     1.1 **==============================================================================
  57              */
  58              
  59              #if defined(CONFIG_POSIX)
  60              
  61              /*
  62                  RequestItem - stores information about request sent to the agent/provider;
  63 krisbash 1.3     this item stores original request's operationId (has to be substituted) and request pointer
  64                  In case of agent disconnection, agent-mgr uses this list to send error responses to
  65 mike     1.1     outstanding requests.
  66              */
  67 krisbash 1.3 
  68              typedef enum _RequestItemFinishState
  69 mike     1.1 {
  70 krisbash 1.3     RequestItemFinishState_None = 0,
  71                  RequestItemFinishState_PendingFinishOnError,
  72                  RequestItemFinishState_ProcessedFinishOnError
  73              } RequestItemFinishState;
  74              
  75              
  76              typedef struct _RequestItem
  77              {
  78                  // managing original interaction coming from dispatcher
  79                  StrandEntry strand;
  80 mike     1.1 
  81 krisbash 1.3     MI_Boolean isIdleRequest;
  82                  MI_Boolean pendingCancel;
  83                  RequestItemFinishState finishOnErrorState;
  84              
  85                  Message* request;           // Request received from the left
  86                  MI_Uint64 originalOperationId;
  87                  MI_Uint64 key;  // OperationId of the outogoing request; for now RequestItem address (as it was before)
  88              }
  89              RequestItem;
  90 mike     1.1 
  91              /*
  92                  AgentElem - stores information about single running agent
  93 krisbash 1.3     (this will be become multiplexer eventually)
  94 mike     1.1 */
  95              struct _AgentElem
  96              {
  97 krisbash 1.3     StrandMany              strand;
  98              
  99 mike     1.1     /* Linked-list support */
 100 krisbash 1.3     ListElem*               next;
 101                  ListElem*               prev;
 102 mike     1.1 
 103                  /* hosting context */
 104 krisbash 1.3     uid_t                   uid;
 105                  gid_t                   gid;
 106 mike     1.1 
 107                  /* connection to the agent */
 108 krisbash 1.3     ProtocolSocketAndBase*  protocol;
 109 mike     1.1 
 110                  /* link to manager */
 111 krisbash 1.3     AgentMgr*               agentMgr;
 112 mike     1.1 
 113                  /* agent process pid */
 114 krisbash 1.3     pid_t                   agentPID;
 115 mike     1.1 };
 116              
 117              /*
 118              **==============================================================================
 119 krisbash 1.3 */
 120              
 121              #define AGENTELEM_STRANDAUX_CLOSEAGENTITEM 0
 122              #define AGENTELEM_STRANDAUX_ENTRYACK       1
 123              
 124              STRAND_DEBUGNAME2( AgentElem, CloseAgentItem, EntryAck );
 125              
 126              #define IDLEREQUESTITEM_STRANDAUX_READYTOFINISH 0
 127              
 128              STRAND_DEBUGNAME1( IdleRequestItem, ReadyToFinish );
 129              
 130              #define REQUESTITEM_STRANDAUX_PREPARETOFINISHONERROR 0
 131              
 132              STRAND_DEBUGNAME1( RequestItem, PrepareToFinishOnError );
 133              
 134              
 135              /*
 136              **==============================================================================
 137              */
 138              
 139              void _AgentElem_InitiateClose( _In_ AgentElem* self )
 140 krisbash 1.3 {
 141                  // remove agent from Mgr's list
 142                  // Do this first so no new request entries are added after this
 143                  ReadWriteLock_AcquireWrite(&self->agentMgr->lock);
 144                  List_Remove(
 145                      &self->agentMgr->headAgents,
 146                      &self->agentMgr->tailAgents,
 147                      (ListElem*)&(self->next));
 148                  ReadWriteLock_ReleaseWrite(&self->agentMgr->lock);
 149              
 150                  StrandMany_ScheduleAux( &self->strand, AGENTELEM_STRANDAUX_CLOSEAGENTITEM );
 151              }
 152              
 153              void _AgentElem_Post( _In_ Strand* self_, _In_ Message* msg)
 154              {
 155                  AgentElem* self = (AgentElem*)StrandMany_FromStrand(self_);
 156                  DEBUG_ASSERT( NULL != self_ );
 157                  trace_AgentElemPostingMessage(&self->strand.strand.info.interaction, self->strand.strand.info.interaction.other);
 158              
 159                  /* ATTN: verify unload message */
 160              
 161 krisbash 1.3     if (BinProtocolNotificationTag == msg->tag)
 162                  {
 163                      BinProtocolNotification* notification = (BinProtocolNotification*)msg;
 164                      if (BinNotificationAgentIdle == notification->type)
 165                      {
 166                          // Check if this agent has outstanding requests -
 167                          // if agent is really idle (only idle notification request)
 168                          // then initiate the close
 169                          if( 1 == self->strand.numEntries )
 170                          {
 171                              _AgentElem_InitiateClose( self );
 172                          }
 173                      }
 174                      /* ignore service messages */
 175                      Strand_Ack( &self->strand.strand );
 176                      return;
 177                  }
 178              
 179                  if( !StrandMany_PostFindEntry( &self->strand, msg ) )
 180                  {
 181                      trace_StrandMany_CannotFindItem( Uint64ToPtr(msg->operationId), (int)self->uid );
 182 krisbash 1.3         _AgentElem_InitiateClose( self );
 183                  }
 184              
 185                  // For now ack immediately
 186                  //TODO eventually multiplexer should take care of flow control here
 187                  // For now, we are short circuiting ACK from RequstItem
 188              }
 189              
 190              void _AgentElem_PostControl( _In_ Strand* self_, _In_ Message* msg)
 191              {
 192                  DEBUG_ASSERT( MI_FALSE );  // not used yet
 193              }
 194              
 195              void _AgentElem_Ack( _In_ Strand* self_)
 196              {
 197                  trace_AgentElemAck( &self_->info.interaction, self_->info.interaction.other );
 198              }
 199              
 200              void _AgentElem_Cancel( _In_ Strand* self_)
 201              {
 202                  DEBUG_ASSERT( MI_FALSE );  // not used yet
 203 krisbash 1.3 }
 204              
 205              void _AgentElem_Close( _In_ Strand* self_)
 206              {
 207                  AgentElem* self = (AgentElem*)StrandMany_FromStrand(self_);
 208              
 209                  trace_AgentClosedConnection((int)self->uid);
 210                  // lost connection to the agent ( within 'CloseAgentItem' call):
 211                  //    - send error repsonses to all outstanding requests
 212                  //    - remove agent form the list
 213              
 214                  _AgentElem_InitiateClose( self );
 215              }
 216              
 217              void _AgentElem_Finish( _In_ Strand* self_)
 218              {
 219                  AgentElem* self = (AgentElem*)StrandMany_FromStrand(self_);
 220                  DEBUG_ASSERT( NULL != self_ );
 221              
 222                  // It is ok now for the protocol object to go away
 223                  ProtocolSocketAndBase_ReadyToFinish(self->protocol);
 224 krisbash 1.3 
 225                  StrandMany_Delete(&self->strand);
 226              }
 227              
 228              // AGENTELEM_STRANDAUX_ENTRYACK
 229              void _AgentElem_EntryAck( _In_ Strand* self_)
 230              {
 231                  //Temporary until we have flow control with multiplexing buffers
 232                  Strand_Ack( self_ );
 233              
 234              }
 235              
 236              // AGENTELEM_STRANDAUX_CLOSEAGENTITEM
 237              static void _AgentElem_CloseAgentItem(Strand* self_);
 238              
 239              /*
 240                  Object that implements a single connection going thru binary protocol
 241                  to one agent. It uses that one-to-many interface to channel thru multiple
 242                  operations on the same connection.
 243              
 244                  Behavior:
 245 krisbash 1.3     - Post checks if the message is a idle notification, and if it is and there is
 246                     only one remaining operation (the idle notification one itself) then initiates
 247                     a close. Otherwise it just post the message to the pertinent operation that is
 248                     find using the buildin hash map searching by the operationId field
 249                     in the message.
 250                  - Ack does nothing currently as there is not an explicit in-the-wire flow control
 251                     protocol implemented yet.
 252                  - PostControl and Cancel are not currently implemented
 253                  - Close initiates the closing of all entries and sending the corresponding
 254                     error messages to each one (see _AgentElem_CloseAgentItem below)
 255                  - Shutdown:
 256                     The objects are deleted thru the normal Strand logic. That is,
 257                     once the interaction is closed on both sides and there are no
 258                     entries the object is auto-deleted.
 259              
 260                  Unique features and special Behavour:
 261                  - _AgentElem_CloseAgentItem is called at any time is there is an unrecoverable
 262                    error or the connection has been lost and it will iterate thru the existing
 263                    operations/requests sending an appropiate error message to each one.
 264                   - _AgentElem_EntryAck is schedule by each entry (RequestItem) when it
 265                    receives and Ack so that Ack can be simply passed thru to the connection
 266 krisbash 1.3       (since we dont have yet a more sophisticated on-the-wire flow control
 267                    mechanism).
 268              */
 269              static StrandFT _AgentElem_FT = {
 270                  _AgentElem_Post,
 271                  _AgentElem_PostControl,
 272                  _AgentElem_Ack,
 273                  _AgentElem_Cancel,
 274                  _AgentElem_Close,
 275                  _AgentElem_Finish,
 276                  NULL,
 277                  _AgentElem_CloseAgentItem,
 278                  _AgentElem_EntryAck,
 279                  NULL,
 280                  NULL,
 281                  NULL };
 282              
 283              /*
 284              **==============================================================================
 285              */
 286              
 287 krisbash 1.3 static MI_Result _PrepareMessageForAgent(
 288                          MI_Uint64       operationId,
 289                  _In_    Message*        msg,
 290                  _Out_   Message**       msgOut)
 291              {
 292                  MI_Result result;
 293              
 294                  /* clone message (may be incoming message in some cases) */
 295                  result = MessagePackCloneForBinarySending(msg, msgOut);
 296                  if( MI_RESULT_OK == result )
 297                  {
 298                      /* substitute message-id on time server->agent call;
 299                      operationId has to be restored once first response is received */
 300                      (*msgOut)->operationId = operationId;
 301                      (*msgOut)->flags = msg->flags;
 302                  }
 303                  else
 304                  {
 305                      trace_SendRequestToAgent_MessageCloneFailed(result);
 306                  }
 307              
 308 krisbash 1.3     return result;
 309              }
 310              
 311              static void _SendErrorResponseAndClose(
 312                  RequestItem* requestItem,
 313                  MI_Result r)
 314              {
 315                  PostResultMsg* resp;
 316                  trace_AgentMgr_SendErrorResponse( requestItem );
 317                  resp = PostResultMsg_NewAndSerialize( requestItem->request, NULL, NULL, MI_RESULT_TYPE_MI, r);
 318              
 319                  //TODO - do a force close
 320                  if (!resp)
 321                      return;
 322              
 323                  requestItem->request->operationId = requestItem->originalOperationId;
 324              
 325                  requestItem->finishOnErrorState = RequestItemFinishState_ProcessedFinishOnError;
 326                  Strand_Post(&requestItem->strand.strand, &resp->base);
 327              
 328                  PostResultMsg_Release(resp);
 329 krisbash 1.3 
 330                  Strand_Close(&requestItem->strand.strand);
 331              }
 332              
 333              // not used much yet (no secondary "semantic" messages at the time)
 334              // currently used for unsubscribe message
 335              void _RequestItem_Post( _In_ Strand* self_, _In_ Message* msg)
 336              {
 337                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 338                  MI_Result result;
 339                  Message* msgOut = NULL;
 340              
 341                  DEBUG_ASSERT( NULL != self_ );
 342                  trace_RequestItemPostingMessage( self_, &self->strand.strand.info.interaction, self->strand.strand.info.interaction.other );
 343              
 344                  result = _PrepareMessageForAgent( self->key, msg, &msgOut );
 345                  if( MI_RESULT_OK == result )
 346                  {
 347                      StrandEntry_PostParentPassthru(&self->strand, msgOut);
 348                      Message_Release(msgOut);
 349                  }
 350 krisbash 1.3     else
 351                  {
 352                      trace_RequestItem_PostFailed(result);
 353                  }
 354              }
 355              
 356              void _RequestItem_PostControl( _In_ Strand* self_, _In_ Message* msg)
 357              {
 358                  DEBUG_ASSERT( MI_FALSE );  // not used yet
 359              }
 360              
 361              void _RequestItem_Ack( _In_ Strand* self_)
 362              {
 363                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 364                  DEBUG_ASSERT( NULL != self_ );
 365                  trace_RequestItemAck( &self_->info.interaction, self_->info.interaction.other );
 366              
 367                  if (self->finishOnErrorState != RequestItemFinishState_ProcessedFinishOnError)
 368                  {
 369                      StrandEntry_ScheduleAuxParent( &self->strand, AGENTELEM_STRANDAUX_ENTRYACK );
 370                  }
 371 krisbash 1.3 
 372                  if (self->finishOnErrorState == RequestItemFinishState_PendingFinishOnError)
 373                  {
 374                      //this is going to set finishOnErrorState to processed state
 375                      _SendErrorResponseAndClose(self, MI_RESULT_FAILED);
 376                  }
 377              
 378              
 379                  //TODO eventually multiplexer "WITH FC Buffers" should take care of flow control here
 380              }
 381              
 382              void _RequestItem_SendCancel( _In_ RequestItem* self )
 383              {
 384                  CancelMsg* msg = CancelMsg_New(self->originalOperationId);  // this will get transformed on _SendMessageToAgent
 385                  MI_Result result;
 386                  Message* msgOut = NULL;
 387              
 388                  DEBUG_ASSERT( NULL != self );
 389              
 390                  trace_RequestItemCancel( &self->strand.strand );
 391              
 392 krisbash 1.3 
 393                  if( NULL != msg )
 394                  {
 395                      result = _PrepareMessageForAgent( self->key, &msg->base, &msgOut );
 396                      if( MI_RESULT_OK == result )
 397                      {
 398                          StrandEntry_PostParent(&self->strand, msgOut);
 399                          Message_Release(msgOut);
 400                      }
 401                      else
 402                      {
 403                          trace_RequestItem_Cancel_PrepMessageFailed(result);
 404                      }
 405                      CancelMsg_Release(msg);
 406                  }
 407                  else
 408                  {
 409                      trace_RequestItem_Cancel_CancelMsg_NewFailed();
 410                  }
 411              }
 412              
 413 krisbash 1.3 void _RequestItem_Cancel( _In_ Strand* self_ )
 414              {
 415                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 416              
 417                  if( self->strand.strand.info.otherAckPending )
 418                  {
 419                      DEBUG_ASSERT( self->strand.ackPassthru );
 420                      // Do nothing now, when the Ack from parent arrives we will send the message
 421                      self->pendingCancel = MI_TRUE;
 422                  }
 423                  else
 424                  {
 425                      _RequestItem_SendCancel( self );
 426                  }
 427              }
 428              
 429              void _RequestItem_Finish( _In_ Strand* self_)
 430              {
 431                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 432              
 433                  // release request before we delete the entry
 434 krisbash 1.3     if( NULL != self->request )
 435                  {
 436                      Message_Release(self->request);
 437                      self->request = NULL;
 438                  }
 439              
 440                  StrandEntry_Delete( &self->strand );
 441              }
 442              
 443              // REQUESTITEM_STRANDAUX_PREPARETOFINISHONERROR
 444              void _RequestItem_PrepareToFinishOnError( _In_ Strand* self_)
 445              {
 446                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 447              
 448                  //if we already closed other
 449                  if (self_->info.thisClosedOther)
 450                      return;
 451              
 452                  //if there isn't an ack pending on a previous post, send the final response
 453                  if (!self_->info.thisAckPending)
 454                  {
 455 krisbash 1.3         _SendErrorResponseAndClose(self, MI_RESULT_FAILED);
 456                      return;
 457                  }
 458              
 459                  //else mark for finish when the next ack arrives
 460                  self->finishOnErrorState = RequestItemFinishState_PendingFinishOnError;
 461              }
 462              
 463              /*
 464                  Object that implements a single operation/request going to an agent thru
 465                  a binary protocol connection. Uses that one-to-many interface to multiplex multiple
 466                  operations in a single connection (AgentElem).
 467              
 468                  Behavior:
 469                  - Post calls _PrepareMessageForAgent to adapt the message to be send on the
 470                     wire the uses StrandEntry_PostParentPassthru to post to the parent
 471                     using the default many-to-one post implementation that enques the message
 472                     on the AgentElem
 473                  - Ack checks on the state of finishOnErrorState. On the normal case the ack is
 474                     just passed thru to the parent by using AGENTELEM_STRANDAUX_ENTRYACK
 475                     but if the state is RequestItemFinishState_PendingFinishOnError then an
 476 krisbash 1.3        error is send instead and if the state is RequestItemFinishState_ProcessedFinishOnError
 477                     it means nothing else is needed.
 478                  - PostControl is not currently implemented
 479                  - Cancel check if there is an Ack pending on the other side of the interaction (dispatcher)
 480                     what means that in that case the cancel cannot be sent immediately and just
 481                     set pendingCancel to true (see _RequestItem_ParentAck below). Otherwise sends
 482                     the cancel immediately.
 483                  - Close uses the default implementation
 484                  - Shutdown:
 485                     The objects are deleted thru the normal Strand logic. That is,
 486                     once the interaction is closed on both sides the object is auto-deleted.
 487                     Note that the interaction is closed once the final message is received as
 488                     noted in _RequestItem_ParentPost below
 489              
 490                  Unique features and special Behavour:
 491                  - _RequestItem_PrepareToFinishOnError is scheduled when the parent
 492                     _AgentElem_CloseAgentItem execute, that is, when for some reason
 493                     the connection to the agent needs to be closed. In that case it checks
 494                     if the Interaction has been already closed (so it doesnt need to do anything),
 495                     or if there is an Ack pending on the other side of the interaction (dispatcher)
 496                     what means that in that case the cancel cannot be sent immediately and just
 497 krisbash 1.3        sets finishOnErrorState RequestItemFinishState_PendingFinishOnError.
 498                     Otherwise it will directly send the error response and close the interaction
 499                     (finishOnErrorState  will be set to RequestItemFinishState_ProcessedFinishOnError
 500                     in that case).
 501                  - _RequestItem_AddedToParent is used to deliver the initial request ONCE
 502                     the Item has been added to the parent AgentElem connection
 503                  - _RequestItem_ParentPost just post the message from the parent back to
 504                     the left interaction (typically dispatcher) unless the connection has already being
 505                     closed for some reason. It restores the original operationId that is replaced in
 506                     the connection to the agent and it also checks if the message is a final message,
 507                     in which case closes the interaction.
 508                  - _RequestItem_ParentAck checks if the corresponding Post was PassThru
 509                     and in that case sends the Ack passThru. It also checks if there was a pending
 510                     cancel to be send (see Cancel above) and send its now that is possible.
 511              */
 512              static StrandFT _RequestItem_FT = {
 513                  _RequestItem_Post,
 514                  _RequestItem_PostControl,
 515                  _RequestItem_Ack,
 516                  _RequestItem_Cancel,
 517                  NULL,
 518 krisbash 1.3     _RequestItem_Finish,
 519                  NULL,
 520                  _RequestItem_PrepareToFinishOnError,
 521                  NULL,
 522                  NULL,
 523                  NULL,
 524                  NULL };
 525              
 526              
 527              void _IdleRequestItem_Post( _In_ Strand* self_, _In_ Message* msg)
 528              {
 529                  DEBUG_ASSERT( MI_FALSE );  // not used
 530              }
 531              
 532              void _IdleRequestItem_PostControl( _In_ Strand* self_, _In_ Message* msg)
 533              {
 534                  DEBUG_ASSERT( MI_FALSE );  // not used
 535              }
 536              
 537              void _IdleRequestItem_Ack( _In_ Strand* self_ )
 538              {
 539 krisbash 1.3     DEBUG_ASSERT( MI_FALSE );  // not used
 540              }
 541              
 542              void _IdleRequestItem_Finish( _In_ Strand* self_)
 543              {
 544                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 545              
 546                  DEBUG_ASSERT( NULL == self->request );
 547              
 548                  StrandEntry_Delete( &self->strand );
 549              }
 550              
 551              // IDLEREQUESTITEM_STRANDAUX_READYTOFINISH
 552              void _IdleRequestItem_ReadyToFinish( _In_ Strand* self_)
 553              {
 554                  RequestItem* self = (RequestItem*)StrandEntry_FromStrand(self_);
 555              
 556                  Strand_ResetDelayFinish(&self->strand.strand);
 557              }
 558              
 559              /*
 560 krisbash 1.3     Object that implements the especific request needed to receive the Idle notification
 561                  from the agent. It is attached as one Entries on the one-to-many interface with the
 562                  agent connection (AgentElem).
 563              
 564                  Behavior:
 565                  - Post, PostControl and Ack are never used
 566                  - Shutdown:
 567                     The object is not deleted thru the normal Strand logic but only
 568                     when the connection is finished. For that SetDelayFinish is set,
 569                     and only reset when _IdleRequestItem_ReadyToFinish is called,
 570                     what would happen when the parent agentElem is closed.
 571                     Aalso note the the idle notification is processed directly by the
 572                     AgentElem as never reaches the IdleRequestItem.
 573                     IdleRequestItem is only used to initiate the corresponding object,
 574                     IdleNotification, in the agent )
 575              */
 576              static StrandFT _IdleRequestItem_FT = {
 577                  _IdleRequestItem_Post,
 578                  _IdleRequestItem_PostControl,
 579                  _IdleRequestItem_Ack,
 580                  NULL,
 581 krisbash 1.3     NULL,
 582                  _IdleRequestItem_Finish,
 583                  NULL,
 584                  _IdleRequestItem_ReadyToFinish,
 585                  NULL,
 586                  NULL,
 587                  NULL,
 588                  NULL };
 589              
 590              /*
 591              **==============================================================================
 592              */
 593              
 594              void _AgentElem_NewEntry( _In_ StrandMany* self, _In_ StrandEntry* newEntry, _In_opt_ Message* msg, _Inout_ MI_Boolean* failed )
 595              {
 596                  DEBUG_ASSERT( NULL != failed );
 597                  DEBUG_ASSERT( !(*failed) );    //TODO process this properly
 598              
 599                  // Nothing to do here. The entry will post its initial message once it receives AddedToParent
 600              }
 601              
 602 krisbash 1.3 void _RequestItem_AddedToParent( _In_ StrandEntry* self, _In_ Message* msg )
 603              {
 604                  RequestItem* requestItem = (RequestItem*)self;
 605              
 606                  DEBUG_ASSERT( NULL != msg );
 607              
 608                  if( requestItem->isIdleRequest )
 609                  {
 610                      // There is no Interaction to deliver an Ack in this case
 611                      StrandEntry_PostParent( &requestItem->strand, msg );
 612                  }
 613                  else
 614                  {
 615                      StrandEntry_PostParentPassthru( &requestItem->strand, msg );
 616                  }
 617              }
 618              
 619              // Message back from protocol
 620              void _RequestItem_ParentPost( _In_ StrandEntry* self, _In_ Message* msg)
 621              {
 622                  RequestItem* requestItem = (RequestItem*)self;
 623 krisbash 1.3     //should never receive a parent post when the parent previously told us to wrap up things on error
 624                  DEBUG_ASSERT(requestItem->finishOnErrorState  == RequestItemFinishState_None);
 625              
 626                  if( self->strand.info.thisClosedOther )
 627                  {
 628                      trace_RequestItem_ParentPost_AfterClose( requestItem, msg );
 629                  }
 630                  else
 631                  {
 632                      trace_RequestItemParentPost( requestItem, msg );
 633              
 634                      /* restore operationId */
 635                      requestItem->request->operationId = requestItem->originalOperationId;
 636                      msg->operationId = requestItem->originalOperationId;
 637              
 638                      Strand_Post( &requestItem->strand.strand, msg );
 639              
 640                      /* remove item if result received */
 641                      if( Message_IsFinalResponse(msg) )
 642                      {
 643                          // Now we can close interaction (nothing else is going to be posted)
 644 krisbash 1.3             Strand_Close( &requestItem->strand.strand );
 645                      }
 646                  }
 647              }
 648              
 649              void _RequestItem_ParentAck(_In_ StrandEntry* self)
 650              {
 651                  RequestItem* requestItem = (RequestItem*)self;
 652              
 653                  if( !requestItem->isIdleRequest )
 654                  {
 655                      if( requestItem->strand.ackPassthru )
 656                      {
 657              
 658                          if( requestItem->pendingCancel )
 659                          {
 660                              requestItem->pendingCancel = MI_FALSE;
 661                              _RequestItem_SendCancel( requestItem );
 662                          }
 663              
 664                          Strand_Ack( &self->strand );
 665 krisbash 1.3         }
 666                      else
 667                      {
 668                          //only case we do a Parent Post without a need to ackPassthru is when
 669                          //posting CancelMsg (See _RequestItem_SendCancel). The strand should have been in canceled state by then
 670                          DEBUG_ASSERT(self->strand.canceled);
 671                      }
 672                  }
 673                  else
 674                  {
 675                      DEBUG_ASSERT( !requestItem->strand.ackPassthru );
 676                  }
 677              }
 678              
 679              static StrandManyInternalFT _AgentElem_InternalFT = {
 680                  _AgentElem_NewEntry,
 681                  NULL,
 682                  NULL,
 683                  NULL,
 684                  NULL,
 685                  _RequestItem_AddedToParent,
 686 krisbash 1.3     _RequestItem_ParentPost,
 687                  NULL,
 688                  _RequestItem_ParentAck,
 689                  NULL };
 690              /*
 691              **==============================================================================
 692 mike     1.1 **
 693              ** Local functions
 694              **
 695              **==============================================================================
 696              */
 697 krisbash 1.3 static MI_Uint64 _NextOperationId()
 698              {
 699                  static ptrdiff_t _operationId = 0;
 700                  return (MI_Uint64) Atomic_Inc(&_operationId);
 701              }
 702              
 703              
 704              // Called with AgentMgr lock acquired
 705 mike     1.1 static AgentElem* _FindAgent(
 706                  AgentMgr* self,
 707                  uid_t uid,
 708                  gid_t gid)
 709              {
 710                  AgentElem* agent;
 711 krisbash 1.3     ListElem* elem;
 712 mike     1.1 
 713 krisbash 1.3     elem = self->headAgents;
 714 mike     1.1 
 715 krisbash 1.3     while (elem)
 716 mike     1.1     {
 717 krisbash 1.3         agent = FromOffset(AgentElem,next,elem);
 718              
 719 mike     1.1         if (uid == agent->uid && gid == agent->gid)
 720 krisbash 1.3         {
 721 mike     1.1             return agent;
 722 krisbash 1.3         }
 723 mike     1.1 
 724 krisbash 1.3         elem = elem->next;
 725 mike     1.1     }
 726 krisbash 1.3 
 727 mike     1.1     return 0;
 728              }
 729              
 730              static pid_t _SpawnAgentProcess(
 731                  Sock s,
 732                  int logfd,
 733                  uid_t uid,
 734                  gid_t gid,
 735                  const char* provDir,
 736                  MI_Uint32 idletimeout)
 737              {
 738                  pid_t child;
 739                  int fdLimit;
 740                  int fd;
 741                  char param_sock[32];
 742                  char param_logfd[32];
 743                  char param_idletimeout[32];
 744 krisbash 1.3     const char* agentProgram = OMI_GetPath(ID_AGENTPROGRAM);
 745 mike     1.1 
 746                  child = fork();
 747              
 748                  if (child < 0)
 749                      return -1;  /* Failed */
 750              
 751                  if (child > 0)
 752                      return child;   /* Started */
 753              
 754                  /* We are in child process here */
 755              
 756                  /* switch user */
 757                  if (0 != SetUser(uid,gid))
 758                  {
 759                      _exit(1);
 760                  }
 761              
 762                  /* Close all open file descriptors except provided socket
 763                   (Some systems have UNLIMITED of 2^64; limit to something reasonable) */
 764              
 765                  fdLimit = getdtablesize();
 766 mike     1.1     if (fdLimit > 2500 || fdLimit < 0)
 767                  {
 768                      fdLimit = 2500;
 769                  }
 770              
 771                  /* ATTN: close first 3 also! Left for debugging only */
 772                  for (fd = 3; fd < fdLimit; ++fd)
 773                  {
 774                      if (fd != s && fd != logfd)
 775                          close(fd);
 776                  }
 777              
 778                  /* prepare parameter:
 779                      socket fd to attach */
 780                  Snprintf(param_sock, sizeof(param_sock), "%d", (int)s);
 781                  Snprintf(param_logfd, sizeof(param_logfd), "%d", (int)logfd);
 782                  Snprintf(param_idletimeout, sizeof(param_idletimeout), "%d", (int)idletimeout);
 783              
 784 krisbash 1.3     execl(agentProgram,
 785                      agentProgram,
 786 mike     1.1         param_sock,
 787                      param_logfd,
 788                      "--destdir",
 789 krisbash 1.3         OMI_GetPath(ID_DESTDIR),
 790 mike     1.1         "--providerdir",
 791                      provDir,
 792                      "--idletimeout",
 793                      param_idletimeout,
 794                      "--loglevel",
 795                      Log_GetLevelString(Log_GetLevel()),
 796                      NULL);
 797              
 798 krisbash 1.3     trace_AgentLaunch_Failed(scs(agentProgram), errno);
 799                  _exit(1);
 800 mike     1.1     return -1;  /* never get here */
 801              }
 802              
 803 krisbash 1.3 static void _AgentElem_CloseAgentItem( Strand* self_ )
 804 mike     1.1 {
 805 krisbash 1.3     AgentElem* agent = (AgentElem*)StrandMany_FromStrand(self_);
 806                  RequestItem* requestItem;
 807 mike     1.1 
 808 krisbash 1.3     StrandMany_BeginIteration( &agent->strand );
 809 mike     1.1 
 810                  /* send error repsonses to all outstanding requests */
 811 krisbash 1.3     while( NULL != (requestItem = (RequestItem*)StrandMany_Iterate( &agent->strand )) )
 812 mike     1.1     {
 813 krisbash 1.3         if(  requestItem->isIdleRequest )
 814                      {
 815                          StrandEntry_ScheduleAux(&requestItem->strand, IDLEREQUESTITEM_STRANDAUX_READYTOFINISH );
 816                      }
 817                      else
 818                      {
 819                          StrandEntry_ScheduleAux(&requestItem->strand, REQUESTITEM_STRANDAUX_PREPARETOFINISHONERROR );
 820                      }
 821                      // No need to call StrandMany_DeleteEntry(&requestItem->strand) to delete requestItem (it would do so itself )
 822 mike     1.1     }
 823              
 824                  if (agent->protocol)
 825 krisbash 1.3     {
 826                      // We can now close the interaction with protocol if not done already
 827                      if( !agent->strand.strand.info.thisClosedOther )
 828                          Strand_Close( &agent->strand.strand );
 829                  }
 830                  else
 831                  {
 832                      agent->strand.strand.info.thisClosedOther = agent->strand.strand.info.otherClosedThis = MI_TRUE;
 833                  }
 834 mike     1.1 
 835                  /* SIGCHILD HANDLER will take care of pid waiting */
 836                  /*if (agent->agentPID > 0)
 837                  {
 838                      int loc = 0;
 839                      pid_t p = waitpid(agent->agentPID, &loc, WNOHANG);
 840              
 841                      LOGI_CHAR(("waitpid returned %d, loc %d",(int)p, loc));
 842              
 843                      if (p != agent->agentPID)
 844                      {
 845                          kill(agent->agentPID, SIGKILL);
 846                          p = waitpid(agent->agentPID, &loc, WNOHANG);
 847              
 848                          LOGW_CHAR(("sent KILL; waitpid returned %d, loc %d",(int)p, loc));
 849                      }
 850                  }*/
 851              
 852 krisbash 1.3     // the AgentElem should delete itself on Finish
 853 mike     1.1 }
 854              
 855 krisbash 1.3 size_t _AgentElem_HashMapHashProc(const HashBucket* bucket)
 856 mike     1.1 {
 857 krisbash 1.3     const RequestItem* self = (const RequestItem*)StrandEntry_FromBucketConst(bucket);
 858                  return (size_t)self->key;
 859              }
 860 mike     1.1 
 861 krisbash 1.3 int _AgentElem_HashMapEqualProc(_In_ const HashBucket* bucket1, _In_ const HashBucket* bucket2)
 862              {
 863                  const RequestItem* entry1 = (const RequestItem*)StrandEntry_FromBucketConst(bucket1);
 864                  const RequestItem* entry2 = (const RequestItem*)StrandEntry_FromBucketConst(bucket2);
 865                  return entry1->key == entry2->key;
 866 mike     1.1 }
 867              
 868 krisbash 1.3 StrandEntry* _AgentElem_FindRequest(_In_ const StrandMany* parent, _In_ const Message* msg)
 869 mike     1.1 {
 870 krisbash 1.3     AgentElem* agent = (AgentElem*)parent;
 871                  RequestItem forSearch;
 872                  HashBucket* bucket;
 873 mike     1.1 
 874 krisbash 1.3     forSearch.key = msg->operationId;
 875 mike     1.1 
 876 krisbash 1.3     bucket = HashMap_Find(&agent->strand.many,&forSearch.strand.bucket);
 877 mike     1.1 
 878 krisbash 1.3     if( NULL == bucket )
 879 mike     1.1     {
 880 krisbash 1.3         trace_AgentElem_FindRequest_CannotFindKey( agent, &agent->strand.strand, forSearch.key );
 881                      return NULL;
 882 mike     1.1     }
 883 krisbash 1.3     else
 884 mike     1.1     {
 885 krisbash 1.3         RequestItem* self = (RequestItem*)StrandEntry_FromBucket(bucket);
 886                      trace_AgentElemFoundKey( agent, &agent->strand.strand, forSearch.key, self, &self->strand.strand );
 887                      return (StrandEntry*)self;
 888 mike     1.1     }
 889              }
 890              
 891 krisbash 1.3 // Called with AgentMgr lock acquired
 892 mike     1.1 static AgentElem* _CreateAgent(
 893 krisbash 1.3     _In_ AgentMgr* self,
 894 mike     1.1     uid_t uid,
 895 krisbash 1.3     gid_t gid )
 896 mike     1.1 {
 897                  AgentElem* agent = 0;
 898                  Sock s[2];
 899                  int logfd = -1;
 900 krisbash 1.3     InteractionOpenParams interactionParams;
 901 mike     1.1 
 902                  /* create communication pipe */
 903                  if(0 != socketpair(AF_UNIX, SOCK_STREAM, 0, s))
 904                  {
 905 krisbash 1.3         trace_SocketPair_Failed();
 906 mike     1.1         return 0;
 907                  }
 908              
 909                  if (MI_RESULT_OK != Sock_SetBlocking(s[0], MI_FALSE) ||
 910                      MI_RESULT_OK != Sock_SetBlocking(s[1], MI_FALSE))
 911                  {
 912 krisbash 1.3         trace_SetNonBlocking_Failed();
 913 mike     1.1         goto failed;
 914                  }
 915              
 916                  /* create/open log file for agent */
 917                  {
 918 krisbash 1.3         char path[PAL_MAX_PATH_SIZE];
 919 mike     1.1 
 920                      if (0 != FormatLogFileName(uid, gid, path))
 921                      {
 922 krisbash 1.3             trace_CannotFormatLogFilename();
 923 mike     1.1             goto failed;
 924                      }
 925              
 926                      /* Create/open fiel with permisisons 644 */
 927                      logfd = open(path, O_WRONLY|O_CREAT|O_APPEND, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
 928                      if (logfd == -1)
 929                      {
 930 krisbash 1.3             trace_CreateLogFile_Failed(scs(path), (int)errno);
 931 mike     1.1             goto failed;
 932                      }
 933                  }
 934              
 935 krisbash 1.3     agent = (AgentElem*)StrandMany_New(
 936                                          STRAND_DEBUG( AgentElem )
 937                                          &_AgentElem_FT,
 938                                          &_AgentElem_InternalFT,
 939                                          sizeof(AgentElem),
 940                                          STRAND_FLAG_ENTERSTRAND,
 941                                          NULL,
 942                                          100,
 943                                          _AgentElem_HashMapHashProc,
 944                                          _AgentElem_HashMapEqualProc,
 945                                          _AgentElem_FindRequest );
 946 mike     1.1 
 947                  if (!agent)
 948                      goto failed;
 949              
 950                  agent->agentMgr = self;
 951                  agent->uid = uid;
 952                  agent->gid = gid;
 953              
 954 krisbash 1.3     if ((agent->agentPID =
 955 mike     1.1         _SpawnAgentProcess(
 956 krisbash 1.3             s[0],
 957                          logfd,
 958                          uid,
 959                          gid,
 960                          self->provDir,
 961 mike     1.1             (MI_Uint32)(self->provmgr.idleTimeoutUsec / 1000000))) < 0)
 962                  {
 963 krisbash 1.3         trace_CannotSpawnChildProcess();
 964 mike     1.1         goto failed;
 965                  }
 966              
 967                  close(logfd);
 968                  logfd = -1;
 969              
 970                  /* Close socket 0 - it will be used by child process */
 971                  Sock_Close(s[0]);
 972                  s[0] = INVALID_SOCK;
 973              
 974 krisbash 1.3     Strand_OpenPrepare(&agent->strand.strand,&interactionParams,NULL,NULL,MI_TRUE);
 975              
 976                  if( MI_RESULT_OK != ProtocolSocketAndBase_New_AgentConnector(
 977 mike     1.1         &agent->protocol,
 978                      self->selector,
 979                      s[1],
 980 krisbash 1.3         &interactionParams ) )
 981 mike     1.1             goto failed;
 982              
 983                  s[1] = INVALID_SOCK;
 984              
 985 krisbash 1.3     trace_AgentItemCreated(agent);
 986 mike     1.1     List_Append(
 987 krisbash 1.3         &self->headAgents,
 988                      &self->tailAgents,
 989                      (ListElem*)&(agent->next));
 990 mike     1.1 
 991                  return agent;
 992              
 993              failed:
 994 krisbash 1.3     if (INVALID_SOCK != s[0])
 995 mike     1.1         Sock_Close(s[0]);
 996              
 997 krisbash 1.3     if (INVALID_SOCK != s[1])
 998 mike     1.1         Sock_Close(s[1]);
 999              
1000 krisbash 1.3     if (-1 != logfd)
1001 mike     1.1         close(logfd);
1002              
1003                  if (agent)
1004 krisbash 1.3     {
1005                      _AgentElem_InitiateClose(agent);
1006                  }
1007 mike     1.1 
1008                  return 0;
1009              }
1010              
1011 krisbash 1.3 // Called with AgentMgr lock acquired
1012              static MI_Result _SendRequestToAgent_Common(
1013                  _In_ RequestItem* requestItem,
1014                  _In_ Message* msg,
1015                  _In_opt_ const ProvRegEntry* proventry)
1016 mike     1.1 {
1017 krisbash 1.3     MI_Result result;
1018                  Message* req = NULL;
1019                  MI_Uint64 operationId;
1020              
1021                  operationId = _NextOperationId();
1022                  requestItem->key = operationId;
1023              
1024                  result = _PrepareMessageForAgent( operationId, msg, &req );
1025                  if( MI_RESULT_OK != result )
1026                  {
1027                      trace_PrepareMessageForAgent_Failed(result);
1028                      StrandEntry_DeleteNoAdded( &requestItem->strand );
1029                      return result;
1030                  }
1031              
1032                  if( NULL != proventry )
1033                  {
1034                      DEBUG_ASSERT( Message_IsRequest(req) );
1035                      {
1036                          RequestMsg* request = (RequestMsg*)req;
1037                          request->libraryName = Batch_Strdup(req->batch, proventry->libraryName);
1038 krisbash 1.3             request->instanceLifetimeContext = proventry->instanceLifetimeContext;
1039              
1040                          if (!request->libraryName)
1041                          {
1042                              trace_SendRequestToAgent_Batch_Strdup_Failed();
1043                              StrandEntry_DeleteNoAdded( &requestItem->strand );
1044                              Message_Release(req);
1045                              return MI_RESULT_FAILED;
1046                          }
1047                      }
1048                  }
1049              
1050                  trace_AgentMgr_SendRequestToAgent(
1051                      req,
1052                      req->tag,
1053                      MessageName(req->tag),
1054                      req->operationId,
1055                      requestItem->originalOperationId,
1056                      requestItem->key );
1057              
1058                  StrandEntry_ScheduleAdd( &requestItem->strand, req);
1059 mike     1.1 
1060 krisbash 1.3     Message_Release(req);
1061 mike     1.1 
1062 krisbash 1.3     return MI_RESULT_OK;
1063 mike     1.1 }
1064              
1065 krisbash 1.3 // Called with AgentMgr lock acquired
1066              static MI_Result _SendIdleRequestToAgent(
1067                  _Inout_ AgentElem* agent )
1068              {
1069                  RequestItem* requestItem;
1070                  MI_Result result;
1071                  BinProtocolNotification* notification;
1072 mike     1.1 
1073 krisbash 1.3     notification = BinProtocolNotification_New( BinNotificationAgentIdle );
1074 mike     1.1 
1075 krisbash 1.3     if( !notification )
1076                  {
1077                      trace_SendRequestToAgent_StrandNewFailed();
1078 mike     1.1         return MI_RESULT_FAILED;
1079 krisbash 1.3     }
1080 mike     1.1 
1081 krisbash 1.3     requestItem = (RequestItem*) StrandEntry_New(
1082                                                  STRAND_DEBUG( IdleRequestItem )
1083                                                  &agent->strand,
1084                                                  &_IdleRequestItem_FT,
1085                                                  sizeof(RequestItem),
1086                                                  STRAND_FLAG_ENTERSTRAND|STRAND_FLAG_NOINTERACTION,
1087                                                  NULL );
1088                  if( NULL == requestItem )
1089 mike     1.1     {
1090 krisbash 1.3         trace_SendRequestToAgent_StrandNewFailed();
1091                      BinProtocolNotification_Release(notification);
1092 mike     1.1         return MI_RESULT_FAILED;
1093                  }
1094              
1095 krisbash 1.3     requestItem->isIdleRequest = MI_TRUE;
1096                  requestItem->pendingCancel = MI_FALSE;
1097                  requestItem->finishOnErrorState = RequestItemFinishState_None;
1098                  Strand_SetDelayFinish(&requestItem->strand.strand);
1099                  Strand_Leave(&requestItem->strand.strand);
1100              
1101                  result = _SendRequestToAgent_Common( requestItem, &notification->base, NULL );
1102              
1103                  BinProtocolNotification_Release(notification);
1104 mike     1.1 
1105 krisbash 1.3     return result;
1106              }
1107              
1108              // Called with AgentMgr lock acquired
1109              static MI_Result _SendRequestToAgent(
1110                  _Inout_ AgentElem* agent,
1111                  _In_ InteractionOpenParams* interactionParams,
1112                  _In_ Message* msg,
1113                  _In_ const ProvRegEntry* proventry)
1114              {
1115                  RequestItem* requestItem;
1116              
1117                  DEBUG_ASSERT( NULL != interactionParams );
1118                  trace_SendMessageToAgent( msg->tag );
1119              
1120                  requestItem = (RequestItem*) StrandEntry_New(
1121                                                  STRAND_DEBUG( RequestItem )
1122                                                  &agent->strand,
1123                                                  &_RequestItem_FT,
1124                                                  sizeof(RequestItem),
1125                                                  0,
1126 krisbash 1.3                                     interactionParams );
1127                  if( NULL == requestItem )
1128 mike     1.1     {
1129 krisbash 1.3         trace_SendRequestToAgent_StrandNewFailed();
1130 mike     1.1         return MI_RESULT_FAILED;
1131                  }
1132 krisbash 1.3 
1133                  requestItem->originalOperationId = msg->operationId;
1134                  requestItem->request = msg;
1135                  requestItem->isIdleRequest = MI_FALSE;
1136                  requestItem->pendingCancel = MI_FALSE;
1137                  requestItem->finishOnErrorState = RequestItemFinishState_None;
1138              
1139 mike     1.1     /* Add ref to keep request around until Result received */
1140                  Message_AddRef(msg);
1141              
1142 krisbash 1.3     return _SendRequestToAgent_Common( requestItem, msg, proventry );
1143 mike     1.1 }
1144              
1145              #endif
1146              
1147              /*
1148              **==============================================================================
1149              **
1150              ** Public API
1151              **
1152              **==============================================================================
1153              */
1154              MI_Result AgentMgr_Init(
1155                  AgentMgr* self,
1156                  Selector* selector)
1157              {
1158                  /* Check parameters */
1159                  if (!self)
1160                      return MI_RESULT_INVALID_PARAMETER;
1161              
1162                  memset(self, 0, sizeof(*self));
1163              
1164 mike     1.1     /* Initialize the provider manager */
1165 krisbash 1.3     MI_RETURN_ERR(ProvMgr_Init(&self->provmgr, selector, NULL, NULL, OMI_GetPath(ID_PROVIDERDIR)));
1166 mike     1.1 
1167 krisbash 1.3     self->home = PAL_Strdup(OMI_GetPath(ID_PREFIX));
1168                  self->provDir = PAL_Strdup(OMI_GetPath(ID_PROVIDERDIR));
1169 mike     1.1 
1170                  self->selector = selector;
1171              
1172 krisbash 1.3     ReadWriteLock_Init(&self->lock);
1173              
1174              #if defined(CONFIG_ENABLE_PREEXEC)
1175                  PreExec_Construct(&self->preexec);
1176              #endif /* defined(CONFIG_ENABLE_PREEXEC) */
1177              
1178 mike     1.1     return MI_RESULT_OK;
1179              }
1180              
1181              MI_Result AgentMgr_Destroy(
1182                  AgentMgr* self)
1183              {
1184 krisbash 1.3     ListElem* listElem;
1185              
1186 mike     1.1     ProvMgr_Destroy(&self->provmgr);
1187 krisbash 1.3     PAL_Free(self->home);
1188                  PAL_Free(self->provDir);
1189              
1190              #if defined(CONFIG_ENABLE_PREEXEC)
1191                  PreExec_Destruct(&self->preexec);
1192              #endif /* defined(CONFIG_ENABLE_PREEXEC) */
1193 mike     1.1 
1194              #if defined(CONFIG_POSIX)
1195                  /*
1196                      Free all outstanding agents
1197                  */
1198 krisbash 1.3     ReadWriteLock_AcquireWrite(&self->lock);
1199                  listElem = self->headAgents;
1200                  while (listElem)
1201 mike     1.1     {
1202 krisbash 1.3         AgentElem* agent = FromOffset(AgentElem,next,listElem);
1203 mike     1.1 
1204 krisbash 1.3         StrandMany_ScheduleAux( &agent->strand, AGENTELEM_STRANDAUX_CLOSEAGENTITEM );
1205 mike     1.1 
1206 krisbash 1.3         listElem = listElem->next;
1207 mike     1.1     }
1208 krisbash 1.3     ReadWriteLock_ReleaseWrite(&self->lock);
1209 mike     1.1 #endif
1210              
1211                  /* Invalidate self */
1212                  memset(self, 0xdd, sizeof(*self));
1213              
1214                  return MI_RESULT_OK;
1215              }
1216              
1217 krisbash 1.3 void AgentMgr_OpenCallback(
1218                  _Inout_ InteractionOpenParams* params )
1219              {
1220                  MI_Result result;
1221                  AgentMgr_OpenCallbackData* callbackData = (AgentMgr_OpenCallbackData*)params->callbackData;
1222              
1223                  result = AgentMgr_HandleRequest( callbackData->self, params, callbackData->proventry );
1224                  if( MI_RESULT_OK != result )
1225                  {
1226                      Strand_FailOpenWithResult(params, result, PostResultMsg_NewAndSerialize);
1227                  }
1228              }
1229              
1230 mike     1.1 MI_Result AgentMgr_HandleRequest(
1231 krisbash 1.3     _In_ AgentMgr* self,
1232                  _Inout_ InteractionOpenParams* params,
1233                  _In_ const ProvRegEntry* proventry)
1234 mike     1.1 {
1235 krisbash 1.3     MI_Result result = MI_RESULT_OK;
1236 mike     1.1     AgentElem* agent;
1237                  uid_t uid;
1238                  gid_t gid;
1239 krisbash 1.3     RequestMsg* msg = (RequestMsg*)params->msg;
1240              
1241                  trace_AgentMgrHandleRequest(msg, msg->base.tag);
1242              
1243                  DEBUG_ASSERT( Message_IsRequest(&msg->base) );
1244 mike     1.1 
1245                  if (proventry->hosting == PROV_HOSTING_INPROC)
1246 krisbash 1.3     {
1247              #if defined(CONFIG_POSIX)
1248                      /* For in proc provider, following checks if an incoming
1249                       * request from non-root user, and omiserver is running
1250                       * under root user, then return access denied error, otherwise
1251                       * it could cause a problem that non-root user runs code under root
1252                       */
1253                      if (IsAuthCallsIgnored() == 0)
1254                      {
1255                          /* Reject in-proc provider requests for non-root client users */
1256                          if (IsRoot() == 0 && msg->authInfo.uid != 0)
1257                          {
1258                              /* user name */
1259                              char name[USERNAME_SIZE];
1260                              char* uname = (char*)name;
1261                              if (0 != GetUserName(msg->authInfo.uid, name))
1262                                  uname = "unknown user";
1263                              trace_NonRootUserAccessInprocProvider(uname, proventry->className, proventry->nameSpace);
1264                              return MI_RESULT_ACCESS_DENIED;
1265                          }
1266                      }
1267 krisbash 1.3 #endif /* defined(CONFIG_POSIX) */
1268              
1269                      return ProvMgr_NewRequest(
1270 mike     1.1             &self->provmgr,
1271 krisbash 1.3             proventry,
1272                          params );
1273                  }
1274 mike     1.1 
1275                  if (proventry->hosting == PROV_HOSTING_USER)
1276                  {
1277                      if (0 != LookupUser(proventry->user, &uid, &gid))
1278                      {
1279 krisbash 1.3             trace_GetUserUidGid_Failed(scs(proventry->user));
1280 mike     1.1             return MI_RESULT_FAILED;
1281                      }
1282                  }
1283                  else
1284                  {
1285 krisbash 1.3         uid = msg->authInfo.uid;
1286                      gid = msg->authInfo.gid;
1287                      MI_UNREFERENCED_PARAMETER(uid);
1288                      MI_UNREFERENCED_PARAMETER(gid);
1289 mike     1.1     }
1290              
1291 krisbash 1.3 #if defined(CONFIG_ENABLE_PREEXEC)
1292                  if (PreExec_Exec(&self->preexec, proventry->preexec, uid, gid) != 0)
1293                      return MI_RESULT_FAILED;
1294              #endif /* defined(CONFIG_ENABLE_PREEXEC) */
1295              
1296 mike     1.1 #if defined(CONFIG_POSIX)
1297              
1298 krisbash 1.3     // We cannot use ReadWriteLock_AcquireRead(&self->lock);
1299                  // as we may need to create the object here
1300                  // (and there is no option to upgrade from read to write acquisition)
1301                  ReadWriteLock_AcquireWrite(&self->lock);
1302              
1303                  agent = _FindAgent(self, uid, gid);
1304 mike     1.1 
1305                  if (!agent)
1306 krisbash 1.3     {
1307                      agent = _CreateAgent(self, uid, gid );
1308              
1309                      if (!agent)
1310                      {
1311                          trace_FailedLoadProviderAgent();
1312                          result = MI_RESULT_FAILED;
1313                      }
1314                      else
1315                      {
1316                          result = _SendIdleRequestToAgent( agent );
1317                      }
1318                  }
1319              
1320                  if( MI_RESULT_OK == result )
1321                  {
1322                      result = _SendRequestToAgent(agent, params, &msg->base, proventry);
1323                  }
1324              
1325                  ReadWriteLock_ReleaseWrite(&self->lock);
1326              
1327 krisbash 1.3     return result;
1328 mike     1.1 
1329              #else
1330                  MI_UNUSED(agent);
1331                  /* windows version hosts all providers as 'in-proc' */
1332 krisbash 1.3     return ProvMgr_NewRequest(
1333 mike     1.1             &self->provmgr,
1334 krisbash 1.3             proventry,
1335                          params );
1336 mike     1.1 #endif
1337              }

ViewCVS 0.9.2