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

   1 mike  1.1 /*
   2           **==============================================================================
   3           **
   4           ** Open Management Infrastructure (OMI)
   5           **
   6           ** Copyright (c) Microsoft Corporation
   7           ** 
   8           ** 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           **
  14           ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15           ** 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           **
  19           ** See the Apache 2 License for the specific language governing permissions 
  20           ** and limitations under the License.
  21           **
  22 mike  1.1 **==============================================================================
  23           */
  24           
  25           #include "context.h"
  26 krisbash 1.5 #include "AggregationContext.h"
  27              #include "SubscriptionContext.h"
  28              #include "LifecycleContext.h"
  29              #include "SubMgr.h"
  30 mike     1.3 #include <wsman/wsbuf.h>
  31 mike     1.1 #include <wql/wql.h>
  32 krisbash 1.5 #include <pal/format.h>
  33              #include <pal/thread.h>
  34              #include <pal/sleep.h>
  35              #include "nioproc.h"
  36              #include <omi_error/omierror.h>
  37              
  38              STRAND_DEBUGNAME3( Context, TryPostLeft, TryPostLeftNotify, InvokeSubscribe );
  39 mike     1.1 
  40              static const MI_Uint32 _MAGIC = 0x35eb3d3b;
  41              
  42 krisbash 1.5 static MI_Result MI_CALL _PostError(
  43                  _In_ MI_Context* self,
  44                  MI_Uint32 result,
  45                  _In_z_ const ZChar* type,
  46                  _In_z_ const ZChar* message);
  47              
  48              void _Context_Destroy(
  49                  _Inout_ Context* self)
  50              {
  51                  RequestMsg* request = self ? self->request : 0;
  52                  Message* loadRequest = self ? self->loadRequest : 0;
  53              
  54                  trace_ContextDestroy( self, &self->strand, &self->strand.info.interaction );
  55              
  56                  DEBUG_ASSERT( self );
  57                  
  58                  if (self->provider)
  59                  {
  60                      Provider_Release(self->provider);
  61                  }
  62              
  63 krisbash 1.5     memset(self, 0xFF, sizeof(Context));
  64              
  65                  /* Context typically allocated from message's batch
  66                   * so it may be freed right inside 'Release' call 
  67                   */
  68                  if (request)
  69                      Message_Release(&request->base);
  70              
  71                  if (loadRequest)
  72                      Message_Release(loadRequest);
  73              }
  74              
  75              /*
  76               * Post a message to the component to the left
  77               */
  78              _Use_decl_annotations_
  79              void Context_PostMessageLeft( 
  80                  Context* self,
  81                  Message* msg)
  82              {
  83                  ptrdiff_t tryingToPostLeft;
  84 krisbash 1.5 // Uncomment when no longer using Selector
  85              //#if !defined(CONFIG_OS_WINDOWS)
  86                  ThreadID threadId = Thread_ID();
  87                  Selector* selector = self->provider->lib->provmgr->selector;
  88              //#endif
  89              
  90                  // It is not clear if a Provider can Post concurrently in different threads (UT does)
  91                  // so protect against it
  92                  Lock_Acquire(&self->lock);
  93                  
  94                  DEBUG_ASSERT( NULL != self->strand.info.interaction.other );
  95                  DEBUG_ASSERT( NULL == self->msgPostingLeft );
  96                  DEBUG_ASSERT( 0 == self->tryingToPostLeft );
  97              
  98                  // we dont need to add a reference to the message as 
  99                  // we are not going to leave this function on this thread until is sent
 100                  // (event if it is actually sent in another thread)
 101                  self->msgPostingLeft = msg; 
 102              
 103              // Uncomment when no longer using Selector
 104              //#if !defined(CONFIG_OS_WINDOWS)
 105 krisbash 1.5     if( Selector_IsSelectorThread( selector, &threadId ) )
 106                  {
 107                      Context_PostMessageLeft_IoThread( self );
 108                      self->postingOnIoThread = MI_TRUE;
 109                  }
 110              //#endif
 111                  Atomic_Swap(&self->tryingToPostLeft,(ptrdiff_t)(CONTEXT_POSTLEFT_POSTING|CONTEXT_POSTLEFT_SCHEDULED));
 112              
 113                  Strand_ScheduleAux( &self->strand, CONTEXT_STRANDAUX_TRYPOSTLEFT );
 114              
 115                  while( (tryingToPostLeft = ReadWithFence( &self->tryingToPostLeft )) != 0 )
 116                  {
 117              // Uncomment when no longer using Selector
 118              //#if defined(CONFIG_OS_WINDOWS)
 119              //        CondLock_Wait(
 120              //            (ptrdiff_t)self, &self->tryingToPostLeft, tryingToPostLeft, CONDLOCK_DEFAULT_SPINCOUNT);
 121              //#else
 122                      if( self->postingOnIoThread )
 123                      {
 124                          Selector_Run( selector, TIME_NEVER, MI_TRUE );
 125                      }
 126 krisbash 1.5         else
 127                      {
 128                          CondLock_Wait(
 129                              (ptrdiff_t)self, &self->tryingToPostLeft, tryingToPostLeft, CONDLOCK_DEFAULT_SPINCOUNT);
 130                      }
 131              //#endif
 132                  }
 133              
 134                  // Sent
 135                  DEBUG_ASSERT( 0 == self->tryingToPostLeft );
 136              
 137              #ifndef DISABLE_INDICATION
 138                  if (CTX_TYPE_IND_SUBSCRIPTION == self->ctxType ||
 139                      CTX_TYPE_IND_LIFECYCLE == self->ctxType)
 140                  {
 141                      SubscriptionContext* subCtx = (SubscriptionContext*)self;
 142                      if (ReadWithFence(&subCtx->subscription->finalmsgbit) == 1)
 143                      {
 144                          /*
 145                           * Release the refcount added by SubscrContext_Init
 146                           */
 147 krisbash 1.5             SubMgrSubscription_Release(subCtx->subscription);
 148                      }
 149                  }
 150              #endif
 151              
 152                  Lock_Release(&self->lock);
 153              }
 154              
 155              void Context_PostSchema( 
 156                  _In_ Context* self,
 157                  _In_ Message* msg)
 158              {
 159                  Context_PostMessageLeft(self, msg);
 160              }
 161              
 162              _Use_decl_annotations_
 163              void Context_Close( Context* self )
 164              {
 165                  // Note that some contexts are used internally (for example to load providers)
 166                  // and therefore dont have an interaction
 167                  if( NULL != self->strand.info.interaction.other )
 168 krisbash 1.5     {
 169                      Strand_ScheduleClose(&self->strand);
 170                  }
 171                  else
 172                  {
 173                      _Context_Destroy(self);
 174                  }
 175              }
 176              
 177 mike     1.1 static MI_Result _ProcessResult(
 178                  MI_Context* self_,
 179                  MI_Result result,
 180 krisbash 1.5     const ZChar* errorMessage,
 181                  const MI_Instance* cimError)
 182 mike     1.1 {
 183                  Context* self = (Context*)self_;
 184              
 185                  if (!self || self->magic != _MAGIC)
 186                      return MI_RESULT_INVALID_PARAMETER;
 187              
 188 krisbash 1.5     trace_Provider_PostResult(result);
 189              
 190                  if (result == MI_RESULT_NOT_SUPPORTED &&
 191                      self->request && self->request->base.tag == ModifyInstanceReqTag &&
 192                      self->postedModifyInstance == MI_FALSE &&
 193                      self->postedModifyGetInstance == MI_TRUE &&
 194                      self->postedModifyEnumInstance != MI_TRUE)
 195                  {
 196                      /* Provider does not support GetInstance so we need to do an Enumerate instead */
 197                      if (self->provider->classDecl->providerFT->EnumerateInstances)
 198                      {
 199                          ModifyInstanceReq* request = (ModifyInstanceReq*)self->request;
 200              
 201                          /* convert this into a filtering enum because GetInstance is not implemented. */
 202                          self->inst = self->keyInstance;
 203                          self->instanceName = NULL;
 204                          self->postedModifyEnumInstance = MI_TRUE;
 205                          self->provider->classDecl->providerFT->EnumerateInstances(self->provider->self, self_, request->nameSpace, self->keyInstance->classDecl->name, NULL, MI_FALSE, NULL);
 206                          return MI_RESULT_OK;
 207                      }
 208                      else
 209 krisbash 1.5         {
 210                          /* We cannot handle the contract, we we need to fail. Fall through to send an error */
 211                      }
 212                  }
 213                  else if (result == MI_RESULT_OK && self->request && self->request->base.tag == ModifyInstanceReqTag && self->postedModifyInstance == MI_FALSE)
 214                  {
 215                      ModifyInstanceReq* request = (ModifyInstanceReq*) self->request;
 216                      /* Need to re-send the request now as a GetInstance so we can get the final result. */
 217                      if (self->provider->classDecl->providerFT->GetInstance)
 218                      {
 219                          self->postedModifyGetInstance = MI_TRUE;
 220                          self->provider->classDecl->providerFT->GetInstance(self->provider->self, self_, request->nameSpace, self->keyInstance->classDecl->name, self->keyInstance, NULL);
 221                          return MI_RESULT_OK;
 222                      }
 223                      else if (self->provider->classDecl->providerFT->EnumerateInstances)
 224                      {
 225                          /* convert this into a filtering enum because GetInstance is not implemented. */
 226                          self->inst = self->keyInstance;
 227                          self->instanceName = NULL;
 228                          self->postedModifyEnumInstance = MI_TRUE;
 229                          self->postedModifyGetInstance = MI_TRUE; /* For state management need to think we tried a GetInst */
 230 krisbash 1.5             self->provider->classDecl->providerFT->EnumerateInstances(self->provider->self, self_, request->nameSpace, self->keyInstance->classDecl->name, NULL, MI_FALSE, NULL);
 231                          return MI_RESULT_OK;
 232                      }
 233                      else
 234                      {
 235                          /* Cannot complete the operation because neither Get or Enum is supported. */
 236                          result = MI_RESULT_NOT_SUPPORTED;
 237                      }
 238                  }
 239 mike     1.1 
 240                  /* If no instances matched during GetInstance over EnumerateInstance */
 241                  if (self->instanceName && !self->matchedInstanceName)
 242                  {
 243                      if (result == MI_RESULT_OK)
 244                          result = MI_RESULT_NOT_FOUND;
 245                  }
 246              
 247                  if (self->request && !self->cancelled)
 248                  {
 249 krisbash 1.5         PostResultMsg* resp = PostResultMsg_New( self->request->base.operationId );
 250 mike     1.1 
 251                      if (!resp)
 252                          return MI_RESULT_FAILED;
 253              
 254 krisbash 1.5         if (self->request->base.flags & WSMANFlag)
 255                      {
 256                          /* Need to clone this in case we need to thread switch. Not the most efficient,
 257                           * but this is consumed in the error packet creation code and seems to be the 
 258                           * best way to achieve this for now.
 259                           */
 260                          resp->cimError = cimError;
 261              
 262                          if (cimError)
 263                          {
 264                              WSBuf_InstanceToBuf(
 265                                  self->request->userAgent,
 266                                  cimError,
 267                                  NULL, /* filterProperty */
 268                                  NULL, /* filterPropertyData */
 269                                  cimError->classDecl,
 270                                  resp->base.batch, 
 271                                  WSMAN_ObjectFlag | WSMAN_IsCimError,
 272                                  &resp->packedInstancePtr, 
 273                                  &resp->packedInstanceSize);
 274              
 275 krisbash 1.5                 resp->cimErrorClassName = Batch_Tcsdup(resp->base.batch, cimError->classDecl->name);
 276                          }
 277                          else
 278                          {
 279                              resp->packedInstancePtr = NULL;
 280                              resp->packedInstanceSize = 0;
 281                              resp->cimErrorClassName = NULL;
 282                          }
 283              
 284                          /* Need to clone this in case we need to thread switch */
 285                          if (errorMessage)
 286                          {
 287                              resp->errorMessage = Batch_Tcsdup(resp->base.batch, errorMessage);
 288                          }
 289                          else
 290                          {
 291                              resp->errorMessage = NULL;
 292                          }
 293              
 294                          resp->result = result;
 295              
 296 krisbash 1.5             resp->base.flags |= self->request->base.flags;
 297                      }
 298                      else /* Binary protocol */
 299                      {
 300                          resp->cimError = cimError;
 301                          if (cimError)
 302                          {
 303                              InstanceToBatch(cimError, NULL, NULL, resp->base.batch, &resp->packedInstancePtr, &resp->packedInstanceSize);
 304                              /* If the serialization fails we should just send the original error back. Seems bad to overrite it with this error */
 305              
 306                              resp->cimErrorClassName = Batch_Tcsdup(resp->base.batch, cimError->classDecl->name);
 307                          }
 308                          else
 309                          {
 310                              resp->packedInstancePtr = NULL;
 311                              resp->packedInstanceSize = 0;
 312                              resp->cimErrorClassName = NULL;
 313                          }
 314                          if (errorMessage)
 315                          {
 316                              resp->errorMessage = Batch_Tcsdup(resp->base.batch, errorMessage);
 317 krisbash 1.5             }
 318                          else
 319                          {
 320                              resp->errorMessage = NULL;
 321                          }
 322                          resp->result = result;
 323                          resp->base.flags |= BinaryProtocolFlag;
 324                      }
 325              
 326                      Context_PostMessageLeft( self, &resp->base);
 327 mike     1.1         PostResultMsg_Release(resp);
 328                  }
 329              
 330                  if (self->result)
 331                      *self->result = result;
 332              
 333 krisbash 1.5     /* close/destroy context */
 334                  Context_Close(self);
 335 mike     1.1 
 336                  return MI_RESULT_OK;
 337              }
 338              
 339 krisbash 1.5 static MI_Boolean _FilterProperty(const ZChar* name, void *data)
 340 mike     1.1 {
 341                  WQL* wql = (WQL*)data;
 342              
 343                  if (WQL_ContainsProperty(wql, name))
 344                      return MI_FALSE;
 345                  else
 346                      return MI_TRUE;
 347              }
 348              
 349 krisbash 1.5 /*
 350               * This is an internal helper function that should be called from wrappers
 351               * that manage the lifecycle of the instance getting posted.
 352               */
 353              static MI_Result _PostInstanceToCallback_Common(
 354                  _In_ Context* self,
 355                  _In_ const MI_Instance* instance,
 356                  _In_ PostInstanceMsg* resp)
 357 mike     1.1 {
 358 krisbash 1.5     MI_Result r = MI_RESULT_OK;
 359 mike     1.1 
 360 krisbash 1.5     if (self->request->base.flags & WSMANFlag)
 361 mike     1.1     {
 362                      const MI_ClassDecl* castToClassDecl = 0;
 363              
 364                      /* Enumerate response with 'base-properties-only' option 
 365                          may require instance conversion */
 366 krisbash 1.5         if (EnumerateInstancesReqTag == self->request->base.tag)
 367 mike     1.1         {
 368                          EnumerateInstancesReq* req = (EnumerateInstancesReq*)self->request;
 369              
 370                          if (req->requestClassName)
 371                          {
 372                              castToClassDecl = instance->classDecl;
 373              
 374                              while (castToClassDecl && 
 375 krisbash 1.5                     Tcscasecmp(req->requestClassName, castToClassDecl->name) != 0)
 376 mike     1.1                 {
 377                                  castToClassDecl = castToClassDecl->superClassDecl;
 378                              }
 379                          }
 380                      }
 381              
 382                      {
 383                          EnumerateInstancesReq* req = NULL;
 384              
 385 krisbash 1.5             if (EnumerateInstancesReqTag == self->request->base.tag)
 386 mike     1.1                 req = (EnumerateInstancesReq*)self->request;
 387              
 388                          if (req && req->wql)
 389                          {
 390 krisbash 1.5                 r = WSBuf_InstanceToBuf(
 391                                  self->request->userAgent,
 392 mike     1.1                     instance,
 393                                  _FilterProperty,
 394                                  req->wql,
 395                                  castToClassDecl,
 396                                  resp->base.batch, 
 397 krisbash 1.5                     self->request->base.flags,
 398 mike     1.1                     &resp->packedInstancePtr, 
 399                                  &resp->packedInstanceSize);
 400                          }
 401                          else
 402                          {
 403 krisbash 1.5                 r = WSBuf_InstanceToBuf(
 404                                  self->request->userAgent,
 405 mike     1.1                     instance,
 406                                  NULL, /* filterProperty */
 407                                  NULL, /* filterPropertyData */
 408                                  castToClassDecl,
 409                                  resp->base.batch, 
 410 krisbash 1.5                     self->request->base.flags,
 411 mike     1.1                     &resp->packedInstancePtr, 
 412                                  &resp->packedInstanceSize);
 413                          }
 414                      }
 415              
 416 krisbash 1.5         resp->base.flags |= self->request->base.flags;
 417 mike     1.1     }
 418                  else
 419                  {
 420                      EnumerateInstancesReq* req = NULL;
 421              
 422 krisbash 1.5         if (EnumerateInstancesReqTag == self->request->base.tag)
 423 mike     1.1             req = (EnumerateInstancesReq*)self->request;
 424              
 425                      if (req && req->wql)
 426                      {
 427 krisbash 1.5             r = InstanceToBatch(
 428                              instance, 
 429                              _FilterProperty, 
 430                              req->wql, 
 431                              resp->base.batch, 
 432                              &resp->packedInstancePtr, 
 433                              &resp->packedInstanceSize);           
 434 mike     1.1         }
 435                      else
 436                      {
 437 krisbash 1.5             r = InstanceToBatch(
 438                              instance, 
 439                              NULL, 
 440                              NULL, 
 441                              resp->base.batch, 
 442                              &resp->packedInstancePtr, 
 443                              &resp->packedInstanceSize);
 444 mike     1.1         }
 445              
 446                      resp->base.flags |= BinaryProtocolFlag;
 447                  }
 448              
 449              
 450 krisbash 1.5     if (r != MI_RESULT_OK)
 451                      trace_PackInstanceFailed(r);
 452                  else
 453                      Context_PostMessageLeft( self, &resp->base);
 454              
 455                  return r;
 456              }
 457              
 458              static MI_Result _PostInstanceToCallback(
 459                  _In_ Context* self,
 460                  _In_ const MI_Instance* instance)
 461              {
 462                  MI_Result result = MI_RESULT_OK;
 463                  PostInstanceMsg* resp = PostInstanceMsg_New(self->request->base.operationId);
 464              
 465                  if (!resp)
 466                      return MI_RESULT_FAILED;
 467              
 468                  result = _PostInstanceToCallback_Common( self, instance, resp );
 469 mike     1.1 
 470                  PostInstanceMsg_Release(resp);
 471              
 472 krisbash 1.5     return result;
 473 mike     1.1 }
 474              
 475              /* successfully received instance from 'gi' - call invoke with this instance now */
 476              static void _CallInvoke(
 477                  Context* self,
 478                  const MI_Instance* instance)
 479              {
 480 krisbash 1.5     Context* ctx = (Context*)Batch_GetClear(self->request->base.batch, sizeof(Context));;
 481 mike     1.1 
 482 krisbash 1.5     // This is an internal context so it doesn't need an interaction 
 483                  Context_Init(ctx, self->provider, NULL);
 484 mike     1.1 
 485                  ctx->request = self->request;
 486                  /* message will be freed in context release*/
 487 krisbash 1.5     Message_AddRef(&ctx->request->base);
 488 mike     1.1 
 489                  /* disregard all other messages for this context */
 490                  self->cancelled = MI_TRUE;
 491                  /* ATTN! clone instance, since invoke can overlive instance (if it's async)!!! */
 492 krisbash 1.5     (*self->md->function)(self->prov_self, &ctx->base,
 493 mike     1.1         __nameSpace, __className, __methodName, instance, self->instParams);
 494              }
 495              
 496              static MI_Result MI_CALL _PostResult(
 497                  MI_Context* self_,
 498                  MI_Result result)
 499              {
 500 krisbash 1.5     Context* self = (Context*)self_;
 501 mike     1.1 
 502 krisbash 1.5     /* Suppress MI_RESULT_NOT_SUPPORTED errors for operations which involve
 503                   * multiple provdiders. For example, suppose the operation is handled by
 504                   * providers A, B, and C. If providers A and B post MI_RESULT_OK but
 505                   * provider C posts MI_RESULT_NOT_SUPPORTED, we must translate this error
 506                   * to a MI_RESULT_OK to prevent the client from receiving it. The client
 507                   * is only concerned with receiving valid instances, not with whether a
 508                   * particular provider implements the operation.
 509                   */
 510                  if (result == MI_RESULT_NOT_SUPPORTED)
 511                  {
 512                      switch (self->request->base.tag)
 513                      {
 514                          case AssociatorsOfReqTag:
 515                          case ReferencesOfReqTag:
 516                              result = MI_RESULT_OK;
 517                              break;
 518                          default:
 519                              break;
 520                      }
 521                  }
 522 mike     1.1 
 523 krisbash 1.5     if (result == MI_RESULT_OK)
 524                      return _ProcessResult(self_, result, NULL, NULL);
 525                  else
 526                      return _PostError(self_, result, MI_RESULT_TYPE_MI, NULL);
 527 mike     1.1 }
 528              
 529              static MI_Result MI_CALL _PostInstance(
 530                  MI_Context* self_,
 531                  const MI_Instance* instance)
 532              {
 533                  Context* self = (Context*)self_;
 534              
 535                  if (!self || self->magic != _MAGIC || !instance)
 536                      return MI_RESULT_INVALID_PARAMETER;
 537              
 538                  if (self->request && !self->cancelled)
 539                  {
 540                      if (self->instanceName == NULL)
 541                      {
 542 krisbash 1.5             if (!Instance_ValidateNonNullKeys(instance))
 543                          {
 544                              /* Fail the Post if it has NULL key properties.  It is an
 545                               * invalid object. */
 546                              return MI_RESULT_FAILED;
 547                          }
 548                          
 549                          if (CTX_TYPE_INVOKE_WITH_INSTANCE == self->ctxType)
 550 mike     1.1             {
 551                              _CallInvoke(self, instance);
 552                              return MI_RESULT_OK;
 553                          }
 554 krisbash 1.5             else if (EnumerateInstancesReqTag == self->request->base.tag)
 555 mike     1.1             {
 556                              EnumerateInstancesReq* req = 
 557                                  (EnumerateInstancesReq*)self->request;
 558              
 559                              if (req->wql)
 560                              {
 561                                  int r;
 562              
 563                                  r = WQL_Eval(req->wql, WQL_LookupInstanceProperty, 
 564                                      (void*)instance);
 565              
 566                                  if (r == 0)
 567                                  {
 568                                      /* Instance matched the query */
 569                                      return _PostInstanceToCallback(self, instance);
 570                                  }
 571                                  else
 572                                  {
 573                                      /* Mismatch or failure */
 574                                      return MI_RESULT_OK;
 575                                  }
 576 mike     1.1                 }
 577                          }
 578 krisbash 1.5             else if (ModifyInstanceReqTag == self->request->base.tag)
 579                          {
 580                              self->postedModifyInstance = MI_TRUE;
 581                              return _PostInstanceToCallback(self, instance);
 582                          }
 583 mike     1.1 
 584                          return _PostInstanceToCallback(self, instance);
 585                      }
 586                      else if (Instance_MatchKeys(instance, self->instanceName))
 587                      {
 588                          /* Handle GetInstance through EnumerateInstances */
 589                          if (!self->matchedInstanceName)
 590                          {
 591                              self->matchedInstanceName = MI_TRUE;
 592                              return _PostInstanceToCallback(self, instance);
 593                          }
 594                      }
 595                  }
 596              
 597                  return MI_RESULT_OK;
 598              }
 599              
 600 krisbash 1.5 static Batch* _GetBatch(Context* self)
 601              {
 602                  if (self->provider && self->provider->lib && self->provider->lib->instanceLifetimeContext)
 603                  {
 604                      if (self->request)
 605                          return self->request->base.batch;
 606              
 607                      if (self->loadRequest)
 608                          return self->loadRequest->batch;
 609                  }
 610              
 611                  return NULL;
 612              }
 613              
 614 mike     1.1 static MI_Result MI_CALL _ConstructInstance(
 615                  MI_Context* self_,
 616                  const MI_ClassDecl* classDecl,
 617                  MI_Instance* instance)
 618              {
 619 krisbash 1.5     Batch *batch = NULL;
 620 mike     1.1     Context* self = (Context*)self_;
 621              
 622                  if (!self || self->magic != _MAGIC || !instance || !classDecl)
 623                      return MI_RESULT_INVALID_PARAMETER;
 624              
 625 krisbash 1.5     batch = _GetBatch(self);
 626              
 627                  return Instance_Construct(instance, classDecl, batch);
 628 mike     1.1 }
 629              
 630              static MI_Result MI_CALL _ConstructParameters(
 631                  MI_Context* self_,
 632                  const MI_MethodDecl* methodDecl,
 633                  MI_Instance* instance)
 634              {
 635 krisbash 1.5     Batch *batch = NULL;
 636 mike     1.1     Context* self = (Context*)self_;
 637              
 638                  if (!self || self->magic != _MAGIC || !instance || !methodDecl)
 639                      return MI_RESULT_INVALID_PARAMETER;
 640              
 641 krisbash 1.5     batch = _GetBatch(self);
 642              
 643                  return Parameters_Init(instance, methodDecl, batch);
 644 mike     1.1 }
 645              
 646              static MI_Result MI_CALL _NewInstance(
 647                  MI_Context* self_,
 648                  const MI_ClassDecl* classDecl,
 649                  MI_Instance** instance)
 650              {
 651 krisbash 1.5     Batch *batch = NULL;
 652 mike     1.1     Context* self = (Context*)self_;
 653              
 654                  if (!self || self->magic != _MAGIC || !classDecl || !instance)
 655                      return MI_RESULT_INVALID_PARAMETER;
 656              
 657 krisbash 1.5     batch = _GetBatch(self);
 658              
 659                  return Instance_New(instance, classDecl, batch);
 660 mike     1.1 }
 661              
 662              static MI_Result MI_CALL _NewDynamicInstance(
 663                  MI_Context* self_,
 664 krisbash 1.5     const ZChar* className,
 665 mike     1.1     MI_Uint32 flags,
 666                  MI_Instance** instance)
 667              {
 668 krisbash 1.5     Batch *batch = NULL;
 669 mike     1.1     Context* self = (Context*)self_;
 670              
 671                  if (!self || self->magic != _MAGIC || !className || !instance)
 672                      return MI_RESULT_INVALID_PARAMETER;
 673              
 674 krisbash 1.5     batch = _GetBatch(self);
 675              
 676 mike     1.1     return Instance_NewDynamic(instance, className, flags, 
 677 krisbash 1.5         batch);
 678 mike     1.1 }
 679              
 680              static MI_Result MI_CALL _NewParameters(
 681                  MI_Context* self_,
 682                  const MI_MethodDecl* methodDecl,
 683                  MI_Instance** instance)
 684              {
 685 krisbash 1.5     Batch *batch = NULL;
 686 mike     1.1     Context* self = (Context*)self_;
 687              
 688                  if (!self || self->magic != _MAGIC || !methodDecl || !instance)
 689                      return MI_RESULT_INVALID_PARAMETER;
 690              
 691 krisbash 1.5     batch = _GetBatch(self);
 692              
 693                  return Parameters_New(instance, methodDecl, batch);
 694 mike     1.1 }
 695              
 696              static MI_Result MI_CALL _Canceled(
 697                  const MI_Context* self_,
 698                  MI_Boolean* flag)
 699              {
 700                  Context* self = (Context*)self_;
 701              
 702                  if (!self || self->magic != _MAGIC || !flag)
 703                      return MI_RESULT_INVALID_PARAMETER;
 704              
 705                  *flag = self->cancelled;
 706                  return MI_RESULT_OK;
 707              }
 708              
 709 krisbash 1.5 #ifndef DISABLE_INDICATION
 710              
 711              static MI_Result _PostIndicationToCallback(
 712                  _In_ Context* self,
 713                  _In_ const MI_Instance* instance,
 714                  _In_opt_z_ const ZChar* bookmark )
 715 mike     1.1 {
 716 krisbash 1.5     MI_Result result = MI_RESULT_OK;
 717                  PostIndicationMsg* resp = PostIndicationMsg_New(self->request->base.operationId);
 718              
 719                  if (!resp)
 720                      return MI_RESULT_FAILED;
 721              
 722                  /* Copy bookmark into the message's Batch to control its lifetime. */
 723                  if (bookmark)
 724                  {
 725                      const ZChar* tmp = Batch_Tcsdup(resp->base.base.batch, bookmark);
 726              
 727                      if (!tmp)
 728                      {
 729                          PostIndicationMsg_Release(resp);
 730                          return MI_RESULT_FAILED;
 731                      }
 732              
 733                      resp->bookmark = tmp;
 734                  }
 735              
 736                  result = _PostInstanceToCallback_Common( self, instance, (PostInstanceMsg*)resp );
 737 mike     1.1 
 738 krisbash 1.5     PostIndicationMsg_Release(resp);
 739 mike     1.1 
 740 krisbash 1.5     return result;
 741 mike     1.1 }
 742              
 743 krisbash 1.5 /*
 744               * PostIndication handler for SubscriptionContext.  It evaluates an indication
 745               * using a pre-specified indication filter.  It is placed here so that
 746               * _PostInstanceToCallback remains private to Context.c.
 747               */
 748              MI_Result _SubscrContext_PostIndication(
 749                  _In_ SubscriptionContext* context,
 750                  _In_ const MI_Instance* indication,
 751                  _In_opt_z_ const ZChar* bookmark,
 752                  _In_ MI_Boolean subscriptionRefcounted)
 753              {
 754                  MI_Result result = MI_RESULT_OK;
 755                  SubMgrSubscription* subscription = NULL;
 756                  MI_Boolean isMatch = MI_FALSE;
 757                  SubscriptionManager* subMgr;
 758 mike     1.1 
 759 krisbash 1.5     if (!context || !indication)
 760                  {
 761                      trace_PostIndicationWithNullInput();
 762 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
 763 krisbash 1.5     }
 764 mike     1.1 
 765 krisbash 1.5     subMgr = context->baseCtx.provider->subMgr;
 766                  DEBUG_ASSERT ( subMgr );
 767              
 768                  if ( MI_FALSE == SubMgr_CanPostIndication( subMgr ) )
 769                      return MI_RESULT_NOT_SUPPORTED;
 770              
 771                  /* Ref counted, release later */
 772                  if ( MI_FALSE == subscriptionRefcounted )
 773                      subscription = SubMgr_GetSubscriptionByContext(subMgr, context);
 774                  else
 775                      subscription = context->subscription;
 776              
 777                  if ( !subscription )
 778                  {
 779                      return MI_RESULT_FAILED;
 780                  }
 781              
 782                  if (SubscriptionState_Unsubscribing == subscription->state ||
 783                      SubscriptionState_Unsubscribed == subscription->state)
 784                  {
 785                      trace_PostIndicationWithUnsubscribedContext();
 786 krisbash 1.5         if ( MI_FALSE == subscriptionRefcounted)
 787                          SubMgrSubscription_Release(subscription);
 788                      return MI_RESULT_OK;
 789                  }
 790              
 791                  if (!Instance_ValidateNonNullKeys(indication))
 792                  {
 793                      /* Fail the Post if it has NULL key properties.  It is an
 794                       * invalid object. */
 795                      if ( MI_FALSE == subscriptionRefcounted)
 796                          SubMgrSubscription_Release(subscription);
 797                      return MI_RESULT_FAILED;
 798                  }
 799              
 800                  result = InstanceFilter_Filter( subscription->filter, indication, &isMatch );
 801              
 802                  /* Check the evaluation status.  Only forward indications that satisfied
 803                   * a known filter. */
 804                  if (MI_RESULT_OK == result && isMatch)
 805                  {
 806                      SubMgrSubscription_AcuquirePostLock(subscription);
 807 krisbash 1.5         if ( MI_FALSE == SubMgrSubscription_CancelStarted(subscription) )
 808                          result = _PostIndicationToCallback((Context*)context, indication, bookmark);
 809                      else
 810                          result = MI_RESULT_FAILED;
 811                      SubMgrSubscription_ReleasePostLock(subscription);
 812                  }
 813              
 814                  if ( MI_FALSE == subscriptionRefcounted)
 815                      SubMgrSubscription_Release(subscription);
 816              
 817                  return result;
 818 mike     1.1 }
 819              
 820 krisbash 1.5 MI_Result _SubscrContext_ProcessResult(
 821                  _In_ Context* context,
 822                  _In_ MI_Result result,
 823                  _In_opt_z_ const ZChar* errorMessage,
 824                  _In_opt_ const MI_Instance* cimError )
 825 mike     1.1 {
 826 krisbash 1.5     /* subscription object is guaranteed live here since the provider owning one refcount */
 827                  /* after this call, the refcount will be released */
 828                  SubscriptionContext* subCtx = (SubscriptionContext*)context;
 829                  SubMgrSubscription* subscription = SubscrContext_GetSubscription( subCtx );
 830                  MI_Result r;
 831              
 832                  DEBUG_ASSERT(subscription); /* This identifies any cases that may violate the refcount guarantee */
 833              
 834                  SubMgrSubscription_Addref(subscription);
 835              
 836                  Provider_RemoveSubscription(context->provider, subscription->subscriptionID);
 837              
 838              #if !defined(_MSC_VER)
 839                  {
 840                      ThreadID tempId = Thread_ID();
 841                      if (Thread_Equal(&tempId, &context->provider->lib->provmgr->ioThreadId))
 842                      {
 843                          /* For non-windows platform, there is only one IO thread in current process, */
 844                          /* which has dead lock issue if have multi-thread (include IO thread) posting messages */
 845                          /* simultaneously. To resolve the issue, unsubscribe has to be invoked from a separate thread */
 846                          /* Upon implementing multi-thread IO for OMI server, this workaround should be removed */
 847 krisbash 1.5             Schedule_SendFinalResult( subCtx, result );
 848                          return MI_RESULT_OK;
 849                      }
 850                  }
 851              #endif
 852              
 853                  trace_SubscrContext_ProcessResult(UintThreadID(), subCtx, subscription);
 854              
 855                  /* Handle failure responses */
 856                  if (SubscriptionState_Subscribed == subscription->state ||
 857                      SubscriptionState_Unsubscribing == subscription->state)
 858                  {
 859                      trace_SubscrContext_ProviderPostingFailure(result,
 860                          ((subscription->state == SubscriptionState_Subscribed) ? PAL_T("subscribed") : PAL_T("unsubscribing")),
 861                          subscription);
 862                  }
 863                  else
 864                  {
 865                      trace_SubscrContext_ProcessResult_InvalidState(UintThreadID(), subCtx, subscription, subscription->state);
 866                  }
 867              
 868 krisbash 1.5     SubMgrSubscription_AcuquirePostLock(subscription);
 869                  r = SubscrContext_SendFinalResultMsg( subCtx, result, errorMessage, cimError );
 870                  SubMgrSubscription_ReleasePostLock(subscription);
 871              
 872                  SubMgrSubscription_Release(subscription);
 873                  return r;
 874              }
 875              
 876              /*
 877               * PostIndication handler for AggregationContext.  It forwards an indication
 878               * to all known subscriptions for filter evaluation.  It is placed here so that
 879               * _PostInstanceToCallback remains private to Context.c.
 880               */
 881              MI_Result _AggrContext_PostIndication(
 882                  _In_ AggregationContext* context,
 883                  _In_ const MI_Instance* indication,
 884                  _In_opt_z_ const ZChar* bookmark )
 885              {
 886                  SubscriptionManager* subMgr = NULL;
 887                  MI_Boolean atLeastOneDelivered = MI_FALSE;
 888                  SubMgrSubscriptionPtr* sublist;
 889 krisbash 1.5     MI_Result r;
 890                  size_t count = 0;
 891                  size_t i;
 892 mike     1.1 
 893 krisbash 1.5     if (!context || !indication)
 894                  {
 895                      trace_PostIndicationWithNullInput();
 896 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
 897 krisbash 1.5     }
 898              
 899                  subMgr = AggrContext_GetManager( context );
 900              
 901                  /* Both of these states result in the same thing: the AggregationContext
 902                   * must be cleaned up. */
 903                  if ( (MI_FALSE == SubMgr_IsEnabled ( subMgr )) ||
 904                       (MI_TRUE == SubMgr_IsSubListEmpty ( subMgr )))
 905                  {
 906                      trace_PostIndicationOnDisabledAggContext();
 907                      return MI_RESULT_FAILED;
 908                  }
 909              
 910                  /* sublist holds one reference count to each subscription */
 911                  r = SubMgr_GetSubscriptionList(subMgr, &sublist, &count);
 912                  if ( r != MI_RESULT_OK )
 913                      return r;
 914              
 915                  for ( i = 0; i < count; i++ )
 916                  {
 917                      /* 
 918 krisbash 1.5          * This is a best-effort action
 919                       * Intermediate failures will be ignored
 920                       */
 921                      r = _SubscrContext_PostIndication( sublist[i]->subscribeCtx, indication, bookmark, MI_TRUE );
 922                      if ( MI_RESULT_OK == r )
 923                      {
 924                          atLeastOneDelivered = MI_TRUE;
 925                      }
 926                      /* release the one reference count */
 927                      SubMgrSubscription_Release( sublist[i] );
 928                  }
 929 mike     1.1 
 930 krisbash 1.5     return (atLeastOneDelivered ? MI_RESULT_OK : r);
 931 mike     1.1 }
 932              
 933 krisbash 1.5 /* 
 934               * Handles AggregationContext cleanup during error scenarios derived from 
 935               * PostResult, PostError, and PostCimError calls on the context.
 936               */
 937              MI_Result _AggrContext_Terminate(
 938                  Context* context,
 939                  MI_Result result,
 940                  const ZChar* errorMessage,
 941                  const MI_Instance* cimError )
 942 mike     1.1 {
 943 krisbash 1.5     return Provider_TerminateIndication(context->provider, result, errorMessage, cimError);
 944 mike     1.1 }
 945              
 946 krisbash 1.5 /*
 947               * Delegates AggregationContext Post calls depending on the state of the 
 948               * context.
 949               */
 950              MI_Result _AggrContext_ProcessResult(
 951                  _In_ Context* context,
 952                  _In_ MI_Result result,
 953                  const ZChar* errorMessage,
 954                  const MI_Instance* cimError )
 955 mike     1.1 {
 956 krisbash 1.5     return _AggrContext_Terminate( context, result, errorMessage, cimError );
 957 mike     1.1 }
 958              
 959 krisbash 1.5 static MI_Result _Ind_Common_ProcessResult(
 960                  _In_ MI_Context* context,
 961                  _In_ MI_Result result,
 962                  const ZChar* errorMessage,
 963                  const MI_Instance* cimError )
 964              {
 965                  Context* self = (Context*)context;
 966                  MI_Result toReturn = MI_RESULT_OK;
 967                  
 968                  if (!self || self->magic != _MAGIC)
 969                  {
 970                      trace_PostCalledWithInvalidContext();
 971                      return MI_RESULT_INVALID_PARAMETER;
 972                  }
 973              
 974                  if (!self->cancelled)
 975                  {
 976                      /* Engages filter handlers to determine if the indication instance is
 977                       * appropriate for forwarding to clients. */
 978                      switch (self->ctxType)
 979                      {
 980 krisbash 1.5             case CTX_TYPE_IND_AGGREGATION:
 981                              toReturn = _AggrContext_ProcessResult( self, result, errorMessage, cimError );
 982                              break;
 983                          case CTX_TYPE_IND_SUBSCRIPTION:
 984                          case CTX_TYPE_IND_LIFECYCLE:    /* Fallthrough expected */
 985                              toReturn = _SubscrContext_ProcessResult( self, result, errorMessage, cimError );
 986                              break;
 987                          default:
 988                              trace_UnknownIndicationContextType((int)self->ctxType);
 989                              toReturn = MI_RESULT_NOT_FOUND;
 990                              break;
 991                      }
 992                  }
 993                  /* else: invalid indication post, so do nothing */
 994                  
 995                  return toReturn;
 996              }
 997              
 998              /* TODO: attach bookmark to PostIndicationMsg */
 999              static MI_Result MI_CALL _Ind_PostIndication(
1000                  MI_Context* context,
1001 krisbash 1.5     const MI_Instance* indication,
1002                  MI_Uint32 subscriptionIDCount,
1003                  const ZChar* bookmark)
1004              {
1005                  MI_Result result = MI_RESULT_OK;    
1006                  Context* self = (Context*)context;
1007                  MI_UNUSED(subscriptionIDCount);
1008              
1009                  if (!self || self->magic != _MAGIC || !indication)
1010                  {
1011                      trace_PostCalledWithInvalidContext();
1012                      return MI_RESULT_INVALID_PARAMETER;
1013                  }
1014              
1015                  if (!self->cancelled)
1016                  {
1017                      /* Engages filter handlers to determine if the indication instance is
1018                       * appropriate for forwarding to clients. */
1019                      switch (self->ctxType)
1020                      {
1021                          case CTX_TYPE_IND_AGGREGATION:
1022 krisbash 1.5                 result = _AggrContext_PostIndication( (AggregationContext*)self, indication, bookmark );
1023                              break;
1024                          case CTX_TYPE_IND_SUBSCRIPTION: /* Fallthrough expected */
1025                          case CTX_TYPE_IND_LIFECYCLE:
1026                              result = _SubscrContext_PostIndication( (SubscriptionContext*)self, indication, bookmark, MI_FALSE );
1027                              break;
1028                          default:
1029                              trace_UnknownIndicationContextType((int)self->ctxType);
1030                              result = MI_RESULT_NOT_FOUND;
1031                              break;
1032                      }
1033                  }
1034                  /* else: invalid indication post, so do nothing */
1035                  
1036                  return result;
1037              }
1038              
1039              /* 
1040               *_PostInstance is not supported for indication contexts.  Indications
1041               * must be posted using _PostIndication. 
1042               */
1043 krisbash 1.5 static MI_Result MI_CALL _Ind_PostInstance(
1044                  MI_Context* self_,
1045                  const MI_Instance* instance)
1046              {
1047                  Context* self = (Context*)self_;
1048              
1049                  if (!self || self->magic != _MAGIC || !instance)
1050                  {
1051                      return MI_RESULT_INVALID_PARAMETER;
1052                  }
1053                  return MI_RESULT_NOT_SUPPORTED;
1054               }
1055              
1056              static MI_Result MI_CALL _Ind_PostResult(
1057                  MI_Context* self_,
1058                  MI_Result result)
1059              {
1060                  return _Ind_Common_ProcessResult( self_, result, NULL, NULL );
1061              }
1062              
1063              static MI_Result MI_CALL _Ind_PostError(
1064 krisbash 1.5     _In_ MI_Context* self,
1065                  MI_Uint32 result,
1066                  _In_z_ const ZChar* type,
1067                  _In_z_ const ZChar* message)
1068              {
1069                  if (NULL == type ||
1070                      Tcscmp(type, MI_RESULT_TYPE_MI) != 0)
1071                  {
1072                      result = MI_RESULT_FAILED;
1073                  }
1074                  return _Ind_Common_ProcessResult(self, result, message, NULL);
1075              }
1076              
1077              static MI_Result MI_CALL _Ind_PostCimError(
1078                  _In_ MI_Context* self,
1079                  _In_ const MI_Instance *error)
1080              {
1081                  MI_Value value;
1082                  MI_Type type;
1083                  MI_Result result;
1084                  
1085 krisbash 1.5     result = MI_Instance_GetElement(error, MI_T("CIMStatusCode"), &value, &type, NULL, NULL);
1086                  if ((MI_RESULT_OK != result) || (MI_UINT32 != type))
1087                  {
1088                      return _Ind_Common_ProcessResult(self, MI_RESULT_INVALID_CLASS_HIERARCHY, MI_T("Invalid CIM_Error object posted from provider"), NULL);
1089                  }
1090                  else
1091                  {
1092                      MI_Value messageValue;
1093                      MI_Type messageType;
1094              
1095                      result = MI_Instance_GetElement(error, MI_T("Message"), &messageValue, &messageType, NULL, NULL);
1096                      if ((MI_RESULT_OK != result) || (MI_STRING != messageType))
1097                      {
1098                          messageValue.string = NULL;
1099                      }
1100                      return _Ind_Common_ProcessResult(self, value.uint32, messageValue.string, error);
1101                  }
1102              }
1103              
1104              #endif /* ifndef DISABLE_INDICATION */
1105              
1106 krisbash 1.5 static MI_Result MI_CALL _PostIndication(
1107                  MI_Context* context,
1108                  const MI_Instance* indication,
1109                  MI_Uint32 subscriptionIDCount,
1110                  const ZChar* bookmark)
1111              {
1112                  MI_UNUSED(context);
1113                  MI_UNUSED(indication);
1114                  MI_UNUSED(subscriptionIDCount);
1115                  MI_UNUSED(bookmark);
1116              
1117                  return MI_RESULT_NOT_SUPPORTED;
1118              }
1119              
1120              static MI_Result MI_CALL _GetLocale(
1121                  const MI_Context* context,
1122                  MI_LocaleType localeType,
1123                  _Pre_writable_size_(MI_MAX_LOCALE_SIZE) ZChar locale[MI_MAX_LOCALE_SIZE])
1124              {
1125                  return MI_RESULT_NOT_SUPPORTED;
1126              }
1127 krisbash 1.5 
1128              static MI_Result MI_CALL _RegisterCancel(
1129                  MI_Context* context,
1130                  MI_CancelCallback callback,
1131                  void* callbackData)
1132              {
1133                  return MI_RESULT_NOT_SUPPORTED;
1134              }
1135              
1136              static MI_Result MI_CALL _RequestUnload(
1137                  MI_Context* self_)
1138              {
1139                  Context* self = (Context*)self_;
1140              
1141                  if (!self || self->magic != _MAGIC || !self->provider)
1142                      return MI_RESULT_INVALID_PARAMETER;
1143              
1144                  Provider_SetRefuseUnloadFlag(self->provider, MI_FALSE);
1145                  return MI_RESULT_OK;
1146              }
1147              
1148 krisbash 1.5 static MI_Result MI_CALL _RefuseUnload(
1149                  MI_Context* self_)
1150              {
1151                  Context* self = (Context*)self_;
1152              
1153                  if (!self || self->magic != _MAGIC || !self->provider)
1154                      return MI_RESULT_INVALID_PARAMETER;
1155              
1156                  Provider_SetRefuseUnloadFlag(self->provider, MI_TRUE);
1157                  return MI_RESULT_OK;
1158              }
1159              
1160              static MI_Result MI_CALL _GetLocalSession(
1161                  _In_ const MI_Context* self_,
1162                  _Out_ MI_Session* session)
1163 mike     1.1 {
1164 krisbash 1.5 #if defined(DISABLE_LOCALSESSION)
1165                  MI_UNREFERENCED_PARAMETER(self_);
1166                  MI_UNREFERENCED_PARAMETER(session);
1167              
1168 mike     1.1     return MI_RESULT_NOT_SUPPORTED;
1169 krisbash 1.5 #else
1170                  Context* self = (Context*)self_;
1171              
1172                  if (!self || self->magic != _MAGIC || !self->provider || !self->provider->lib || !self->provider->lib->provmgr)
1173                      return MI_RESULT_INVALID_PARAMETER;
1174              
1175                  return ProvMgr_GetLocalSesson(self->provider->lib->provmgr, session);
1176              #endif /* defined(DISABLE_LOCALSESSION) */
1177 mike     1.1 }
1178              
1179 krisbash 1.5 static MI_Result MI_CALL _SetStringOption(
1180                  _In_ MI_Context* context,
1181                  _In_z_ const ZChar* name,
1182                  _In_z_ const ZChar* value)
1183 mike     1.1 {
1184                  return MI_RESULT_NOT_SUPPORTED;
1185 krisbash 1.5 }
1186 mike     1.1 
1187 krisbash 1.5 static MI_Result MI_CALL _GetCustomOption(
1188                  _In_  MI_Context* context_,
1189                  _In_z_ const ZChar* name,
1190 mike     1.1     _Out_opt_  MI_Type* valueType,
1191                  _Out_opt_  MI_Value* value)
1192              {
1193 krisbash 1.5     Context* context = (Context*)context_;
1194              
1195                  /* Check parameters */
1196                  if (!context || !context->request)
1197                      return MI_RESULT_INVALID_PARAMETER;
1198              
1199                  /* Return zero if no option object */
1200                  if (!context->request->options)
1201                      return MI_RESULT_NO_SUCH_PROPERTY;
1202              
1203                  return __MI_Instance_GetElement(
1204                      context->request->options,
1205                      name,
1206                      value,
1207                      valueType,
1208                      NULL,
1209                      NULL);
1210 mike     1.1 }
1211              
1212 krisbash 1.5 static MI_Result MI_CALL _GetCustomOptionCount(
1213                  _In_  MI_Context* context_,
1214 mike     1.1     _Out_opt_ MI_Uint32* count)
1215              {
1216 krisbash 1.5     Context* context = (Context*)context_;
1217              
1218                  /* Check parameters */
1219                  if (!context || !context->request)
1220                      return MI_RESULT_INVALID_PARAMETER;
1221              
1222                  /* Return zero if no option object */
1223                  if (!context->request->options)
1224                  {
1225                      if (count)
1226                          *count = 0;
1227                      return MI_RESULT_OK;
1228                  }
1229              
1230                  return __MI_Instance_GetElementCount(context->request->options, count);
1231 mike     1.1 }
1232              
1233 krisbash 1.5 static MI_Result MI_CALL _GetCustomOptionAt(
1234                  _In_  MI_Context* context_,
1235 mike     1.1     _In_ MI_Uint32 index,
1236 krisbash 1.5     _Outptr_opt_result_maybenull_z_  const ZChar** name,
1237 mike     1.1     _Out_opt_  MI_Type* valueType,
1238                  _Out_opt_  MI_Value* value)
1239              {
1240 krisbash 1.5     Context* context = (Context*)context_;
1241              
1242                  /* Check parameters */
1243                  if (!context || !context->request)
1244                      return MI_RESULT_INVALID_PARAMETER;
1245              
1246                  if (!context->request->options)
1247                      return MI_RESULT_FAILED;
1248              
1249                  return __MI_Instance_GetElementAt(
1250                      context->request->options,
1251                      index,
1252                      name,
1253                      value,
1254                      valueType,
1255                      0);
1256              }
1257              
1258              static MI_Result MI_CALL _GetStringOption(
1259                  _In_  MI_Context* context,
1260                  _In_z_ const ZChar* name,
1261 krisbash 1.5     _Outptr_result_z_  const ZChar** valueOut)
1262              {
1263                  MI_Type type;
1264                  MI_Value value;
1265                  MI_Result r;
1266                  
1267                  r = _GetCustomOption(
1268                      context,
1269                      name,
1270                      &type,
1271                      &value);
1272              
1273                  if (r != MI_RESULT_OK)
1274                      return r;
1275              
1276                  if (type != MI_STRING)
1277                      return MI_RESULT_NO_SUCH_PROPERTY;
1278              
1279                  if (valueOut)
1280                      *valueOut = value.string;
1281              
1282 krisbash 1.5     return MI_RESULT_OK;
1283              }
1284              
1285              static MI_Result MI_CALL _GetNumberOption(
1286                  _In_  MI_Context* context,
1287                  _In_z_ const ZChar *name,
1288                  _Out_opt_  MI_Uint32* valueOut)
1289              {
1290                  MI_Type type;
1291                  MI_Value value;
1292                  MI_Result r;
1293                  
1294                  r = _GetCustomOption(
1295                      context,
1296                      name,
1297                      &type,
1298                      &value);
1299              
1300                  if (r != MI_RESULT_OK)
1301                      return r;
1302              
1303 krisbash 1.5     if (type != MI_UINT32)
1304                      return MI_RESULT_NO_SUCH_PROPERTY;
1305              
1306                  if (valueOut)
1307                      *valueOut = value.uint32;
1308              
1309                  return MI_RESULT_OK;
1310              }
1311 mike     1.1 
1312 krisbash 1.5 static MI_Result MI_CALL _WriteMessage(
1313 mike     1.1     _In_ MI_Context* context,
1314                  MI_Uint32 channel,
1315 krisbash 1.5     _In_z_ const ZChar* message)
1316 mike     1.1 {
1317                  return MI_RESULT_NOT_SUPPORTED;
1318              }
1319              
1320 krisbash 1.5 static MI_Result MI_CALL _WriteProgress(
1321 mike     1.1     _In_ MI_Context* context,
1322 krisbash 1.5     _In_z_ const ZChar* activity,
1323                  _In_z_ const ZChar* currentOperation,
1324                  _In_z_ const ZChar* statusDescription,
1325 mike     1.1     MI_Uint32 percentComplete,
1326                  MI_Uint32 secondsRemaining)
1327              {
1328                  return MI_RESULT_NOT_SUPPORTED;
1329              }
1330              
1331 krisbash 1.5 static MI_Result MI_CALL _WriteStreamParameter(
1332 mike     1.1     _In_ MI_Context* context,
1333 krisbash 1.5     _In_z_ const ZChar* name,
1334 mike     1.1     _In_ const MI_Value* value,
1335                  _In_ MI_Type type,
1336                  _In_ MI_Uint32 flags)
1337              {
1338                  return MI_RESULT_NOT_SUPPORTED;
1339              }
1340              
1341 krisbash 1.5 static MI_Result MI_CALL _WriteCimError(
1342 mike     1.1     _In_ MI_Context* context,
1343                  _In_ const MI_Instance *error,
1344                  _Out_ MI_Boolean *flag)
1345              {
1346                  return MI_RESULT_NOT_SUPPORTED;
1347              }     
1348              
1349 krisbash 1.5 static MI_Result MI_CALL _PromptUser(
1350 mike     1.1     _In_ MI_Context* context,
1351 krisbash 1.5     _In_z_ const ZChar* message, 
1352 mike     1.1     MI_PromptType promptType,
1353                  _Out_ MI_Boolean* result)
1354              {
1355                  return MI_RESULT_NOT_SUPPORTED;
1356              }    
1357              
1358 krisbash 1.5 static MI_Result MI_CALL _ShouldProcess(
1359 mike     1.1     _In_ MI_Context* context,
1360 krisbash 1.5     _In_z_ const ZChar* target,
1361                  _In_z_ const ZChar* action,
1362 mike     1.1     _Out_ MI_Boolean* result)
1363              {
1364                  return MI_RESULT_NOT_SUPPORTED;
1365              }
1366              
1367 krisbash 1.5 static MI_Result MI_CALL _ShouldContinue(
1368 mike     1.1     _In_ MI_Context* context,
1369 krisbash 1.5     _In_z_ const ZChar* message,
1370 mike     1.1     _Out_ MI_Boolean* result)
1371              {
1372                  return MI_RESULT_NOT_SUPPORTED;
1373              } 
1374              
1375 krisbash 1.5 static MI_Result MI_CALL _PostError(
1376                  _In_ MI_Context* self,
1377                  MI_Uint32 result,
1378                  _In_z_ const ZChar* type,
1379                  _In_z_ const ZChar* message)
1380 mike     1.1 {
1381 krisbash 1.5     OMI_Error *omiError = NULL;
1382                  MI_Result returnVal;
1383              
1384                  if (NULL == type)
1385                  {
1386                      /* Don't know the error type so just use failed */
1387                      type = MI_RESULT_TYPE_MI;
1388                      result = MI_RESULT_FAILED;
1389                  }
1390                  returnVal = OMI_ErrorFromErrorCode(NULL, result, type, message, &omiError);
1391                  if (returnVal == MI_RESULT_INVALID_PARAMETER)
1392                  {
1393                      /* invalid error type */
1394                      type = MI_RESULT_TYPE_MI;
1395                      result = MI_RESULT_FAILED;
1396                  }
1397                  if (returnVal != MI_RESULT_FAILED)
1398                  {
1399                      /* We ignore this error as we need to fail the operation */
1400                      returnVal = _ProcessResult(self, result, message, (MI_Instance*)omiError);
1401                  }
1402 krisbash 1.5     else
1403                  {
1404                      if (message == NULL)
1405                      {
1406                          MI_Value messageValue;
1407                          MI_Type messageType;
1408              
1409                          returnVal = MI_Instance_GetElement(&omiError->__instance, MI_T("Message"), &messageValue, &messageType, NULL, NULL);
1410                          if ((MI_RESULT_OK == returnVal) && (MI_STRING == messageType))
1411                          {
1412                              message = messageValue.string;
1413                          }
1414                      }
1415                      returnVal = _ProcessResult(self, result, message, &omiError->__instance);
1416                  }
1417              
1418                  if ( omiError )
1419                      MI_Instance_Delete(&omiError->__instance);
1420              
1421                  return returnVal;
1422 mike     1.1 }
1423              
1424 krisbash 1.5 static MI_Result MI_CALL _PostCimError(
1425                  _In_ MI_Context* self,
1426 mike     1.1     _In_ const MI_Instance *error)
1427              {
1428 krisbash 1.5     MI_Value value;
1429                  MI_Type type;
1430                  MI_Result result;
1431                  
1432                  result = MI_Instance_GetElement(error, MI_T("CIMStatusCode"), &value, &type, NULL, NULL);
1433                  if ((MI_RESULT_OK != result) || (MI_UINT32 != type))
1434                  {
1435                      return _ProcessResult(self, MI_RESULT_INVALID_CLASS_HIERARCHY, MI_T("Invalid CIM_Error object posted from provider"), NULL);
1436                  }
1437                  else
1438                  {
1439                      MI_Value messageValue;
1440                      MI_Type messageType;
1441              
1442                      result = MI_Instance_GetElement(error, MI_T("Message"), &messageValue, &messageType, NULL, NULL);
1443                      if ((MI_RESULT_OK != result) || (MI_STRING != messageType))
1444                      {
1445                          messageValue.string = NULL;
1446                      }
1447                      return _ProcessResult(self, value.uint32, messageValue.string, error);
1448                  }
1449 mike     1.1 }  
1450              
1451 krisbash 1.5 static MI_Result MI_CALL _WriteError(
1452 mike     1.1     _In_ MI_Context* context,
1453                  MI_Uint32 resultCode,
1454 krisbash 1.5     _In_z_ const ZChar* resultType,
1455                  _In_z_ const ZChar* errorMessage,
1456 mike     1.1     _Out_ MI_Boolean *flag)
1457              {
1458                  return MI_RESULT_NOT_SUPPORTED;
1459              }
1460              
1461 krisbash 1.5 static MI_Result _GetLifecycleIndicationContext_NotSupported(
1462                  _In_ const MI_Context* context,
1463                  _Outptr_ MI_LifecycleIndicationContext** lifecycleContext)
1464              {
1465                  MI_UNREFERENCED_PARAMETER(context);
1466                  *lifecycleContext = NULL;
1467                  return MI_RESULT_NOT_SUPPORTED;
1468              }
1469              
1470              /*
1471               * Initializes lifecycle indication handling for a provider and populates the
1472               * lifecycleContext ptr if everything goes well.  Returns existing 
1473               * LifecycleContext if it has already been initialized.
1474               */
1475              static MI_Result _GetLifecycleIndicationContext(
1476                  _In_ const MI_Context* context,
1477                  _Outptr_ MI_LifecycleIndicationContext** lifecycleContext)
1478              {
1479              #ifdef DISABLE_INDICATION
1480                  return _GetLifecycleIndicationContext_NotSupported(context, lifecycleContext);
1481              #else
1482 krisbash 1.5 
1483                  Context* internalContext = (Context*)context;
1484                  LifecycleContext* lifeCtx = NULL;
1485              
1486                  /* Check if indication support has been enabled for this _Provider.  If
1487                   * not, activate it.  Previously initialized support means that either
1488                   * this provider is an Indication class or that a subscription already
1489                   * exists.
1490                   */
1491                  lifeCtx = internalContext->provider->subMgr->lifecycleCtx;
1492                  if (NULL == lifeCtx)
1493                  {
1494                      lifeCtx = LifeContext_New();
1495                      if (NULL == lifeCtx)
1496                      {
1497                          return MI_RESULT_FAILED;
1498                      }
1499                      LifeContext_Init( lifeCtx, internalContext->provider );
1500                      internalContext->provider->subMgr->lifecycleCtx = lifeCtx;
1501                  }
1502              
1503 krisbash 1.5     *lifecycleContext = (MI_LifecycleIndicationContext*)lifeCtx;
1504              
1505                  return MI_RESULT_OK;
1506              #endif
1507              }
1508              
1509              MI_ContextFT __mi_contextFT = 
1510 mike     1.1 {
1511 krisbash 1.5     // MI_Context_FT
1512 mike     1.1     _PostResult,
1513                  _PostInstance,
1514                  _PostIndication,
1515                  _ConstructInstance,
1516                  _ConstructParameters,
1517                  _NewInstance,
1518                  _NewDynamicInstance,
1519                  _NewParameters,
1520                  _Canceled,
1521                  _GetLocale,
1522                  _RegisterCancel,
1523                  _RequestUnload,
1524                  _RefuseUnload,
1525                  _GetLocalSession,
1526                  _SetStringOption,
1527                  _GetStringOption,
1528                  _GetNumberOption,
1529                  _GetCustomOption,
1530                  _GetCustomOptionCount,
1531                  _GetCustomOptionAt,
1532                  _WriteMessage,
1533 mike     1.1     _WriteProgress,
1534                  _WriteStreamParameter,
1535                  _WriteCimError,
1536                  _PromptUser,
1537                  _ShouldProcess,
1538                  _ShouldContinue,
1539                  _PostError,
1540                  _PostCimError,
1541                  _WriteError,
1542 krisbash 1.5     _GetLifecycleIndicationContext,
1543              };
1544              
1545              #ifndef DISABLE_INDICATION
1546              
1547              /*
1548               * Alternate MI_Context function table for handling indication functions.
1549               */
1550              MI_ContextFT __mi_indication_contextFT =
1551              {
1552                  _Ind_PostResult,
1553                  _Ind_PostInstance,
1554                  _Ind_PostIndication,
1555                  _ConstructInstance,
1556                  _ConstructParameters,
1557                  _NewInstance,
1558                  _NewDynamicInstance,
1559                  _NewParameters,
1560                  _Canceled,
1561                  _GetLocale,
1562                  _RegisterCancel,
1563 krisbash 1.5     _RequestUnload,
1564                  _RefuseUnload,
1565                  _GetLocalSession,
1566                  _SetStringOption,
1567                  _GetStringOption,
1568                  _GetNumberOption,
1569                  _GetCustomOption,
1570                  _GetCustomOptionCount,
1571                  _GetCustomOptionAt,
1572                  _WriteMessage,
1573                  _WriteProgress,
1574                  _WriteStreamParameter,
1575                  _WriteCimError,
1576                  _PromptUser,
1577                  _ShouldProcess,
1578                  _ShouldContinue,
1579                  _Ind_PostError,
1580                  _Ind_PostCimError,
1581                  _WriteError,
1582                  _GetLifecycleIndicationContext_NotSupported,
1583              };
1584 krisbash 1.5 
1585              /*
1586               * Alternate MI_Context function table for invoking subscribe and unsubscribe
1587               */
1588              
1589              static MI_Result _subunsub_ProcessResult(
1590                  MI_Context* self_,
1591                  MI_Result result,
1592                  const ZChar* errorMessage,
1593                  const MI_Instance* cimError)
1594              {
1595                  Context* self = (Context*)self_;
1596                  MI_UNREFERENCED_PARAMETER(errorMessage);
1597                  MI_UNREFERENCED_PARAMETER(cimError);
1598                  if (!self || self->magic != _MAGIC)
1599                      return MI_RESULT_INVALID_PARAMETER;
1600                  *self->result = result;
1601                  return MI_RESULT_OK;
1602              }
1603              
1604              static MI_Result MI_CALL _subunsub_PostResult(
1605 krisbash 1.5     MI_Context* self_,
1606                  MI_Result result)
1607              {
1608                  return _subunsub_ProcessResult(self_, result, NULL, NULL);
1609              }
1610              
1611              static MI_Result MI_CALL _subunsub_PostError(
1612                  _In_ MI_Context* self,
1613                  MI_Uint32 result,
1614                  _In_z_ const ZChar* type,
1615                  _In_z_ const ZChar* message)
1616              {
1617                  if (NULL == type ||
1618                      Tcscmp(type, MI_RESULT_TYPE_MI) != 0)
1619                  {
1620                      result = MI_RESULT_FAILED;
1621                  }
1622                  return _subunsub_ProcessResult(self, (MI_Result)result, message, NULL);
1623              }
1624              
1625              static MI_Result MI_CALL _subunsub_PostCimError(
1626 krisbash 1.5     _In_ MI_Context* self,
1627                  _In_ const MI_Instance *error)
1628              {
1629                  return _subunsub_ProcessResult(self, MI_RESULT_FAILED, NULL, error);
1630              }
1631              
1632              MI_ContextFT __mi_indication_subunsub_contextFT =
1633              {
1634                  _subunsub_PostResult,
1635                  _Ind_PostInstance,
1636                  _PostIndication,
1637                  _ConstructInstance,
1638                  _ConstructParameters,
1639                  _NewInstance,
1640                  _NewDynamicInstance,
1641                  _NewParameters,
1642                  _Canceled,
1643                  _GetLocale,
1644                  _RegisterCancel,
1645                  _RequestUnload,
1646                  _RefuseUnload,
1647 krisbash 1.5     _GetLocalSession,
1648                  _SetStringOption,
1649                  _GetStringOption,
1650                  _GetNumberOption,
1651                  _GetCustomOption,
1652                  _GetCustomOptionCount,
1653                  _GetCustomOptionAt,
1654                  _WriteMessage,
1655                  _WriteProgress,
1656                  _WriteStreamParameter,
1657                  _WriteCimError,
1658                  _PromptUser,
1659                  _ShouldProcess,
1660                  _ShouldContinue,
1661                  _subunsub_PostError,
1662                  _subunsub_PostCimError,
1663                  _WriteError,
1664                  _GetLifecycleIndicationContext_NotSupported,
1665 mike     1.1 };
1666              
1667 krisbash 1.5 /* 
1668               * The Context that uses this table does not get exposed
1669               * to a _Provider, so it is considered "internal."
1670               */
1671              MI_ContextFT __mi_lifecycleIndication_contextFT =
1672              {
1673                  _Ind_PostResult,
1674                  NULL,
1675                  _Ind_PostIndication,
1676                  NULL,
1677                  NULL,
1678                  NULL,
1679                  NULL,
1680                  NULL,
1681                  NULL,
1682                  NULL,
1683                  NULL,
1684                  NULL,
1685                  NULL,
1686                  NULL,
1687                  NULL,
1688 krisbash 1.5     NULL,
1689                  NULL,
1690                  NULL,
1691                  NULL,
1692                  NULL,
1693                  NULL,
1694                  NULL,
1695                  NULL,
1696                  NULL,
1697                  NULL,
1698                  NULL,
1699                  NULL,
1700                  NULL,
1701                  NULL,
1702                  NULL,
1703              };
1704              
1705              #endif /* ifndef DISABLE_INDICATION */
1706              
1707              static void _Context_Post( _In_ Strand* self_, _In_ Message* msg)
1708              {
1709 krisbash 1.5     DEBUG_ASSERT( MI_FALSE );  // not used yet (no secondary "semantic" messages)
1710              }
1711              
1712              static void _Context_PostControl( _In_ Strand* self, _In_ Message* msg)
1713              {
1714                  DEBUG_ASSERT( MI_FALSE );  // not used yet
1715              }
1716              
1717              #ifdef _PREFAST_
1718              #pragma prefast (push)
1719              #pragma prefast (disable: 26001) // bogus "we know the interaction points to the middle of the InteractionDispBase struct"
1720              #endif /* _PREFAST_ */
1721              
1722              static void _Context_Ack( _In_ Strand* self_)
1723              {
1724                  Context* self = FromOffset(Context,strand,self_);
1725                  ptrdiff_t tryingToPostLeftValue = ReadWithFence(&self->tryingToPostLeft);
1726              
1727                  trace_ContextAck( 
1728                      self_, 
1729                      self->strand.info.interaction.other, 
1730 krisbash 1.5         &self->strand.info.interaction, 
1731                      self->strand.info.thisClosedOther, 
1732                      self->strand.info.otherClosedThis,
1733                      tryingToPostLeftValue );
1734              
1735                  // al management done by strand implementation except broadcasting cond var
1736              
1737                  // wake up Context_PostMessageLeft if appropiate
1738                  // (no point on waking up Context_PostMessageLeft if CONTEXT_STRANDAUX_TRYPOSTLEFT is scheduled to run after us)
1739                  if( CONTEXT_POSTLEFT_POSTING == Atomic_CompareAndSwap( &self->tryingToPostLeft, (ptrdiff_t)CONTEXT_POSTLEFT_POSTING, (ptrdiff_t)(CONTEXT_POSTLEFT_POSTING|CONTEXT_POSTLEFT_SCHEDULED)) )
1740                  {
1741                      // Schedule it again
1742                      Strand_ScheduleAux( &self->strand, CONTEXT_STRANDAUX_TRYPOSTLEFT );
1743                      // again we get a memory barrier on tryingToPostLeft/tryingToPostLeftScheduled after this
1744                  }
1745              }
1746              
1747              static void _Context_Cancel( _In_ Strand* self )
1748              {
1749                  trace_ContextCancel( self );
1750              }
1751 krisbash 1.5 
1752              static void _Context_Close( _In_ Strand* self_ )
1753              {
1754                  Context* self = FromOffset(Context,strand,self_);
1755                  trace_ContextClose(
1756                      self_,
1757                      self->strand.info.interaction.other,
1758                      &self->strand.info.interaction );
1759              }
1760              
1761              static void _Context_Finish( _In_ Strand* self_ )
1762              {
1763                  Context* self = FromOffset(Context,strand,self_);
1764              
1765                  trace_ContextFinish( self_ );
1766                  _Context_Destroy(self);
1767              }
1768              
1769              // CONTEXT_STRANDAUX_TRYPOSTLEFT  
1770              static void _Context_Aux_TryPostLeft( _In_ Strand* self_ )
1771              {
1772 krisbash 1.5     Context* self = FromOffset(Context,strand,self_);
1773                  ptrdiff_t oldValue;
1774              
1775                  trace_ContextAuxPostLeft( self_, self->strand.info.thisAckPending );
1776              
1777                  if( !self->strand.info.thisAckPending )
1778                  {
1779                      if (!self->strand.info.thisClosedOther)  // TODO: Is this correct, or is it indiciative of a different problem?
1780                      {
1781                          /* Only post the message if this Context has not "closed"
1782                           * the connection.  Another thread may have done so on the
1783                           * context while this thread was waiting. */
1784                          Strand_Post( &self->strand, self->msgPostingLeft );
1785                      }
1786                      self->msgPostingLeft = NULL; 
1787                      Strand_ScheduleAux(self_, CONTEXT_STRANDAUX_TRYPOSTLEFT_NOTIFY);
1788                  }
1789                  else
1790                  {
1791                      oldValue = Atomic_Swap(&self->tryingToPostLeft,(ptrdiff_t)CONTEXT_POSTLEFT_POSTING);
1792                      DEBUG_ASSERT( (CONTEXT_POSTLEFT_POSTING|CONTEXT_POSTLEFT_SCHEDULED) == oldValue );
1793 krisbash 1.5     }
1794              }
1795              
1796              // CONTEXT_STRANDAUX_TRYPOSTLEFT_NOTIFY  
1797              static void _Context_Aux_TryPostLeft_Notify( _In_ Strand* self_ )
1798              {
1799                  Context* self = FromOffset(Context,strand,self_);
1800                  ptrdiff_t oldValue;
1801              
1802                  oldValue = Atomic_Swap(&self->tryingToPostLeft,(ptrdiff_t)0);
1803                  // wake up _Context_PostMessageLeft 
1804              
1805              // Uncomment when no longer using Selector
1806              //#if defined(CONFIG_OS_WINDOWS)
1807              //    trace_ContextAuxPostLeftNotify( self_ );
1808              //    CondLock_Broadcast((ptrdiff_t)self);
1809              //#else
1810                  if( self->postingOnIoThread )
1811                  {
1812                      trace_ContextAuxPostLeftNotify_IoThread( self_ );
1813                      self->postingOnIoThread = MI_FALSE;
1814 krisbash 1.5         Selector_StopRunningNoReadsMode( self->provider->lib->provmgr->selector );
1815                  }
1816                  else
1817                  {
1818                      trace_ContextAuxPostLeftNotify( self_ );
1819                      CondLock_Broadcast((ptrdiff_t)self);
1820                  }
1821              //#endif
1822              
1823                  DEBUG_ASSERT( (CONTEXT_POSTLEFT_POSTING|CONTEXT_POSTLEFT_SCHEDULED) == oldValue );
1824              }
1825              
1826              
1827              #ifdef _PREFAST_
1828              #pragma prefast (pop)
1829              #endif /* _PREFAST_ */
1830              
1831              /*
1832               * This represents a standard Context object.  It mediates access to the 
1833               * internal strands from providers so that a provider can have only one
1834               * operation outstanding at a time.  Provider Posts (Result, Indication, 
1835 krisbash 1.5  * Error, CimError, and Instance) are routed through 'TryPostLeft' so that
1836               * they can be handled within a post lock and in the context of a strand
1837               * action.  Providers may post from multiple threads to the same Context,
1838               * but only one post will be handled at a time.  An ACK releases the 
1839               * tryingToPostLeft flag to allow another Post to occur.
1840               * 
1841               * Shutdown behavior:
1842               *     Cancel and Close do nothing.  The strand cannot be finished until it
1843               *     schedules a close on itself.  This will happen when the Context or
1844               *     ProvMgr determine that a connection to a provider should be closed.
1845               *     Typically this happens after a provider calls PostResult, PostError,
1846               *     or PostCimError.
1847               */
1848              StrandFT _Context_leftInteractionFT =
1849              {
1850                  _Context_Post, 
1851                  _Context_PostControl, 
1852                  _Context_Ack,
1853                  _Context_Cancel, 
1854                  _Context_Close,
1855                  _Context_Finish,
1856 krisbash 1.5     NULL,
1857                  _Context_Aux_TryPostLeft,
1858                  _Context_Aux_TryPostLeft_Notify,
1859                  NULL,
1860                  NULL,
1861                  NULL 
1862              };
1863              
1864              
1865              #ifndef DISABLE_INDICATION
1866              
1867              /* 
1868               * IndicationManager cancels the operations upon get cancelled call from protocol or
1869               * received unsubscribe message.
1870               *
1871               * This function works for both Lifecycle and regular subscription contexts
1872               */
1873              static void _SubscribeContext_Cancel(_In_ Strand* self_)
1874              {
1875                  SubscriptionContext* self = (SubscriptionContext*)((char*)self_ - offsetof(Context,strand));
1876                  trace_SubscribeContext_Cancel(self);
1877 krisbash 1.5 
1878                  if (NULL == self->subscription ||
1879                      SubMgrSubscription_CancelStarted(self->subscription))
1880                  {
1881                      /* The subscription has already posted a final result, so there is 
1882                       * nothing to do here. */
1883                      return;
1884                  }
1885                  SubscrContext_Unsubscribe(self);
1886                  trace_SubscribeContext_CancelDone(self);
1887              }
1888              
1889              
1890              // CONTEXT_STRANDAUX_INVOKESUBSCRIBE
1891              static void _Context_Aux_InvokeSubscribe( _In_ Strand* self_ )
1892              {
1893                  Context* self = FromOffset(Context,strand,self_);
1894                  Message* msg = self->strand.info.stored.msg;
1895              
1896                  DEBUG_ASSERT( NULL != msg );
1897              
1898 krisbash 1.5     self->strand.info.stored.msg = NULL;
1899              
1900                  Provider_InvokeSubscribe(
1901                      self->provider,
1902                      (SubscribeReq*)msg,
1903                      (SubscriptionContext*)self);
1904              
1905                  /*
1906                   * release the reference count from _SubMgrSubscription_New
1907                   */
1908                  SubMgrSubscription_Release(((SubscriptionContext*)self)->subscription);
1909              
1910                  Message_Release( msg );
1911              }
1912              
1913              /*
1914               * This represents a SubscriptionContext object.  It functions the same way as
1915               * a normal Context (follows the same behavioral pattern), but is designed to 
1916               * handle indications.  It also includes an AUX subscribe method so that 
1917               * subscription requests happen within the protections of a strand invocation.
1918               */
1919 krisbash 1.5 StrandFT _SubscribeContext_leftInteractionFT =
1920              {
1921                  _Context_Post, 
1922                  _Context_PostControl, 
1923                  _Context_Ack,
1924                  _SubscribeContext_Cancel, 
1925                  _Context_Close,
1926                  _Context_Finish,
1927                  NULL,
1928                  _Context_Aux_TryPostLeft,
1929                  _Context_Aux_TryPostLeft_Notify,
1930                  _Context_Aux_InvokeSubscribe,
1931                  NULL,
1932                  NULL 
1933              };
1934              
1935              #endif /* ifndef DISABLE_INDICATION */
1936              
1937              _Use_decl_annotations_
1938              MI_Result _Context_Init(
1939 mike     1.1     Context* self,
1940 krisbash 1.5     Provider* provider,
1941                  InteractionOpenParams* interactionParams,
1942                  ContextInitOptions options,
1943                  Context_Type ctxType )
1944 mike     1.1 {
1945 krisbash 1.5     StrandFT *ft = NULL;
1946              
1947                  if( NULL == self )
1948                      return MI_RESULT_FAILED;
1949              
1950 mike     1.1     memset(self, 0, sizeof(Context));
1951 krisbash 1.5 
1952                  trace_ContextNew( self, interactionParams ? interactionParams->interaction : NULL, &self->strand.info.interaction );
1953              
1954                  Lock_Init(&self->lock);
1955              
1956                  self->ctxType = ctxType;
1957                  
1958                  if( NULL != interactionParams && NULL != interactionParams->msg )
1959                  {
1960                      DEBUG_ASSERT( Message_IsRequest( interactionParams->msg ) );
1961                      /* release inside _Context_Destroy */
1962                      Message_AddRef( interactionParams->msg );
1963                      self->request = (RequestMsg*)interactionParams->msg;
1964                  }
1965              
1966              #ifndef DISABLE_INDICATION
1967                  /*
1968                   * Conditionally set function table based on desired context type.
1969                   */
1970                  if (CTX_TYPE_IND_AGGREGATION == ctxType ||
1971                      CTX_TYPE_IND_SUBSCRIPTION == ctxType)
1972 krisbash 1.5     {
1973                      self->base.ft = &__mi_indication_contextFT;
1974                      ft = &_SubscribeContext_leftInteractionFT;
1975                  }
1976                  else if (CTX_TYPE_IND_LIFECYCLE == ctxType)
1977                  {
1978                      self->base.ft = &__mi_lifecycleIndication_contextFT;
1979                      ft = &_SubscribeContext_leftInteractionFT;
1980                  }
1981                  else if (CTX_TYPE_IND_SUB_UNSUB == ctxType)
1982                  {
1983                      DEBUG_ASSERT( provider == NULL );
1984                      DEBUG_ASSERT( interactionParams == NULL );
1985                      DEBUG_ASSERT( ContextInit_NoInteraction == options );
1986                      self->base.ft = &__mi_indication_subunsub_contextFT;
1987                  }
1988                  else
1989              #endif /* ifndef DISABLE_INDICATION */
1990                  {
1991                      self->base.ft = &__mi_contextFT;
1992                      ft = &_Context_leftInteractionFT;
1993 krisbash 1.5     }
1994              
1995 mike     1.1     self->magic = _MAGIC;
1996                  self->provider = provider;
1997 krisbash 1.5 
1998                  if( ContextInit_DelayOpen == options )
1999                  {
2000                      DEBUG_ASSERT( NULL != interactionParams );
2001                      Strand_Init( STRAND_DEBUG( Context ) &self->strand, ft, STRAND_FLAG_ENTERSTRAND|STRAND_FLAG_DELAYACCEPTOPEN, interactionParams );
2002                  }
2003                  else if ( ContextInit_NoInteraction != options )
2004                  {
2005                      Strand_Init( STRAND_DEBUG( Context ) &self->strand, ft, STRAND_FLAG_ENTERSTRAND, interactionParams );
2006                      if( NULL != interactionParams )
2007                      {
2008                          DEBUG_ASSERT( NULL != interactionParams->msg );
2009                          Strand_Ack( &self->strand );
2010                      }
2011                      if( ContextInit_DontLeaveStrand  != options  )
2012                      {
2013                          Strand_Leave( &self->strand );
2014                      }
2015                  }
2016              
2017 mike     1.1     Provider_Addref(self->provider);
2018 krisbash 1.5 
2019                  return MI_RESULT_OK;
2020 mike     1.1 }
2021              
2022 krisbash 1.5 void Context_CompleteOpen(
2023                  _In_ Context* self,
2024                  _In_ InteractionOpenParams* params,
2025                       MI_Result result)
2026 mike     1.1 {
2027 krisbash 1.5     DEBUG_ASSERT( NULL != params->msg );
2028 mike     1.1 
2029 krisbash 1.5     if( MI_RESULT_OK == result )
2030                  {
2031                      Strand_AcceptOpen( &self->strand, params );
2032                      Strand_Ack( &self->strand );
2033                      Strand_Leave( &self->strand );
2034                  }
2035                  else
2036                  {
2037                      // Just destroy the context
2038                      _Context_Destroy(self);
2039                      Strand_FailOpenWithResult(params, result, PostResultMsg_NewAndSerialize);
2040                  }
2041              }
2042 mike     1.1 
2043 krisbash 1.5 //
2044              // Initialize subscribe/unsubscribe context
2045              //
2046              MI_Result Subunsub_Context_Init(
2047                  _Out_ Context* self,
2048                  _In_ MI_Result* result,
2049                  _In_ RequestMsg* msg)
2050              {
2051                  MI_Result r;
2052                  DEBUG_ASSERT( msg && result );
2053                  r = _Context_Init(self, NULL, NULL, ContextInit_NoInteraction, CTX_TYPE_IND_SUB_UNSUB);
2054                  if ( r == MI_RESULT_OK )
2055                  {
2056                      Message_AddRef( &msg->base );
2057                      self->request = msg;
2058                      self->result = result;
2059                  }
2060                  return r;
2061 mike     1.1 }

ViewCVS 0.9.2