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

   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 <assert.h>
  26 krisbash 1.3 #include <ctype.h>
  27 mike     1.1 #include "wsman.h"
  28              #include "wsbuf.h"
  29              #include "wsmanparser.h"
  30 krisbash 1.3 #include <pal/sleep.h>
  31 mike     1.1 #include <xml/xml.h>
  32              #include <base/log.h>
  33              #include <base/result.h>
  34 krisbash 1.3 #include <pal/strings.h>
  35 mike     1.1 #include <base/user.h>
  36 krisbash 1.3 #include <base/memman.h>
  37              #include <pal/format.h>
  38              #include <base/Strand.h>
  39 mike     1.1 #include <base/base.h>
  40 krisbash 1.3 #include <base/list.h>
  41              #include <pal/lock.h>
  42              #include <indication/common/indicommon.h>
  43              #include <pal/cpu.h>
  44              
  45              #if defined(CONFIG_USE_WCHAR)
  46              # define HASHSTR_CHAR wchar_t
  47              # define HASHSTR_T(scs) L##scs
  48              #endif
  49 mike     1.1 
  50              #include "wstags.h"
  51              
  52 krisbash 1.3 #define CR ZT("\n")
  53              
  54              #define TRACE_GOTO_FAILED
  55              
  56              #if defined(TRACE_GOTO_FAILED)
  57              # define GOTO_FAILED \
  58                  for (;;) \
  59                  { \
  60                      trace_Wsman_GotoFailed(__FILE__, __LINE__); \
  61                      goto failed; \
  62                  }
  63              #else
  64              # define GOTO_FAILED goto failed
  65              #endif
  66              
  67              //-----------------------------------------------------------------------
  68              
  69              #define WSMANCONNECTION_STRANDAUX_PROCESSREQUEST                0
  70              
  71              STRAND_DEBUGNAME1( WsmanConnection, ProcessRequest );
  72              
  73 krisbash 1.3 #define ENUMERATIONCONTEXT_STRANDAUX_PULLATTACHED               0
  74              #define ENUMERATIONCONTEXT_STRANDAUX_UNSUBSCRIBEATTACHED        1
  75              #define ENUMERATIONCONTEXT_STRANDAUX_CONNECTION_DATA_TIMEOUT    2
  76              
  77              STRAND_DEBUGNAME2( WsmanEnumerationContext, PullAttached, UnsubscribeAttached );
  78 mike     1.1 
  79              /*
  80              **==============================================================================
  81              **
  82              ** Local definitions:
  83              **
  84              **==============================================================================
  85              */
  86 krisbash 1.3 #define WSMAN_MAX_ENVELOPE_SIZE MAX_ENVELOPE_SIZE 
  87              
  88              #define MAX_WSMAN_BUFFER_SIZE 2*1024*1024  // 2 MB
  89              #define MAX_WSMAN_COLLECTION_SIZE 2*1024 // upto 2K instances
  90              
  91              const MI_Uint64 WSMAN_TIMEOUT_DEFAULT = 60 * 1000 * 1000; // 60 Seconds in microseconds
  92              
  93              #define TYPICAL_ENUM_RESPONSE_ENVELOPE \
  94                  "<SOAP-ENV:Envelope \n" \
  95                  "xmlns:SOAP-ENV=\n" \
  96                  "\"http://www.w3.org/2003/05/soap-envelope\" \n" \
  97                  "xmlns:wsa=\n" \
  98                  "\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" \n" \
  99                  "xmlns:wsen=\n" \
 100                  "\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\" \n" \
 101                  "xmlns:xsi=\n" \
 102                  "\"http://www.w3.org/2001/XMLSchema-instance\" \n" \
 103                  "xmlns:wsmb=\n" \
 104                  "\"http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd\" \n" \
 105                  "xmlns:wsman=\n" \
 106                  "\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\" \n" \
 107 krisbash 1.3     "xmlns:wxf=\n" \
 108                  "\"http://schemas.xmlsoap.org/ws/2004/09/transfer\" \n" \
 109                  "xmlns:cim=\n" \
 110                  "\"http://schemas.dmtf.org/wbem/wscim/1/common\" \n" \
 111                  "xmlns:wsmid=\n" \
 112                  "\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\">\n" \
 113                  "<SOAP-ENV:Header>\n" \
 114                  "<wsa:To>\n" \
 115                  "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous\n" \
 116                  "</wsa:To>\n" \
 117                  "<wsa:Action>\n" \
 118                  "http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse\n" \
 119                  "</wsa:Action>\n" \
 120                  "<wsa:MessageID>\n" \
 121                  "uuid:00000000-0000-0000-0000-000000000000\n" \
 122                  "</wsa:MessageID>\n" \
 123                  "<wsa:RelatesTo>\n" \
 124                  "uuid:00000000-0000-0000-0000-000000000000\n" \
 125                  "</wsa:RelatesTo>\n" \
 126                  "</SOAP-ENV:Header>\n" \
 127                  "<SOAP-ENV:Body>\n" \
 128 krisbash 1.3     "<wsen:EnumerateResponse>\n" \
 129                  "<wsen:EnumerationContext>\n" \
 130                  "000000000000\n" \
 131                  "</wsen:EnumerationContext>\n" \
 132                  "<wsman:Items>\n" \
 133                  "</wsman:Items>\n" \
 134                  "</wsen:EnumerateResponse>\n" \
 135                  "</SOAP-ENV:Body>\n" \
 136                  "</SOAP-ENV:Envelope>\n"
 137 mike     1.1 
 138              /* aproximate repsonse header size */
 139 krisbash 1.3 #define APPROX_ENUM_RESP_ENVELOPE_SIZE \
 140                  (sizeof(TYPICAL_ENUM_RESPONSE_ENVELOPE) + 64)
 141 mike     1.1 
 142              static const MI_Uint32 _MAGIC = 0x1CF2BCB7;
 143              
 144              /************************************************************************\
 145              *   Local definitions
 146              \************************************************************************/
 147              
 148              typedef struct _WSMAN_ConnectionData    WSMAN_ConnectionData;
 149              typedef struct _WSMAN_EnumerateContext  WSMAN_EnumerateContext;
 150              
 151              /* Maximum number of enumeration contexts stored at the same time 
 152                  effectively limits number of concurent enumerations */
 153 krisbash 1.3 #define WSMAN_MAX_ENUM_CONTEXTS 64
 154 mike     1.1 
 155              struct _WSMAN
 156              {
 157                  MI_Uint32 magic;
 158 krisbash 1.3 
 159                  OpenCallback callback;
 160 mike     1.1     void* callbackData;
 161 krisbash 1.3     
 162 mike     1.1     Http* http;
 163                  Selector* selector;
 164              
 165                  /* configurable options */
 166                  WSMAN_Options options;
 167              
 168 krisbash 1.3     // to synchronize access to enumeration contexts
 169                  RecursiveLock lock;
 170                  
 171 mike     1.1     /* Array of enumeration contexts:
 172                      each 'pull' will look for corresponding context
 173                  */
 174                  WSMAN_EnumerateContext* enumerateContexts[WSMAN_MAX_ENUM_CONTEXTS];
 175 krisbash 1.3     // If the particular enumerate context is in the process of being deleted
 176                  MI_Boolean enumerateContextDeleted[WSMAN_MAX_ENUM_CONTEXTS];
 177              
 178                  ptrdiff_t numEnumerateContexts;
 179                  MI_Boolean deleting;
 180 mike     1.1 
 181                  /* Cached xml parser with all namespaces registered */
 182                  XML xml;
 183              };
 184              
 185 krisbash 1.3 typedef struct _WSMAN_Timer
 186              {
 187                  /* Generic timer to handle timeouts */
 188                  Timer timer;
 189              
 190                  /* Force a heartbeat event if nothing else can be sent during HB interval */
 191                  MI_Boolean forceResult;
 192              
 193                  /* The Strand is exiting while a timer may be active.  The timer should fire,
 194                   * but not take action to ensure appropriate clean up. */
 195                  MI_Boolean cancelledTimer;
 196              
 197                  /* When heartbeats are requested during subscribe, these values are
 198                   * considered when deciding when to send heartbeats. */
 199                  MI_Uint64 heartbeatInterval;
 200                  
 201                  /* The timeout was called as a result of a PullAttach */
 202                  MI_Boolean isPullAttached;
 203              } WSMAN_Timer;
 204              
 205 mike     1.1 /* Represents state of connection including buffers, unsent packets, states etc */
 206              struct _WSMAN_ConnectionData
 207              {
 208 krisbash 1.3     StrandBoth strand;
 209 mike     1.1 
 210 krisbash 1.3     WSMAN* wsman;
 211 mike     1.1 
 212                  /* Requestor information */
 213 krisbash 1.3     AuthInfo authInfo;
 214 mike     1.1 
 215                  /* Attributes of the request */
 216                  WSMAN_WSHeader  wsheader;
 217                  union
 218                  {
 219                      /* Actual type is defined by wsheader.rqtAction field */
 220                       WSMAN_WSEnumeratePullBody wsenumpullbody;
 221                  }
 222                  u;
 223              
 224 krisbash 1.3     /* incomming request msg */
 225                  HttpRequestMsg * request;
 226                  
 227 mike     1.1     /* Request page (buffer for most pointers inside header/body structures) */
 228 krisbash 1.3     Page* page;
 229              
 230                  /* for single-instance/single-schema repsonses, we keep mesage until result
 231                     received to avoid conflicts with keep-alive enabled */
 232                  Message* single_message;
 233              
 234                  /* flag indicates that response was not sent yet to the client */
 235                  MI_Boolean outstandingRequest;
 236              
 237                  /* True if WinRM client */
 238                  UserAgent userAgent;
 239              
 240                  /* Generic timer to handle operation timeouts */
 241                  WSMAN_Timer cdTimer;
 242                  MI_Uint32 enumCtxId;        // TODO: What about replacing it with a WSMAN_EnumerateContext ptr?
 243              
 244                  /* A temporarily stored message from Post, prior to handling */
 245                  Message* responseMessage; // TODO: During refactoring, see if it is possible to safely remove this or merge it with single_message
 246 mike     1.1 
 247 krisbash 1.3 #if defined(CONFIG_ENABLE_HTTPHEADERS)
 248 mike     1.1 
 249 krisbash 1.3     /* Dynamic list of headers */
 250                  HttpHeader headers[HTTP_MAX_HEADERS];
 251                  size_t headersSize;
 252 mike     1.1 
 253 krisbash 1.3 #endif
 254 mike     1.1 };
 255              
 256 krisbash 1.3 typedef struct _WSMAN_EnumerateContextData
 257              {
 258                  /* Type of the request initiated the context */
 259                  MI_Uint32 requestTag;
 260              
 261                  /* Success response to client sent or not */
 262                  MI_Boolean responsed;
 263              }WSMAN_EnumerateContextData;
 264              
 265 mike     1.1 /* Enumeration context:
 266                  'derived' from socket Handler, so it can subscribe for timeouts */
 267              
 268              struct _WSMAN_EnumerateContext
 269              {
 270 krisbash 1.3     StrandBoth strand;
 271 mike     1.1 
 272 krisbash 1.3     WSMAN* wsman;
 273                  
 274 mike     1.1     /* based member - can be added to 'selector' for timeout support */
 275                  Handler     base;
 276              
 277                  /* response data */
 278                  /* Linked list of messages to send */
 279                  PostInstanceMsg* head;
 280                  PostInstanceMsg* tail;
 281              
 282                  /* Total size of all instances in response queue */
 283                  MI_Uint32   totalResponseSize;
 284              
 285 krisbash 1.3     /* Number of messages in repsonse queue */
 286 mike     1.1     MI_Uint32   totalResponses;
 287              
 288                  /* lower 16 bits is aninxed in self->enumerateContexts, upper 16 bits are random data (for validation) */
 289                  MI_Uint32   enumerationContextID;
 290                  MI_Result   finalResult;
 291 krisbash 1.3     PostResultMsg *errorMessage;
 292              
 293                  /* Indicates that 'Result' recevied from provider and stored in finalResult.
 294                   * Also blocks future posts from providers during shutdown scenarios. */
 295 mike     1.1     MI_Boolean  enumerationCompleted;
 296              
 297                  /* pointer to current active connection - either Enumerate or Pull request */
 298                  WSMAN_ConnectionData*   activeConnection;
 299 krisbash 1.3 
 300                  /* pointer to the connection being attached (a pull or unsubscribe). It will 
 301                   * become activeConnection once attached */
 302                  volatile WSMAN_ConnectionData*   attachingConnection;
 303              
 304                  /* If we are reached our buffer limit, we hold any posted message here and delay ACK */
 305                  PostInstanceMsg* pendingMessage;
 306              
 307              #ifndef DISABLE_INDICATION
 308                  /* Whether the subscribe request asked for bookmarks during event delivery. */
 309                  MI_Boolean sendBookmarks;
 310              #endif
 311              
 312                  /* additional data associated with operation */
 313                  WSMAN_EnumerateContextData data;
 314              
 315                  /* Heartbeat timer */
 316                  WSMAN_Timer ecTimer;
 317 mike     1.1 };
 318              
 319              /* forward declarations */
 320              
 321              static void _SendEnumPullResponse(
 322 krisbash 1.3     _In_    WSMAN_EnumerateContext* selfEC, 
 323                          MI_Boolean              fromRequest );
 324              
 325              static void _SendErrorResultResponse(
 326                  _In_        WSMAN_ConnectionData*   selfCD, 
 327                  _In_opt_    WSMAN_EnumerateContext* sendECStrand,
 328                              MI_Result               result);
 329              
 330              static void _WSMAN_ReleaseEnumerateContext(
 331                  _In_    WSMAN*      self,
 332                          MI_Uint32   enumerationContextID);
 333              
 334              static void _HttpProcessRequest(
 335                  _In_    WSMAN_ConnectionData*   selfCD,
 336                  _In_    const HttpHeaders*      headers,
 337                  _In_    Page*                   page);
 338              
 339              #ifndef DISABLE_INDICATION
 340              
 341              static MI_Result _WSMAN_AddSubscribeResponse(
 342                  WSBuf *wsbuf,
 343 mike     1.1     WSMAN_EnumerateContext* selfEC);
 344              
 345 krisbash 1.3 static void _ParseValidateProcessUnsubscribeRequest(
 346                  WSMAN_ConnectionData* selfCD,
 347                  XML* xml);
 348              
 349              static void _ParseValidateProcessSubscribeRequest(
 350                  WSMAN_ConnectionData* selfCD,
 351                  XML* xml);
 352              
 353              #endif /* ifndef DISABLE_INDICATION */
 354              
 355              static MI_Uint64 _NextOperationID()
 356              {
 357                  static volatile ptrdiff_t _operationId = (ptrdiff_t)0x100000;
 358                  return (MI_Uint64) Atomic_Inc(&_operationId);
 359              }
 360 mike     1.1 
 361 krisbash 1.3 static StrandFT _InteractionWsmanEnum_Left_FT;   
 362              static StrandFT _InteractionWsmanEnum_Right_FT;
 363 mike     1.1 
 364              /************************************************************************\
 365 krisbash 1.3 *   Helper functions
 366 mike     1.1 \************************************************************************/
 367              /* Converts Enumeration mode into "Message" struct flag */
 368              MI_INLINE   MI_Uint32 _convertWSMANtoMsgEnumerationMode(
 369                  MI_Uint32 enumerationMode )
 370              {
 371                  if (WSMANTAG_ENUM_MODE_EPR == enumerationMode)
 372                      return WSMAN_EPRFlag;
 373              
 374                  if (WSMANTAG_ENUM_MODE_OBJECT_AND_EPR == enumerationMode)
 375                      return WSMAN_ObjectAndEPRFlag;
 376              
 377                  return WSMAN_ObjectFlag;
 378              }
 379              
 380              /************************************************************************\
 381              *   Enumeration Context operations
 382              \************************************************************************/
 383 krisbash 1.3 
 384              static void _EC_ReleasePendingMessage(
 385                  WSMAN_EnumerateContext* self)
 386              {
 387                  if (self->pendingMessage)
 388                  {
 389                      PostInstanceMsg_Release(self->pendingMessage);
 390                      self->pendingMessage = NULL;
 391                      StrandBoth_ScheduleAckRight(&self->strand);
 392                  }
 393              }
 394              
 395              // Called inside the EC strand
 396 mike     1.1 static void _EC_ReleaseAllMessages(
 397                  WSMAN_EnumerateContext* self)
 398              {
 399 krisbash 1.3     STRAND_ASSERTONSTRAND( &self->strand.base );
 400              
 401 mike     1.1     /* Delete all queued messages*/
 402                  while (self->head)
 403                  {
 404                      PostInstanceMsg* msg = self->head;
 405              
 406                      List_Remove(
 407                          (ListElem**)&self->head, 
 408                          (ListElem**)&self->tail, 
 409                          (ListElem*)msg);
 410                      PostInstanceMsg_Release(msg);
 411                  }
 412                  self->totalResponses = 0;
 413                  self->totalResponseSize = 0;
 414 krisbash 1.3 
 415                  _EC_ReleasePendingMessage(self);
 416 mike     1.1 }
 417              
 418 krisbash 1.3 // Detaches from left connection
 419              // Usually called inside the EC strand (can be on called on CD Strand on creation)
 420              static void _EC_CloseLeft(
 421                  _In_    WSMAN_EnumerateContext* self,
 422                          MI_Boolean              fromRequest )
 423              {
 424                  DEBUG_ASSERT( self->strand.base.info.opened );
 425                  DEBUG_ASSERT( !self->strand.base.info.thisClosedOther );
 426                  DEBUG_ASSERT( NULL != self->activeConnection );
 427                  
 428                  if( fromRequest )
 429                  {
 430                      // We set this manually
 431                      self->activeConnection->strand.infoRight.otherClosedThis = MI_TRUE;
 432                      self->strand.base.info.thisClosedOther = MI_TRUE;
 433                      self->activeConnection->strand.infoRight.thisClosedOther = MI_TRUE;
 434                      self->strand.base.info.otherClosedThis = MI_TRUE;
 435                      self->activeConnection = NULL;
 436                  }
 437                  else
 438 mike     1.1     {
 439 krisbash 1.3         self->activeConnection = NULL;
 440                      StrandBoth_CloseLeft( &self->strand );
 441 mike     1.1     }
 442              }
 443              
 444 krisbash 1.3 // Called inside the EC strand
 445              // checks if the left interaction is already closed 
 446              // if not, it closes it 
 447              static void _EC_CheckCloseLeft(
 448                  _In_    WSMAN_EnumerateContext* self)
 449 mike     1.1 {
 450 krisbash 1.3     STRAND_ASSERTONSTRAND(&self->strand.base);
 451                  DEBUG_ASSERT( self->strand.base.info.opened );
 452 mike     1.1 
 453 krisbash 1.3     trace_Wsman_EC_CheckCloseLeft( self->strand.base.info.thisClosedOther, self->activeConnection );
 454 mike     1.1 
 455 krisbash 1.3     if( !self->strand.base.info.thisClosedOther )
 456                  {
 457                      _EC_CloseLeft( self, MI_FALSE );
 458 mike     1.1     }
 459 krisbash 1.3     else
 460 mike     1.1     {
 461 krisbash 1.3         // If we have closed the left already there should not be activeConnection
 462                      DEBUG_ASSERT( NULL == self->activeConnection  );
 463 mike     1.1     }
 464              }
 465              
 466 krisbash 1.3 // Called inside the EC strand
 467              // checks if the right interaction is already closed 
 468              // if not, it closes it and releases enum context from WSMAN
 469              static void _EC_CheckCloseRight(
 470                  _In_    WSMAN_EnumerateContext* self)
 471 mike     1.1 {
 472 krisbash 1.3     STRAND_ASSERTONSTRAND(&self->strand.base);
 473                  
 474                  trace_Wsman_EC_CheckCloseRight( Strand_HaveTimer(&self->strand.base), self->strand.infoRight.thisClosedOther );
 475 mike     1.1 
 476 krisbash 1.3     if (Strand_HaveTimer(&self->strand.base))
 477                  {
 478                      // takes care of deleting timer if was set (it will come back here once timer is actually expired)
 479                      Strand_FireTimer( &self->strand.base );
 480                  }
 481                  else if( !self->strand.infoRight.thisClosedOther )
 482 mike     1.1     {
 483 krisbash 1.3         // Remove context from the list 
 484                      _WSMAN_ReleaseEnumerateContext(self->wsman, self->enumerationContextID);
 485 mike     1.1 
 486 krisbash 1.3         _EC_ReleaseAllMessages(self);
 487 mike     1.1 
 488 krisbash 1.3         // Close interaction to the right so object is ready to be deleted
 489                      StrandBoth_CloseRight( &self->strand );
 490 mike     1.1     }
 491              }
 492              
 493              /************************************************************************\
 494              *   WSman operations
 495              \************************************************************************/
 496 krisbash 1.3 MI_INLINE
 497              MI_Uint32 _WSMAN_GetEnumContextIndex(
 498                      WSMAN*      self,
 499                      MI_Uint32   enumerationContextID,
 500                      MI_Boolean  isRelease )
 501 mike     1.1 {
 502 krisbash 1.3     MI_Uint32 index = enumerationContextID & 0xFFFF;
 503                  
 504                  /* verify that context exist and has the same id as required */
 505                  if (index < MI_COUNT(self->enumerateContexts) &&
 506                      self->enumerateContexts[index] &&
 507                      (isRelease || !self->enumerateContextDeleted[index]) &&
 508                      self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
 509 mike     1.1     {
 510 krisbash 1.3         return index;
 511 mike     1.1     }
 512 krisbash 1.3     else
 513 mike     1.1     {
 514 krisbash 1.3         return WSMAN_MAX_ENUM_CONTEXTS;
 515 mike     1.1     }
 516 krisbash 1.3 }
 517 mike     1.1 
 518 krisbash 1.3 static WSMAN_EnumerateContext* _WSMAN_FindEnumContext(
 519                  WSMAN* self,
 520                  MI_Uint32   enumerationContextID)
 521              {
 522                  MI_Uint32 index;
 523                  WSMAN_EnumerateContext* context = NULL;
 524 mike     1.1 
 525 krisbash 1.3     RecursiveLock_Acquire(&self->lock);
 526 mike     1.1 
 527 krisbash 1.3     index = _WSMAN_GetEnumContextIndex(self, enumerationContextID, MI_FALSE );
 528                  if( index < WSMAN_MAX_ENUM_CONTEXTS )
 529                  {
 530                      context = self->enumerateContexts[index];
 531                  }
 532                  else
 533                  {
 534                      trace_Wsman_CannotFindEnumerateContext( enumerationContextID );
 535                  }
 536                  
 537                  RecursiveLock_Release(&self->lock);
 538                  
 539                  return context;
 540 mike     1.1 }
 541              
 542 krisbash 1.3 // Called on Release Request
 543              static WSMAN_EnumerateContext* _WSMAN_FindAndDeleteEnumContext(
 544 mike     1.1     WSMAN* self,
 545                  MI_Uint32   enumerationContextID)
 546              {
 547 krisbash 1.3     MI_Uint32 index;
 548                  WSMAN_EnumerateContext* context = NULL;
 549 mike     1.1 
 550 krisbash 1.3     RecursiveLock_Acquire(&self->lock);
 551 mike     1.1 
 552 krisbash 1.3     index = _WSMAN_GetEnumContextIndex(self, enumerationContextID, MI_FALSE );
 553                  if( index < WSMAN_MAX_ENUM_CONTEXTS )
 554                  {
 555                      context = self->enumerateContexts[index];
 556                      self->enumerateContextDeleted[index] = MI_TRUE;
 557                  }
 558                  else
 559                  {
 560                      trace_CannotFindEnumerateContext( enumerationContextID );
 561                  }
 562                  
 563                  RecursiveLock_Release(&self->lock);
 564                  
 565                  return context;
 566 mike     1.1 }
 567              
 568 krisbash 1.3 // Called on enum context strand or on CD strand during creation
 569 mike     1.1 static void _WSMAN_ReleaseEnumerateContext(
 570 krisbash 1.3     _In_    WSMAN*      self,
 571                          MI_Uint32   enumerationContextID)
 572 mike     1.1 {
 573 krisbash 1.3     MI_Boolean broadcast = MI_FALSE;
 574                  MI_Uint32 index;
 575 mike     1.1 
 576 krisbash 1.3     RecursiveLock_Acquire(&self->lock);
 577                  
 578                  index = _WSMAN_GetEnumContextIndex(self, enumerationContextID, MI_TRUE );
 579                  if( index < WSMAN_MAX_ENUM_CONTEXTS )
 580 mike     1.1     {
 581 krisbash 1.3         self->enumerateContexts[index] = 0;
 582                      self->enumerateContextDeleted[index] = MI_FALSE;
 583                      --self->numEnumerateContexts;
 584 mike     1.1 
 585 krisbash 1.3         broadcast = self->deleting;
 586                  }
 587                  else
 588                  {
 589                      DEBUG_ASSERT( MI_FALSE );
 590 mike     1.1     }
 591 krisbash 1.3 
 592                  RecursiveLock_Release(&self->lock);
 593              
 594                  if( broadcast )
 595                      CondLock_Broadcast( (ptrdiff_t)self );
 596 mike     1.1 }
 597              
 598 krisbash 1.3 // Lock should be acquired when calling here
 599              static void _WSMAN_CancelAllEnumerateContexts(
 600 mike     1.1     WSMAN* self)
 601              {
 602                  MI_Uint32 index;
 603              
 604                  for (index = 0; index < MI_COUNT(self->enumerateContexts); index++ )
 605                  {
 606                      if (self->enumerateContexts[index])
 607                      {
 608 krisbash 1.3             // delete timer if was set 
 609 mike     1.1             Selector_RemoveHandler(self->selector, &self->enumerateContexts[index]->base);
 610              
 611 krisbash 1.3             StrandBoth_ScheduleCancel( &self->enumerateContexts[index]->strand );
 612 mike     1.1         }
 613                  }
 614              }
 615              
 616 krisbash 1.3 static WSMAN_EnumerateContext* _WSMAN_AllocateEnumContext(
 617                  _In_    WSMAN*          self,
 618                  _In_    Interaction*    withInteraction )
 619 mike     1.1 {
 620 krisbash 1.3     MI_Uint32   enumerationContextID;
 621                  WSMAN_EnumerateContext* enumContext;
 622                  InteractionOpenParams params;
 623              
 624                  RecursiveLock_Acquire(&self->lock);
 625              
 626                  if( self->numEnumerateContexts >= MI_COUNT(self->enumerateContexts) )
 627 mike     1.1     {
 628 krisbash 1.3         trace_EnumContexAllocFailed_TooManyConcurrent();
 629                      RecursiveLock_Release(&self->lock);
 630                      return NULL;   /* no more slots available */
 631                  }
 632 mike     1.1 
 633 krisbash 1.3     /* Find empty slot */
 634                  for (enumerationContextID = 0; enumerationContextID < MI_COUNT(self->enumerateContexts); enumerationContextID++)
 635                  {
 636                      if (!self->enumerateContexts[enumerationContextID])
 637                          break;
 638 mike     1.1     }
 639              
 640 krisbash 1.3     if (MI_COUNT(self->enumerateContexts) == enumerationContextID)
 641 mike     1.1     {
 642 krisbash 1.3         trace_EnumContexAllocFailed_TooManyConcurrent();
 643                      RecursiveLock_Release(&self->lock);
 644                      return NULL;   /* no more slots available */
 645                  }
 646 mike     1.1 
 647 krisbash 1.3     InteractionOpenParams_Init( &params );
 648                  params.interaction = withInteraction;
 649              
 650                  enumContext = (WSMAN_EnumerateContext*)StrandBoth_New(
 651                                      STRAND_DEBUG( WsmanEnumerationContext )
 652                                      &_InteractionWsmanEnum_Left_FT,
 653                                      &_InteractionWsmanEnum_Right_FT,
 654                                      sizeof(WSMAN_EnumerateContext),
 655                                      STRAND_FLAG_ENTERSTRAND,
 656                                      &params );
 657              
 658                  if (!enumContext)
 659                  {
 660                      trace_EnumContexAllocFailed_OutOfMemory();
 661                      RecursiveLock_Release(&self->lock);
 662                      return 0;
 663 mike     1.1     }
 664 krisbash 1.3 
 665                  /* Store reference to a new context */
 666                  self->enumerateContexts[enumerationContextID] = enumContext;
 667                  self->enumerateContextDeleted[enumerationContextID] = MI_FALSE;
 668              
 669                  ++self->numEnumerateContexts;
 670                  
 671                  RecursiveLock_Release(&self->lock);
 672              
 673              
 674                  /* Add random data to the context-id */
 675                  enumerationContextID |= (rand() & 0xFFFF) << 16;
 676                  enumContext->enumerationContextID = enumerationContextID;
 677              
 678                  enumContext->wsman = self;
 679              
 680                  return enumContext;
 681 mike     1.1 }
 682              
 683              /************************************************************************\
 684              *   connection data operations
 685              \************************************************************************/
 686 krisbash 1.3 
 687              static WSMAN_EnumerateContext* _CD_CreateEnumContext(
 688                  WSMAN_ConnectionData* self)
 689              {
 690                  WSMAN_EnumerateContext* enumContext;
 691              
 692                  DEBUG_ASSERT( !self->strand.infoRight.opened || !self->strand.infoRight.thisAckPending );
 693                  DEBUG_ASSERT( !self->strand.infoRight.otherAckPending );
 694              
 695                  enumContext = _WSMAN_AllocateEnumContext( self->wsman, &self->strand.infoRight.interaction );
 696              
 697                  if( NULL != enumContext )
 698                  {
 699                      // Establish interaction opened with the enumeration context,
 700                      // (equivalent to what would happening after opening interaction with dispatcher and receiving an Ack)
 701                      self->strand.infoRight.opened = MI_TRUE;
 702                      self->strand.infoRight.thisAckPending = MI_FALSE;
 703                      self->strand.infoRight.thisClosedOther = MI_FALSE;
 704                      enumContext->strand.base.info.opened = MI_TRUE;
 705                      enumContext->strand.base.info.otherAckPending = MI_FALSE;
 706                      enumContext->strand.base.info.otherClosedThis = MI_FALSE;
 707 krisbash 1.3         // Also reset this so _EC_CheckCloseRight will properly close the CD
 708                      self->strand.infoRight.otherClosedThis = MI_FALSE;
 709              
 710                      /* link new context to current EnumRequest */
 711                      enumContext->activeConnection = self;
 712                  }
 713              
 714                  return enumContext;
 715              }
 716                  
 717 mike     1.1 MI_INLINE void _CD_SetPage(
 718 krisbash 1.3     WSMAN_ConnectionData* self,
 719 mike     1.1     Page*   page)
 720              {
 721 krisbash 1.3     if (self->page)
 722                      PAL_Free(self->page);
 723 mike     1.1 
 724 krisbash 1.3     self->page = page;
 725 mike     1.1 }
 726              
 727              MI_INLINE void _CD_SetSingleMessage(
 728                  WSMAN_ConnectionData* selfConnectionData,
 729 krisbash 1.3     Message* single_message)
 730 mike     1.1 {
 731                  if (selfConnectionData->single_message)
 732 krisbash 1.3         Message_Release(selfConnectionData->single_message);
 733 mike     1.1 
 734                  selfConnectionData->single_message = single_message;
 735              
 736                  if (selfConnectionData->single_message)
 737 krisbash 1.3         Message_AddRef(selfConnectionData->single_message);
 738 mike     1.1 }
 739              
 740              static void _CD_Cleanup(
 741                  WSMAN_ConnectionData* selfConnectionData)
 742              {
 743                  _CD_SetPage(selfConnectionData, 0);
 744                  _CD_SetSingleMessage(selfConnectionData, 0);
 745              
 746 krisbash 1.3     selfConnectionData->userAgent = USERAGENT_UNKNOWN;
 747              
 748              #if defined(CONFIG_ENABLE_HTTPHEADERS)
 749                  memset(selfConnectionData->headers, 0, sizeof(selfConnectionData->headers));
 750              #endif
 751              
 752 mike     1.1     /* free allocated instance/batch */
 753                  if (selfConnectionData->wsheader.instanceBatch)
 754                  {
 755                      /* destroying batch takes care of instance and instanceBatch members */
 756                      Batch_Destroy(selfConnectionData->wsheader.instanceBatch);
 757                      selfConnectionData->wsheader.instanceBatch = 0;
 758                      selfConnectionData->wsheader.instance = 0;
 759                  }
 760                  memset(&selfConnectionData->wsheader, 0, sizeof(selfConnectionData->wsheader));
 761 krisbash 1.3 
 762                  if (selfConnectionData->responseMessage)
 763                  {
 764                      Message_Release(selfConnectionData->responseMessage);
 765                      selfConnectionData->responseMessage = NULL;
 766                      // TODO: This is an un-acked message, but it cannot be acked since this is called from Finish
 767                  }
 768 mike     1.1 }
 769              
 770 krisbash 1.3 // Used for both WSMAN_ConnectionData and WSMAN_EnumerateContext
 771              static HttpResponseMsg* _PrepareResponseMsg(
 772                  int httpErrorCode,
 773                  Page* data)
 774 mike     1.1 {
 775 krisbash 1.3     HttpResponseMsg* msg;
 776                  
 777              #if defined(CONFIG_ENABLE_WCHAR)
 778              
 779                  if( NULL != data )
 780 mike     1.1     {
 781 krisbash 1.3         /* Convert page to wire XML character representation */
 782              
 783                      size_t count = data->u.s.size / sizeof(ZChar);
 784                      ZChar* src = (ZChar*)(data + 1);
 785                      size_t firstNonAscii = 0; // temp variable used by this conversion function between two passes
 786                      Page* page = NULL;
 787                      int neededSpace = 0;
 788                      
 789                      neededSpace = ConvertWideCharToMultiByte(
 790                                      src,
 791                                      count,
 792                                      &firstNonAscii,
 793                                      NULL,
 794                                      neededSpace);
 795 mike     1.1 
 796 krisbash 1.3         // output string would not be smaller than input
 797                      if(neededSpace < (int)count)
 798                      {
 799                          PAL_Free(data);
 800                          trace_Wsman_HttpResponseMsg_ConversionError();
 801                          return NULL;
 802                      }
 803 mike     1.1 
 804 krisbash 1.3         page = (Page*)PAL_Malloc(sizeof(Page) + (neededSpace * sizeof(char)));
 805 mike     1.1 
 806 krisbash 1.3         if (!page)
 807                      {
 808                          trace_Wsman_HttpResponseMsgPage_AllocError( httpErrorCode );
 809                          PAL_Free(data);
 810                          return NULL;
 811                      }
 812 mike     1.1         
 813 krisbash 1.3         memset(page, 0, sizeof(Page));
 814                      page->u.s.size = neededSpace;
 815 mike     1.1 
 816 krisbash 1.3         neededSpace = ConvertWideCharToMultiByte(
 817                                      src,
 818                                      count,
 819                                      &firstNonAscii,
 820                                      (Utf8Char *)(page + 1),
 821                                      neededSpace);
 822 mike     1.1 
 823 krisbash 1.3         // previously computed length must be equal to the neededSpace
 824                      if(neededSpace != page->u.s.size)
 825                      {
 826                          PAL_Free(data);
 827                          trace_Wsman_HttpResponseMsg_ConversionError();
 828                          return NULL;
 829                      }
 830 mike     1.1 
 831 krisbash 1.3 #if 0
 832                      Tprintf(ZT("PAGE{%.*s}"), (int)(page->u.s.size), (char*)(page + 1));
 833              #endif
 834 mike     1.1 
 835 krisbash 1.3         PAL_Free(data);
 836 mike     1.1         
 837 krisbash 1.3         data = page;
 838                  }
 839 mike     1.1 
 840 krisbash 1.3 #endif /* !defined(CONFIG_ENABLE_WCHAR) */
 841 mike     1.1 
 842 krisbash 1.3     msg = HttpResponseMsg_New(data, httpErrorCode);
 843 mike     1.1 
 844 krisbash 1.3     if( NULL == msg )
 845                  {
 846                      trace_Wsman_HttpResponseMsg_AllocError( httpErrorCode );
 847                      
 848                      if (data)
 849                      {
 850                          PAL_Free(data);
 851                      }
 852                  }
 853                  
 854                  return msg;
 855 mike     1.1 }
 856              
 857 krisbash 1.3 MI_Result _SendResponse(
 858                  StrandBoth* self,
 859                  int httpErrorCode,
 860                  Page* data)
 861              {
 862                  HttpResponseMsg* msg;
 863 mike     1.1 
 864 krisbash 1.3     STRAND_ASSERTONSTRAND(&self->base);
 865 mike     1.1 
 866 krisbash 1.3     msg = _PrepareResponseMsg( httpErrorCode, data );
 867                  
 868                  if( NULL != msg )
 869                  {
 870                      StrandBoth_PostLeft( self, &msg->base);
 871                      
 872                      HttpResponseMsg_Release( msg);
 873                      
 874                      return MI_RESULT_OK;
 875                  }
 876                  else
 877 mike     1.1     {
 878 krisbash 1.3         return MI_RESULT_FAILED;
 879                  }
 880              }
 881              
 882              MI_INLINE
 883              MI_Result _EC_SendResponse(
 884                  WSMAN_EnumerateContext* selfEC,
 885                  int httpErrorCode,
 886                  Page* data)
 887              {
 888                  return _SendResponse( &selfEC->strand, httpErrorCode, data );
 889              }
 890              
 891              MI_INLINE
 892              MI_Result _CD_SendResponse(
 893                  WSMAN_ConnectionData* selfCD,
 894                  int httpErrorCode,
 895                  Page* data)
 896              {
 897                  selfCD->outstandingRequest = MI_FALSE;
 898                  return _SendResponse( &selfCD->strand, httpErrorCode, data );
 899 krisbash 1.3 }
 900              
 901              MI_INLINE MI_Result _CD_SendErrorFailedResponse(
 902                  _In_    WSMAN_ConnectionData*   selfCD,
 903                          int                     httpErrorCode )
 904              {
 905                  return _CD_SendResponse(
 906                              selfCD,
 907                              httpErrorCode,
 908                              NULL);
 909              }
 910              
 911              MI_INLINE MI_Result _CD_SendFailedResponse(
 912                  _In_    WSMAN_ConnectionData*   selfCD )
 913              {
 914                  return _CD_SendErrorFailedResponse(
 915                              selfCD,
 916                              HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
 917              }
 918              
 919              // Used for both WSMAN_ConnectionData and WSMAN_EnumerateContext (sendOnDifferentStrand is indicated in that case)
 920 krisbash 1.3 static void _SendCimFaultResponse(
 921                  _In_                WSMAN_ConnectionData*   selfCD, 
 922                  _In_opt_            WSMAN_EnumerateContext* sendOnECStrand,
 923                                      WSBUF_FAULT_CODE        faultCode,
 924                  _In_                const PostResultMsg*    message)
 925              {
 926                  MI_Result result;
 927                  
 928                  Page* responsePage = WSBuf_CreateFaultResponsePage(
 929                      faultCode,
 930                      selfCD->wsheader.unknownMandatoryTag,
 931                      selfCD->wsheader.rqtMessageID,
 932                      message);
 933              
 934                  if( NULL == sendOnECStrand )
 935                  {
 936                      STRAND_ASSERTONSTRAND(&selfCD->strand.base);
 937              
 938                      result = _CD_SendResponse(
 939                          selfCD,
 940                          HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR,
 941 krisbash 1.3             responsePage);
 942                  }
 943                  else
 944                  {
 945                      STRAND_ASSERTONSTRAND(&sendOnECStrand->strand.base);
 946                  
 947                      result = _EC_SendResponse(
 948                          sendOnECStrand,
 949                          HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR,
 950                          responsePage);
 951                  }
 952              
 953                  DEBUG_ASSERT( MI_RESULT_OK == result );
 954              }
 955              
 956              static void _CD_SendFaultResponse(
 957                  _In_                WSMAN_ConnectionData*   selfCD, 
 958                  _In_opt_            WSMAN_EnumerateContext* sendOnECStrand,
 959                                      WSBUF_FAULT_CODE        faultCode,
 960                  _In_                const ZChar*            descriptionText)
 961              {
 962 krisbash 1.3     /* This method is called when there is Non-Cim error occured ... 
 963                   * so sending MI_RESULT_OK
 964                   */
 965                  PostResultMsg message;
 966              
 967                  memset(&message, 0, sizeof(message));
 968                  message.result = MI_RESULT_OK;
 969                  message.errorMessage = descriptionText;
 970              
 971                  _SendCimFaultResponse(
 972                      selfCD, 
 973                      sendOnECStrand,
 974                      faultCode, 
 975                      &message);
 976              }
 977              
 978              static void _CD_SendReleaseResponse(
 979                  WSMAN_ConnectionData* selfCD)
 980              {
 981                  Page* responsePage = WSBuf_CreateReleaseResponsePage(
 982                      selfCD->wsheader.rqtMessageID);
 983 krisbash 1.3         
 984                  STRAND_ASSERTONSTRAND(&selfCD->strand.base);
 985              
 986                  _CD_SendResponse(selfCD,
 987                      HTTP_ERROR_CODE_OK, 
 988                      responsePage);
 989              }
 990              
 991              static void _CD_ProcessEnumFailedWithResult(
 992                  _In_    WSMAN_ConnectionData*   self,
 993                  _In_    WSMAN_EnumerateContext* enumContext,
 994                          MI_Result               result )
 995              {
 996                  _WSMAN_ReleaseEnumerateContext(self->wsman, enumContext->enumerationContextID);
 997                  if( MI_RESULT_OK == result )
 998                  {
 999                      // In this case we are calling from the CD strand
1000                      STRAND_ASSERTONSTRAND(&self->strand.base);
1001                      _CD_SendFailedResponse(self);
1002                      _EC_CloseLeft( enumContext, MI_TRUE );
1003                  }
1004 krisbash 1.3     else
1005                  {
1006                      // In this case we are calling from the EC strand
1007                      STRAND_ASSERTONSTRAND(&enumContext->strand.base);
1008                      _SendErrorResultResponse( self, enumContext, result );
1009                      _EC_CloseLeft( enumContext, MI_FALSE );
1010                  }
1011                  // force close state so the strand will delete itself
1012                  Strand_ForceClose( &enumContext->strand.infoRight );
1013                  enumContext->ecTimer.cancelledTimer = MI_TRUE;
1014                  Strand_FireTimer( &enumContext->strand.base );
1015              }
1016              
1017              static void _CD_ProcessEnumFailed(
1018                  _In_    WSMAN_ConnectionData*   self,
1019                  _In_    WSMAN_EnumerateContext* enumContext )
1020              {
1021                  _CD_ProcessEnumFailedWithResult( self, enumContext, MI_RESULT_OK );
1022              }
1023              
1024              static int _ValidateHeader(
1025 krisbash 1.3     WSMAN_ConnectionData* selfCD)
1026              {
1027                  STRAND_ASSERTONSTRAND(&selfCD->strand.base);
1028              
1029                  if (selfCD->wsheader.unknownMandatoryTag)
1030                  {
1031                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_NOT_UNDERSTOOD, 0);
1032                      return -1;
1033 mike     1.1     }
1034              
1035                  //DSP0226
1036                  //1756 R6.2-4: Services should reject any MaxEnvelopeSize value less than 8192 octets. This number
1037                  //1757 is the safe minimum in which faults can be reliably encoded for all character sets. If the requested
1038                  //1758 size is less than this, the service should return a wsman:EncodingLimit fault with the following
1039                  //1759 detail code:
1040                  //1760 http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/MinimumEnvelopeLimit
1041              
1042                  if (selfCD->wsheader.maxEnvelopeSize != 0 &&
1043                      selfCD->wsheader.maxEnvelopeSize < 8192)
1044                  {
1045 krisbash 1.3         trace_Wsman_RequestedEnvelopeSizeIsTooSmall((int)selfCD->wsheader.maxEnvelopeSize);
1046                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_ENCODING_LIMIT, 0);
1047 mike     1.1         return -1;
1048                  }
1049              
1050                  /* Limit envelope size to server's max */
1051                  if (selfCD->wsheader.maxEnvelopeSize == 0 ||
1052                      selfCD->wsheader.maxEnvelopeSize > WSMAN_MAX_ENVELOPE_SIZE)
1053                  {
1054                      selfCD->wsheader.maxEnvelopeSize = WSMAN_MAX_ENVELOPE_SIZE;
1055                  }
1056              
1057 krisbash 1.3     /* Confirm appropriate OperationTimeout (if specified).
1058                   * This check determines if xs:date was sent instead.
1059                   * Conforms to R6.1-2 "Should" */
1060                  if (selfCD->wsheader.operationTimeout.exists &&
1061                      selfCD->wsheader.operationTimeout.value.isTimestamp )
1062                  {
1063                      trace_Wsman_InvalidOperationTimeoutValue_Timestamp();
1064                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INVALID_MESSAGE_INFORMATION_HEADER, 
1065                          ZT("OperationTimeout must be xs:duration if specified"));
1066                      return -1;        
1067                  }
1068              
1069 mike     1.1     /* verify action for invoke */
1070                  if (selfCD->wsheader.foundAction &&
1071                      0 == selfCD->wsheader.rqtAction &&
1072                      (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtMethod))
1073                  {
1074 krisbash 1.3         trace_Wsman_UnknownCustomAction();
1075              
1076                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_NOT_SUPPORTED, 
1077                          ZT("unknown custom action"));
1078                      return -1;
1079                  }
1080              
1081                  /* Reject unsupported actions:
1082                   * 1 - GetStatus
1083                   * 2 - Renew */
1084                  if (WSMANTAG_ACTION_RENEW == selfCD->wsheader.rqtAction ||
1085                      WSMANTAG_ACTION_GETSTATUS == selfCD->wsheader.rqtAction)
1086                  {
1087                      trace_Wsman_InvalidActionRequest();
1088 mike     1.1 
1089 krisbash 1.3         _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_ACTION_NOT_SUPPORTED, 
1090                          ZT("Unsupported action requested."));
1091 mike     1.1         return -1;
1092                  }
1093              
1094                  return 0;
1095              }
1096              
1097              static int _ValidateEnumerateRequest(
1098                  WSMAN_ConnectionData* selfCD)
1099              {
1100                  /* If it has reference params, it must be an association request */
1101                  MI_Instance* referenceParameters = 
1102                      selfCD->u.wsenumpullbody.associationFilter.referenceParameters;
1103              
1104 krisbash 1.3     STRAND_ASSERTONSTRAND(&selfCD->strand.base);
1105              
1106 mike     1.1     if (referenceParameters)
1107                  {
1108                      selfCD->wsheader.rqtNamespace = referenceParameters->nameSpace;
1109                      selfCD->wsheader.rqtClassname = referenceParameters->classDecl->name;
1110                  }
1111                  else if (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtNamespace)
1112                  {
1113 krisbash 1.3 #if defined(CONFIG_OS_WINDOWS)
1114                      trace_WsmanEnum_ParametersMissing();
1115              
1116                      _CD_SendFaultResponse(
1117                          selfCD, 
1118                          NULL,
1119                          WSBUF_FAULT_INTERNAL_ERROR, 
1120                          ZT("mandatory parameters (className, namespace) ")
1121                              ZT("are missing for enumerate request"));
1122              #else
1123                      trace_WsmanEnum_ParametersMissing();
1124 mike     1.1 
1125 krisbash 1.3         _CD_SendFaultResponse(
1126 mike     1.1             selfCD, 
1127 krisbash 1.3             NULL,
1128 mike     1.1             WSBUF_FAULT_INTERNAL_ERROR, 
1129 krisbash 1.3             ZT("mandatory parameters (className, namespace) "
1130 mike     1.1                 "are missing for enumerate request"));
1131 krisbash 1.3 #endif
1132 mike     1.1         return -1;
1133                  }
1134              
1135                  //R8.2.3; DSP226
1136                  //wsmen:Enumerate/wsman:MaxElements
1137                  //(optional) indicates the maximum number of items the consumer is willing to accept in the
1138                  //EnumerateResponse
1139                  //It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
1140                  //implied value is 1.
1141                  if (!selfCD->u.wsenumpullbody.maxElements)
1142                      selfCD->u.wsenumpullbody.maxElements = 1;
1143              
1144                  // if enumeration mode is not specified, use 'Objects'
1145                  if (selfCD->u.wsenumpullbody.enumerationMode == 0)
1146                      selfCD->u.wsenumpullbody.enumerationMode = WSMANTAG_ENUM_MODE_OBJECT;
1147              
1148                  return 0;
1149              }
1150              
1151              static int _ValidatePullRequest(
1152                  WSMAN_ConnectionData* selfCD)
1153 mike     1.1 {
1154 krisbash 1.3     STRAND_ASSERTONSTRAND(&selfCD->strand.base);
1155              
1156 mike     1.1     //R8.2.3; DSP226
1157                  //wsmen:Enumerate/wsman:MaxElements
1158                  //(optional) indicates the maximum number of items the consumer is willing to accept in the
1159                  //EnumerateResponse
1160                  //It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
1161                  //implied value is 1.
1162                  if (!selfCD->u.wsenumpullbody.maxElements)
1163                      selfCD->u.wsenumpullbody.maxElements = 1;
1164              
1165 krisbash 1.3     if (selfCD->u.wsenumpullbody.maxTime.exists)
1166                  {
1167                      MI_Uint64 durationInUsec = 0;
1168                      DatetimeToUsec( &selfCD->u.wsenumpullbody.maxTime.value, &durationInUsec );
1169              
1170                      if (0 == durationInUsec)
1171                      {
1172                          trace_Wsman_PullRequest_InvalidMaxTimeValue();
1173                          _CD_SendFaultResponse(
1174                              selfCD, 
1175                              NULL,
1176                              WSBUF_FAULT_INVALID_EXPIRATION_TIME, 
1177                              ZT("Maxtime cannot be zero if specified"));
1178                          return -1;
1179                      }
1180                  }
1181              
1182 mike     1.1     return 0;
1183              }
1184              
1185 krisbash 1.3 #if defined(CONFIG_ENABLE_HTTPHEADERS)
1186              static void _FixupHTTPHeaderName(ZChar* name)
1187              {
1188                  while (*name)
1189                  {
1190                      ZChar c = *name;
1191              
1192                      if (!isalnum(c) && c != '_')
1193                          *name = '_';
1194              
1195                      name++;
1196                  }
1197              }
1198              #endif /* defined(CONFIG_ENABLE_HTTPHEADERS) */
1199              
1200              
1201              /* Create msg->options instance to represent HTTP headers */
1202              static MI_Result _GetHTTPHeaderOpts(
1203                  WSMAN_ConnectionData* selfCD,
1204                  RequestMsg* msg)
1205              {
1206 krisbash 1.3 #if defined(CONFIG_ENABLE_HTTPHEADERS)
1207              
1208                  MI_Instance* options;
1209                  MI_Result r;
1210                  size_t i;
1211              
1212                  /* Don't create instance if there are no HTTP headers */
1213                  if (selfCD->headersSize == 0)
1214                      return MI_RESULT_OK;
1215              
1216                  /* Create new instance to represent options */
1217              
1218                  r = Instance_NewDynamic(&options, MI_T("Options"), MI_FLAG_CLASS,
1219                      msg->base.batch);
1220              
1221                  if (r == MI_RESULT_FAILED || options == NULL)
1222                      return MI_RESULT_FAILED;
1223              
1224                  /* Add string options for each of the HTTP headers */
1225              
1226                  for (i = 0; i < selfCD->headersSize; i++)
1227 krisbash 1.3     {
1228                      MI_Value v;
1229                      ZChar name[128];
1230                      ZChar value[128];
1231              
1232                      Tcslcpy(name, MI_T("HTTP_"), MI_COUNT(name));
1233                      TcsStrlcat(name, selfCD->headers[i].name, MI_COUNT(name));
1234              
1235                      _FixupHTTPHeaderName(name);
1236              
1237                      Tcslcpy(value, selfCD->headers[i].value, MI_COUNT(value));
1238              
1239                      v.string = value;
1240              
1241                      r = __MI_Instance_AddElement(
1242                          options,
1243                          name,
1244                          &v,
1245                          MI_STRING,
1246                          0);
1247              
1248 krisbash 1.3         if (r != MI_RESULT_OK)
1249                          return r;
1250                  }
1251              
1252                  msg->options = options;
1253              
1254              
1255              #endif /* defined(CONFIG_ENABLE_HTTPHEADERS) */
1256              
1257                  return MI_RESULT_OK;
1258              }
1259              
1260              
1261              /* Converts the WSMAN options into "Message" struct flag */
1262              MI_INLINE   MI_Uint32 _GetFlagsFromWsmanOptions(
1263                      WSMAN_ConnectionData* selfCD )
1264              {
1265                  MI_Uint32 flags = 0;
1266              
1267                  if(selfCD->wsheader.includeClassOrigin)
1268                      flags |= WSMAN_IncludeClassOrigin;
1269 krisbash 1.3 
1270                  if(selfCD->wsheader.includeInheritanceHierarchy)
1271                      flags |= WSMAN_IncludeInheritanceHierarchy;
1272              
1273                  if(selfCD->wsheader.includeInheritedElements)
1274                      flags |= WSMAN_IncludeInheritedElements;
1275              
1276                  if(selfCD->wsheader.includeQualifiers)
1277                      flags |= WSMAN_IncludeQualifiers;
1278              
1279                  if(selfCD->wsheader.usePreciseArrays)
1280                      flags |= WSMAN_UsePreciseArrays;
1281              
1282                  trace_GetFlagsFromWsmanOptions(
1283                          (flags & WSMAN_IncludeClassOrigin) != 0,
1284                          (flags & WSMAN_IncludeInheritanceHierarchy) != 0,
1285                          (flags & WSMAN_IncludeInheritedElements) != 0,
1286                          (flags & WSMAN_IncludeQualifiers) != 0,
1287                          (flags & WSMAN_UsePreciseArrays) != 0);
1288                  return flags;
1289              }
1290 krisbash 1.3 
1291              
1292              // open interaction with the part on the right (usually dispatcher)
1293              static void _OpenRight_Imp(
1294                  _In_    StrandBoth*             strand,
1295                  _In_    WSMAN*                  wsman,
1296                  _In_    RequestMsg*             msg )
1297              {
1298                  if( !strand->infoRight.opened )    
1299                  {
1300                      // If this is the first time we used this CD it will be waiting an Open already
1301                      strand->infoRight.thisAckPending = MI_FALSE;
1302                  }
1303                  else
1304                  {
1305                      DEBUG_ASSERT( !strand->infoRight.thisAckPending );
1306                  }
1307                  
1308                  // This give the ability to steal the strand if the open completes, 
1309                  // otherwise any Post in the same thread will be delayed
1310                  // and the stack will eventually deadlock on in-proc providers that send
1311 krisbash 1.3     // several posts in the same open thread
1312                  StrandBoth_Open( strand, wsman->callback, wsman->callbackData, &msg->base, MI_TRUE, MI_FALSE );
1313                  // Operation can be already started (note that the strand is abandoned at this point)
1314              }
1315              
1316              /* Return value of zero means that it is not specified and should not be used. 
1317               * Otherwise a value will be provided. */
1318              static MI_Uint64 _GetTimeoutFromConnectionData(
1319                  WSMAN_ConnectionData* self)
1320              {
1321                  MI_Uint64 timeoutUsec = 0;
1322              
1323                  if (self->wsheader.operationTimeout.exists ||   /* Common to all operations */
1324                      self->u.wsenumpullbody.maxTime.exists)      /* Only for PULL operations */
1325                  {
1326                      /* A timeout was specified. Determine the correct value to use
1327                       * or use the default. 
1328                       * Note: OperationTimeout has precendence when both are specified. */
1329                      if (self->wsheader.operationTimeout.exists)
1330                      {
1331                          DatetimeToUsec(&self->wsheader.operationTimeout.value, &timeoutUsec);
1332 krisbash 1.3         }
1333                      else
1334                      {
1335                          DatetimeToUsec(&self->u.wsenumpullbody.maxTime.value, &timeoutUsec);
1336                      }
1337              
1338                      if (0 == timeoutUsec)
1339                      {
1340                          /* Unable to parse.  Use default instead */
1341                          timeoutUsec = WSMAN_TIMEOUT_DEFAULT;
1342              #if defined(_MSC_VER)
1343                          trace_Wsman_UnableToconvertDatetimeToUsec_MSCVER( timeoutUsec, self->wsheader.rqtAction );
1344              #else
1345                          trace_Wsman_UnableToconvertDatetimeToUsec_POSIX( timeoutUsec, self->wsheader.rqtAction );
1346              #endif
1347                      }
1348                  }
1349                  return timeoutUsec;
1350              }
1351              
1352              /* Starts a timer on the CD strand if one was specified in the request. */
1353 krisbash 1.3 static void _CD_StartTimer(
1354                  WSMAN_ConnectionData* self)
1355              {
1356                  MI_Uint64 timeoutInUsec = _GetTimeoutFromConnectionData(self);
1357              
1358                  if (0 != timeoutInUsec)
1359                  {
1360                      Strand_StartTimer( &self->strand.base, &self->cdTimer.timer, timeoutInUsec );
1361                  }
1362              }
1363              
1364              MI_INLINE
1365              void _OpenRightSingle(
1366                  _In_    WSMAN_ConnectionData*   self,
1367                  _In_    RequestMsg*             msg )
1368              {
1369              #if defined(CONFIG_OS_WINDOWS)
1370                  // TODO: Remove OS-specific check once OMI is multi-threaded
1371                  /* Timers cannot be supported for non-complex operations in OMI until it
1372                   * becomes multi-threaded.  This check limits support to Windows and should
1373                   * be removed once OMI is multi-threaded.
1374 krisbash 1.3      */
1375                  // TODO: Re-enable once the logic is debugged in OMI
1376                  //_CD_StartTimer( self );
1377              #endif
1378              
1379                  _OpenRight_Imp( &self->strand, self->wsman, msg );
1380              }
1381              
1382              static void _OpenRightEnum(
1383                  _In_    WSMAN_ConnectionData*   self,
1384                  _In_    WSMAN_EnumerateContext* enumContext,
1385                  _In_    RequestMsg*             msg,
1386                          MI_Boolean              updateTimer )
1387              {
1388                  // Do this while still in the CD strand for safety
1389              
1390              #if defined(CONFIG_OS_WINDOWS)
1391                  // TODO: Remove OS-specific check once OMI is multi-threaded
1392                  /* Timers cannot be supported for non-complex operations in OMI until it
1393                   * becomes multi-threaded.  This check limits support to Windows and should
1394                   * be removed once OMI is multi-threaded.
1395 krisbash 1.3      */
1396                  // TODO: Re-enable once the logic is debugged in OMI
1397                  // self->enumCtxId = enumContext->enumerationContextID;
1398                  //_CD_StartTimer( self );
1399              #else
1400                  // TODO: Remove this else once OMI is multi-threaded
1401                  // In Linux and Unix, only start the CD timer if the operation is a subscribe
1402                  // request. All other complex operations will not support timers until OMI
1403                  // is multi-threaded.
1404                  if (WSMANTAG_ACTION_SUBSCRIBE == self->wsheader.rqtAction)
1405                  {
1406                      self->enumCtxId = enumContext->enumerationContextID;
1407                      _CD_StartTimer( self );
1408                  }
1409              #endif
1410              
1411                  // Leave CD strand first, otherwise any Post in the same thread will be delayed
1412                  // and the stack will eventually deadlock on in-proc providers that send
1413                  // several posts in the same open thread
1414                  Strand_Leave( &self->strand.base );
1415              
1416 krisbash 1.3     // Now we are just on the enum context strand
1417                  _OpenRight_Imp( &enumContext->strand, enumContext->wsman, msg );
1418              }
1419              
1420 mike     1.1 static void _ProcessEnumerateRequest(
1421                  WSMAN_ConnectionData* selfCD)
1422              {
1423                  EnumerateInstancesReq* msg;
1424                  WSMAN_EnumerateContext* enumContext;
1425 krisbash 1.3     MI_Boolean updateTimer = MI_FALSE;
1426              
1427                  STRAND_ASSERTONSTRAND(&selfCD->strand.base);
1428 mike     1.1 
1429                  /* create EnumerateContext */
1430 krisbash 1.3     enumContext = _CD_CreateEnumContext(selfCD);
1431 mike     1.1 
1432                  if (!enumContext)
1433                  {
1434 krisbash 1.3         _CD_SendFailedResponse(selfCD);
1435 mike     1.1         return;
1436                  }
1437              
1438                  // Create new request.
1439 krisbash 1.3     msg = EnumerateInstancesReq_New(_NextOperationID(), 
1440                      WSMANFlag | _convertWSMANtoMsgEnumerationMode(selfCD->u.wsenumpullbody.enumerationMode) | _GetFlagsFromWsmanOptions(selfCD));
1441 mike     1.1 
1442 krisbash 1.3     if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
1443 mike     1.1     {
1444 krisbash 1.3         _CD_ProcessEnumFailed( selfCD, enumContext );
1445 mike     1.1         return;
1446                  }
1447              
1448 krisbash 1.3     /* Set the user agent */
1449                  msg->base.userAgent = selfCD->userAgent;
1450              
1451 mike     1.1     /* In case when client does not support optimized enumeration,
1452                      send empty Enum-response with correct enumerate context */
1453                  if (!selfCD->u.wsenumpullbody.allowOptimization)
1454                  {   
1455 krisbash 1.3         _SendEnumPullResponse(enumContext, MI_TRUE);
1456                      updateTimer = MI_TRUE;
1457                  }
1458              
1459                  msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
1460                  msg->className = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtClassname);
1461              
1462                  if (!msg->className || !msg->nameSpace)
1463                  {
1464                      _CD_ProcessEnumFailed( selfCD, enumContext );
1465                      EnumerateInstancesReq_Release(msg);
1466                      return;
1467 mike     1.1     }
1468              
1469                  msg->deepInheritance = (selfCD->u.wsenumpullbody.polymorphismMode != WSMANTAG_ENUM_POLYMORPHISM_MODE_NONE);
1470                  msg->basePropertiesOnly = (selfCD->u.wsenumpullbody.polymorphismMode == WSMANTAG_ENUM_POLYMORPHISM_MODE_EXCLUDE_PROPS);
1471              
1472                  /* Set the query related fields */
1473                  {
1474                      if (selfCD->u.wsenumpullbody.dialect)
1475 krisbash 1.3         {
1476                          msg->queryLanguage = Batch_Tcsdup(msg->base.base.batch, selfCD->u.wsenumpullbody.dialect);
1477                          if (!msg->queryLanguage)
1478                          {
1479                              _CD_ProcessEnumFailed( selfCD, enumContext );
1480                              EnumerateInstancesReq_Release(msg);
1481                              return;
1482                          }
1483                      }
1484 mike     1.1 
1485                      if (selfCD->u.wsenumpullbody.filter)
1486 krisbash 1.3         {
1487                          msg->queryExpression = Batch_Tcsdup(msg->base.base.batch, selfCD->u.wsenumpullbody.filter);
1488                          if (!msg->queryExpression)
1489                          {
1490                              _CD_ProcessEnumFailed( selfCD, enumContext );
1491                              EnumerateInstancesReq_Release(msg);
1492                              return;
1493                          }
1494                      }
1495 mike     1.1     }
1496              
1497 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
1498 mike     1.1 
1499 krisbash 1.3     _OpenRightEnum(selfCD,enumContext,&msg->base,updateTimer);
1500                  
1501 mike     1.1     EnumerateInstancesReq_Release(msg);
1502              }
1503              
1504              static void _ProcessAssociatorsRequest(
1505                  WSMAN_ConnectionData* selfCD)
1506              {
1507 krisbash 1.3     AssociationsOfReq* msg;
1508 mike     1.1     WSMAN_EnumerateContext* enumContext;
1509                  MI_Uint32 enumerationMode;
1510 krisbash 1.3     MI_Boolean updateTimer = MI_FALSE;
1511 mike     1.1 
1512                  /* create EnumerateContext */
1513 krisbash 1.3     enumContext = _CD_CreateEnumContext(selfCD);
1514 mike     1.1 
1515                  if (!enumContext)
1516                  {
1517 krisbash 1.3         _CD_SendFailedResponse(selfCD);
1518 mike     1.1         return;
1519                  }
1520              
1521 krisbash 1.3     /* Extract the enumeration mode */
1522 mike     1.1     enumerationMode = _convertWSMANtoMsgEnumerationMode(
1523                      selfCD->u.wsenumpullbody.enumerationMode);
1524              
1525                  /* Create new request. */
1526 krisbash 1.3 
1527                  msg = AssociationsOfReq_New(
1528                      _NextOperationID(),
1529                      WSMANFlag | enumerationMode | _GetFlagsFromWsmanOptions(selfCD),
1530                      (selfCD->u.wsenumpullbody.associationFilter.isAssosiatorOperation == MI_TRUE) ? AssociatorsOfReqTag : ReferencesOfReqTag);
1531              
1532                  if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
1533                  {
1534                      _CD_ProcessEnumFailed( selfCD, enumContext );
1535 mike     1.1         return;
1536                  }
1537              
1538 krisbash 1.3     /* Set the user agent */
1539                  msg->base.userAgent = selfCD->userAgent;
1540              
1541 mike     1.1     /* In case when client does not support optimized enumeration,
1542                   *  send empty Enum-response with correct enumerate context 
1543                   */
1544                  if (!selfCD->u.wsenumpullbody.allowOptimization)
1545                  {
1546 krisbash 1.3         _SendEnumPullResponse(enumContext, MI_TRUE);
1547                      updateTimer = MI_TRUE;
1548 mike     1.1     }
1549              
1550 krisbash 1.3     msg->nameSpace = Batch_Tcsdup(
1551                      msg->base.base.batch, 
1552 mike     1.1         selfCD->wsheader.rqtNamespace);
1553              
1554 krisbash 1.3     msg->className = Batch_Tcsdup(
1555                      msg->base.base.batch, 
1556 mike     1.1         selfCD->wsheader.rqtClassname);
1557              
1558 krisbash 1.3     if (!msg->nameSpace || !msg->className)
1559                  {
1560                      _CD_ProcessEnumFailed( selfCD, enumContext );
1561                      AssociationsOfReq_Release(msg);
1562                      return;
1563                  }
1564              
1565                  AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
1566 mike     1.1 
1567                  /* Set messages fileds from association filter */
1568                  {
1569                      WSMAN_AssociationFilter* filter = 
1570                          &selfCD->u.wsenumpullbody.associationFilter;
1571              
1572                      msg->instance = filter->referenceParameters;
1573 krisbash 1.3         msg->role = filter->role;
1574 mike     1.1         msg->resultClass = filter->resultClassName;
1575 krisbash 1.3 
1576                      if (filter->isAssosiatorOperation == MI_TRUE)
1577                      {
1578                          msg->assocClass = filter->associationClassName;
1579                          msg->resultRole = filter->resultRole;
1580                      }
1581 mike     1.1     }
1582              
1583 krisbash 1.3     _OpenRightEnum(selfCD,enumContext,&msg->base,updateTimer);
1584 mike     1.1 
1585 krisbash 1.3     AssociationsOfReq_Release(msg);
1586              }
1587 mike     1.1 
1588              
1589 krisbash 1.3 static void _CD_ForceCloseRight(
1590                  _In_ WSMAN_ConnectionData* self)
1591              {
1592                  STRAND_ASSERTONSTRAND(&self->strand.base);
1593                  
1594                  // Set this manually since we are not going to open anything to the right
1595                  self->strand.infoRight.thisAckPending = MI_FALSE;
1596                  self->strand.infoRight.thisClosedOther = MI_TRUE;
1597                  self->strand.infoRight.otherClosedThis = MI_TRUE;
1598 mike     1.1 }
1599              
1600              static void _ProcessPullRequest(
1601                  WSMAN_ConnectionData* selfCD)
1602              {
1603                  WSMAN_EnumerateContext* enumContext;
1604              
1605                  /* find EnumerateContext */
1606 krisbash 1.3     enumContext = _WSMAN_FindEnumContext(selfCD->wsman, selfCD->u.wsenumpullbody.enumerationContextID);
1607 mike     1.1 
1608                  if (!enumContext)
1609                  {
1610 krisbash 1.3         _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_DESTINATION_UNREACHABLE, ZT("Enumeration context not found"));
1611                      _CD_ForceCloseRight(selfCD);
1612 mike     1.1         return;
1613                  }
1614              
1615                  /* link new context to the request */
1616 krisbash 1.3     if (Atomic_CompareAndSwap((ptrdiff_t*)&enumContext->attachingConnection, 0, (ptrdiff_t)selfCD) == 0)
1617                  {
1618                      // We are about to reopen
1619                      StrandBoth_StartOpenAsync( &selfCD->strand );
1620 mike     1.1 
1621 krisbash 1.3 #if defined(CONFIG_OS_WINDOWS)
1622                      // TODO: Remove OS-specific check once OMI is multi-threaded
1623                      /* Timers cannot be supported for non-complex operations in OMI until it
1624                       * becomes multi-threaded.  This check limits support to Windows and should
1625                       * be removed once OMI is multi-threaded.
1626                       */
1627                      // TODO: Re-enable once the logic is debugged in OMI
1628                      //_CD_StartTimer( selfCD );
1629              #else
1630                      // TODO: Remove this else once OMI is multi-threaded
1631                      // In Linux and Unix, only start the CD timer if the operation is a Pull
1632                      // request for a Subscribe EC. All other complex operations will not 
1633                      // support timers until OMI is multi-threaded.
1634                      if (SubscribeReqTag == enumContext->data.requestTag)
1635                      {
1636                          _CD_StartTimer( selfCD );
1637                      }
1638              #endif
1639                 
1640                      //TODO: make sure there is no other pull attached
1641                      StrandBoth_ScheduleAuxLeft(&enumContext->strand,ENUMERATIONCONTEXT_STRANDAUX_PULLATTACHED);
1642 krisbash 1.3     }
1643                  else
1644                  {
1645                      //one other pull is already registered
1646                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INTERNAL_ERROR, ZT("Discarding illegitimate Pull request"));
1647                      _CD_ForceCloseRight(selfCD);
1648                      return;
1649                  }
1650 mike     1.1 }
1651              
1652              static void _ProcessReleaseRequest(
1653                  WSMAN_ConnectionData* selfCD)
1654              {
1655                  WSMAN_EnumerateContext* enumContext;
1656              
1657 krisbash 1.3     // We are not going to open anything to the right anyway
1658                  _CD_ForceCloseRight(selfCD);
1659                  
1660 mike     1.1     /* find EnumerateContext */
1661 krisbash 1.3     enumContext = _WSMAN_FindAndDeleteEnumContext(selfCD->wsman, selfCD->u.wsenumpullbody.enumerationContextID);
1662 mike     1.1 
1663                  if (!enumContext)
1664                  {
1665 krisbash 1.3         _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_DESTINATION_UNREACHABLE, ZT("Enumeration context not found"));
1666 mike     1.1         return;
1667                  }
1668              
1669 krisbash 1.3     trace_Wsman_ProcessReleaseRequest( selfCD->u.wsenumpullbody.enumerationContextID );
1670                  
1671                  // Remove it and also cancel anything outgoing
1672                  StrandBoth_ScheduleCancel(&enumContext->strand);
1673 mike     1.1 
1674 krisbash 1.3     _CD_SendReleaseResponse(selfCD);
1675 mike     1.1 }
1676              
1677              static void _ParseValidateProcessEnumerateRequest(
1678                  WSMAN_ConnectionData* selfCD,
1679                  XML*    xml)
1680              {
1681                  /* ATTN: only used if enumeration contains an association filter. Find
1682                   * some way to prevent creation in that case.
1683                   */
1684              
1685                  if (!selfCD->wsheader.instanceBatch)
1686                  {
1687                      selfCD->wsheader.instanceBatch = Batch_New(BATCH_MAX_PAGES);
1688                  }
1689              
1690                  /* Parse enumerate request/body */
1691                  if (WS_ParseEnumerateBody(
1692                      xml, 
1693                      &selfCD->wsheader.instanceBatch, 
1694                      &selfCD->u.wsenumpullbody) != 0)
1695                  {
1696 krisbash 1.3         trace_WsmanEnum_UnableToParseXml();
1697                      _CD_SendFailedResponse(selfCD);
1698 mike     1.1         return;
1699                  }
1700              
1701                  /* Validate enumerate request body */
1702 krisbash 1.3     if (_ValidateEnumerateRequest(selfCD) != 0)
1703 mike     1.1     {
1704                      /* appropriate error code was already sent to the client */
1705                      return;
1706                  }
1707              
1708 krisbash 1.3     /* Process request */
1709 mike     1.1 
1710 krisbash 1.3     if (selfCD->u.wsenumpullbody.foundAssociationOperation)
1711 mike     1.1     {
1712 krisbash 1.3         _ProcessAssociatorsRequest(selfCD);
1713 mike     1.1     }
1714                  else
1715                  {
1716 krisbash 1.3         _ProcessEnumerateRequest(selfCD);
1717 mike     1.1     }
1718              }
1719              
1720              static void _ParseValidateProcessInvokeRequest(
1721                  WSMAN_ConnectionData* selfCD,
1722                  XML*    xml)
1723              {
1724                  InvokeReq* msg = 0;
1725              
1726                  /* if instance was created from batch, re-use exisintg batch to allocate message */
1727                  if (selfCD->wsheader.instanceBatch)
1728                  {
1729                      /* Allocate heap space for message */
1730                      msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(InvokeReq));
1731              
1732                      if (!msg)
1733 krisbash 1.3             GOTO_FAILED;
1734 mike     1.1 
1735                      /* Set the tag */
1736 krisbash 1.3         msg->base.base.tag = InvokeReqTag;
1737 mike     1.1 
1738 krisbash 1.3         /* Set the operation id and flags */
1739                      msg->base.base.operationId = _NextOperationID();
1740                      msg->base.base.flags = WSMANFlag | WSMAN_ObjectFlag | _GetFlagsFromWsmanOptions(selfCD);
1741 mike     1.1 
1742                      /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1743 krisbash 1.3         msg->base.base.refCounter = 1;
1744 mike     1.1 
1745                      /* Copy batch onto message (released by delete method) */
1746 krisbash 1.3         msg->base.base.batch = selfCD->wsheader.instanceBatch;
1747 mike     1.1 
1748                      msg->instance = selfCD->wsheader.instance;
1749                      selfCD->wsheader.instanceBatch = 0;
1750                      selfCD->wsheader.instance = 0;
1751                  }
1752                  else
1753 krisbash 1.3         msg = InvokeReq_New(_NextOperationID(), WSMANFlag | WSMAN_ObjectFlag | _GetFlagsFromWsmanOptions(selfCD));
1754 mike     1.1 
1755 krisbash 1.3     if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
1756                      GOTO_FAILED;
1757              
1758                  /* Set the user agent */
1759                  msg->base.userAgent = selfCD->userAgent;
1760 mike     1.1 
1761                  /* Parse invoke request/body */
1762 krisbash 1.3     if (WS_ParseInvokeBody(xml, msg->base.base.batch, &msg->instanceParams) != 0)
1763                      GOTO_FAILED;
1764 mike     1.1 
1765                  /* Extract/set relevant parameters */
1766                  if (selfCD->wsheader.rqtNamespace)
1767 krisbash 1.3     {
1768                      msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
1769                      if (!msg->nameSpace)
1770                          GOTO_FAILED;
1771                  }
1772 mike     1.1 
1773 krisbash 1.3     msg->className = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtClassname);
1774                  msg->function = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtMethod);
1775 mike     1.1 
1776 krisbash 1.3     if (!msg->className || !msg->function)
1777                      GOTO_FAILED;
1778 mike     1.1 
1779 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
1780 mike     1.1 
1781 krisbash 1.3     _OpenRightSingle(selfCD,&msg->base);
1782 mike     1.1 
1783                  InvokeReq_Release(msg);
1784                  return;
1785              
1786              failed:
1787 krisbash 1.3     trace_WsmanInvoke_UnableToProcessRequest();
1788                  _CD_SendFailedResponse(selfCD);
1789 mike     1.1 
1790                  if (msg)
1791                      InvokeReq_Release(msg);
1792              }
1793              
1794 krisbash 1.3 static void _ParseValidateProcessGetInstanceRequest(
1795 mike     1.1     WSMAN_ConnectionData* selfCD,
1796                  XML*    xml)
1797              {
1798                  GetInstanceReq* msg = 0;
1799              
1800                  MI_UNUSED(xml);
1801              
1802                  /* Check if instance name parameter was specified */
1803                  if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
1804                  {
1805 krisbash 1.3         trace_WsmanGetInstance_InstanceNameParameterMissing();
1806                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INTERNAL_ERROR, ZT("get-instance: instance name parameter is missing"));
1807 mike     1.1         return;
1808                  }
1809              
1810                  /* if instance was created from batch, re-use exisintg batch to allocate message */
1811                  /* Allocate heap space for message */
1812                  msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(GetInstanceReq));
1813              
1814 krisbash 1.3     if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
1815                      GOTO_FAILED;
1816              
1817                  /* Set the user agent */
1818                  msg->base.userAgent = selfCD->userAgent;
1819 mike     1.1 
1820                  /* Set the tag */
1821 krisbash 1.3     msg->base.base.tag = GetInstanceReqTag;
1822 mike     1.1 
1823 krisbash 1.3     /* Set the operation id and flags */
1824                  msg->base.base.operationId = _NextOperationID();
1825                  msg->base.base.flags = WSMANFlag | WSMAN_ObjectFlag | _GetFlagsFromWsmanOptions(selfCD);
1826 mike     1.1 
1827                  /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1828 krisbash 1.3     msg->base.base.refCounter = 1;
1829 mike     1.1 
1830                  /* Copy batch into message (released by delete method) */
1831 krisbash 1.3     msg->base.base.batch = selfCD->wsheader.instanceBatch;
1832 mike     1.1 
1833                  msg->instanceName = selfCD->wsheader.instance;
1834              
1835                  /* clear batch/instance fields in header structure */
1836                  selfCD->wsheader.instanceBatch = 0;
1837                  selfCD->wsheader.instance = 0;
1838              
1839                  /* Skip parsing get-request/body - assumed to be empty */
1840              
1841                  /* Extract/set relevant parameters */
1842                  if (selfCD->wsheader.rqtNamespace)
1843 krisbash 1.3     {
1844                      msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
1845                      if (!msg->nameSpace)
1846                          GOTO_FAILED;
1847                  }
1848 mike     1.1 
1849 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
1850 mike     1.1 
1851 krisbash 1.3     _OpenRightSingle(selfCD,&msg->base);
1852 mike     1.1 
1853                  GetInstanceReq_Release(msg);
1854                  return;
1855              
1856              failed:
1857 krisbash 1.3     trace_WsmanGetInstance_UnableToProcessRequest();
1858                  _CD_SendFailedResponse(selfCD);
1859 mike     1.1 
1860                  if (msg)
1861                      GetInstanceReq_Release(msg);
1862              }
1863              
1864 krisbash 1.3 static void _ParseValidateProcessGetClassRequest(
1865 mike     1.1     WSMAN_ConnectionData* selfCD,
1866                  XML*    xml)
1867              {
1868 krisbash 1.3     GetClassReq* msg = 0;
1869              
1870                  MI_Uint32 flags = WSMANFlag | _GetFlagsFromWsmanOptions(selfCD);
1871 mike     1.1 
1872                  MI_UNUSED(xml);
1873              
1874 krisbash 1.3     msg = GetClassReq_New(_NextOperationID(), flags);
1875 mike     1.1 
1876 krisbash 1.3     if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
1877                      GOTO_FAILED;
1878 mike     1.1 
1879 krisbash 1.3     /* Set the user agent */
1880                  msg->base.userAgent = selfCD->userAgent;
1881 mike     1.1 
1882                  /* Set the tag */
1883 krisbash 1.3     msg->base.base.tag = GetClassReqTag;
1884 mike     1.1 
1885 krisbash 1.3     /* Set the flags */
1886                  msg->base.base.flags = flags;
1887 mike     1.1 
1888                  /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1889 krisbash 1.3     msg->base.base.refCounter = 1;
1890 mike     1.1 
1891 krisbash 1.3     /* Skip parsing get-request/body - assumed to be empty */
1892 mike     1.1 
1893 krisbash 1.3     /* Extract/set relevant parameters */
1894                  if (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtNamespace)
1895                  {
1896                      GOTO_FAILED;
1897                  }
1898 mike     1.1 
1899 krisbash 1.3     msg->className = Batch_Tcsdup(
1900                      msg->base.base.batch, 
1901                      selfCD->wsheader.rqtClassname);
1902                  if (!msg->className)
1903                      GOTO_FAILED;
1904              
1905                  msg->nameSpace = Batch_Tcsdup(
1906                                  msg->base.base.batch, 
1907                                  selfCD->wsheader.rqtNamespace);
1908                  if (!msg->nameSpace)
1909                      GOTO_FAILED;
1910              
1911                  AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
1912              
1913                  _OpenRightSingle(selfCD,&msg->base);
1914              
1915                  GetClassReq_Release(msg);
1916                  return;
1917              
1918              failed:
1919                  trace_WsmanGetClass_UnableToProcessRequest();
1920 krisbash 1.3     _CD_SendFailedResponse(selfCD);
1921              
1922                  if (msg)
1923                      GetClassReq_Release(msg);
1924              }
1925              
1926              static void _ParseValidateProcessGetRequest(
1927                  WSMAN_ConnectionData* selfCD,
1928                  XML*    xml)
1929              {
1930                  if(selfCD->wsheader.schemaRequestType == NOT_A_SCHEMA_REQUEST)
1931                  {
1932                      _ParseValidateProcessGetInstanceRequest(selfCD, xml);
1933                  }
1934                  else if(selfCD->wsheader.schemaRequestType == CIM_XML_SCHEMA_REQUEST)
1935                  {
1936                      _ParseValidateProcessGetClassRequest(selfCD, xml);
1937                  }
1938                  else
1939                  {
1940                      trace_WsmanGet_UnsupportedResourceURI();
1941 krisbash 1.3 
1942                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_NOT_SUPPORTED,
1943                          ZT("GetClass not Supported in WS-CIM format"));
1944                      return;
1945                  }
1946              }
1947              
1948              static void _ParseValidateProcessPutRequest(
1949                  WSMAN_ConnectionData* selfCD,
1950                  XML*    xml)
1951              {
1952                  ModifyInstanceReq* msg = 0;
1953              
1954                  MI_UNUSED(xml);
1955              
1956                  /* Check if instance name parameter was specified */
1957                  if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
1958                  {
1959                      trace_WsmanPut_InstanceNameParameterMissing();
1960                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INTERNAL_ERROR, ZT("Put-instance: instance name parameter is missing"));
1961                      return;
1962 krisbash 1.3     }
1963              
1964                  /* if instance was created from batch, re-use exisintg batch to allocate message */
1965                  /* Allocate heap space for message */
1966                  msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(ModifyInstanceReq));
1967              
1968                  if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
1969                      GOTO_FAILED;
1970              
1971                  /* Set the user agent */
1972                  msg->base.userAgent = selfCD->userAgent;
1973              
1974                  /* Set the tag */
1975                  msg->base.base.tag = ModifyInstanceReqTag;
1976              
1977                  /* Set the operation id and flags */
1978                  msg->base.base.operationId = _NextOperationID();
1979                  msg->base.base.flags = WSMANFlag | WSMAN_ObjectFlag | _GetFlagsFromWsmanOptions(selfCD);
1980              
1981                  /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
1982                  msg->base.base.refCounter = 1;
1983 krisbash 1.3 
1984                  /* Copy batch into message (released by delete method) */
1985                  msg->base.base.batch = selfCD->wsheader.instanceBatch;
1986                  msg->instance = selfCD->wsheader.instance;
1987              
1988                  /* clear batch/instance fields in header structure */
1989                  selfCD->wsheader.instanceBatch = 0;
1990                  selfCD->wsheader.instance = 0;
1991              
1992                  /* re-use 'create' parser to parse 'Modify' request/body */
1993                  if (WS_ParseCreateBody(xml, msg->base.base.batch, &msg->instance) != 0)
1994                      GOTO_FAILED;
1995 mike     1.1 
1996                  /* Extract/set relevant parameters */
1997                  if (selfCD->wsheader.rqtNamespace)
1998 krisbash 1.3     {
1999                      msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
2000                      if (!msg->nameSpace)
2001                          GOTO_FAILED;
2002                  }
2003 mike     1.1 
2004 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
2005 mike     1.1 
2006 krisbash 1.3     _OpenRightSingle(selfCD,&msg->base);
2007 mike     1.1 
2008                  ModifyInstanceReq_Release(msg);
2009                  return;
2010              
2011              failed:
2012 krisbash 1.3     trace_WsmanPutInstance_UnableToProcessRequest();
2013                  _CD_SendFailedResponse(selfCD);
2014 mike     1.1 
2015                  if (msg)
2016                      ModifyInstanceReq_Release(msg);
2017              }
2018              
2019              static void _ParseValidateProcessDeleteRequest(
2020                  WSMAN_ConnectionData* selfCD,
2021                  XML*    xml)
2022              {
2023                  DeleteInstanceReq* msg = 0;
2024              
2025                  MI_UNUSED(xml);
2026              
2027                  /* Check if instance name parameter was specified */
2028                  if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
2029                  {
2030 krisbash 1.3         trace_Wsman_InstanceNameParameterMissing();
2031                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INTERNAL_ERROR, ZT("delete-instance: instance name parameter is missing"));
2032 mike     1.1         return;
2033                  }
2034              
2035                  /* if instance was created from batch, re-use exisintg batch to allocate message */
2036                  /* Allocate heap space for message */
2037                  msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(DeleteInstanceReq));
2038              
2039 krisbash 1.3     if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
2040                      GOTO_FAILED;
2041              
2042                  /* Set the user agent */
2043                  msg->base.userAgent = selfCD->userAgent;
2044 mike     1.1 
2045                  /* Set the tag */
2046 krisbash 1.3     msg->base.base.tag = DeleteInstanceReqTag;
2047 mike     1.1 
2048 krisbash 1.3     /* Set the operation id and flags */
2049                  msg->base.base.operationId = _NextOperationID();
2050                  msg->base.base.flags = WSMANFlag | WSMAN_ObjectFlag | _GetFlagsFromWsmanOptions(selfCD);
2051 mike     1.1 
2052                  /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
2053 krisbash 1.3     msg->base.base.refCounter = 1;
2054 mike     1.1 
2055                  /* Copy batch into message (released by delete method) */
2056 krisbash 1.3     msg->base.base.batch = selfCD->wsheader.instanceBatch;
2057 mike     1.1 
2058                  msg->instanceName = selfCD->wsheader.instance;
2059              
2060                  /* clear batch/instance fields in header structure */
2061                  selfCD->wsheader.instanceBatch = 0;
2062                  selfCD->wsheader.instance = 0;
2063              
2064                  /* Skip parsing Delete-request/body - assumed to be empty */
2065              
2066                  /* Extract/set relevant parameters */
2067                  if (selfCD->wsheader.rqtNamespace)
2068 krisbash 1.3     {
2069                      msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
2070                      if (!msg->nameSpace)
2071                          GOTO_FAILED;
2072                  }
2073 mike     1.1 
2074 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
2075 mike     1.1 
2076 krisbash 1.3     _OpenRightSingle(selfCD,&msg->base);
2077 mike     1.1 
2078                  DeleteInstanceReq_Release(msg);
2079                  return;
2080              
2081              failed:
2082 krisbash 1.3     trace_WsmanDelete_UnableToProcessRequest();
2083                  _CD_SendFailedResponse(selfCD);
2084 mike     1.1 
2085                  if (msg)
2086                      DeleteInstanceReq_Release(msg);
2087              }
2088              
2089              static void _ParseValidateProcessCreateRequest(
2090                  WSMAN_ConnectionData* selfCD,
2091                  XML*    xml)
2092              {
2093                  CreateInstanceReq* msg = 0;
2094              
2095 krisbash 1.3     msg = CreateInstanceReq_New(_NextOperationID(), WSMANFlag | WSMAN_CreatedEPRFlag | _GetFlagsFromWsmanOptions(selfCD));
2096              
2097                  if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
2098                      GOTO_FAILED;
2099 mike     1.1 
2100 krisbash 1.3     /* Set the user agent */
2101                  msg->base.userAgent = selfCD->userAgent;
2102 mike     1.1 
2103                  /* Parse create request/body */
2104 krisbash 1.3     if (WS_ParseCreateBody(xml, msg->base.base.batch, &msg->instance) != 0)
2105                      GOTO_FAILED;
2106 mike     1.1 
2107                  /* Extract/set relevant parameters */
2108                  if (selfCD->wsheader.rqtNamespace)
2109 krisbash 1.3     {
2110                      msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
2111                      if (!msg->nameSpace)
2112                          GOTO_FAILED;
2113                  }
2114 mike     1.1 
2115 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
2116 mike     1.1 
2117 krisbash 1.3     _OpenRightSingle(selfCD,&msg->base);
2118 mike     1.1 
2119                  CreateInstanceReq_Release(msg);
2120                  return;
2121              
2122              failed:
2123 krisbash 1.3     trace_WsmanCreate_UnableToProcessRequest();
2124                  _CD_SendFailedResponse(selfCD);
2125 mike     1.1 
2126                  if (msg)
2127                      CreateInstanceReq_Release(msg);
2128              }
2129              
2130              static void _ParseValidateProcessPullRequest(
2131                  WSMAN_ConnectionData* selfCD,
2132                  XML*    xml)
2133              {
2134                  /* Parse pull request/body */
2135                  if (WS_ParsePullBody(xml, &selfCD->u.wsenumpullbody) != 0)
2136                  {
2137 krisbash 1.3         trace_WsmanPull_UnableToParseXml();
2138                      _CD_SendFailedResponse(selfCD);
2139 mike     1.1         return;
2140                  }
2141              
2142                  /* Validate enumerate request body */
2143 krisbash 1.3     if (_ValidatePullRequest(selfCD) != 0)
2144 mike     1.1     {
2145                      /* appropriate error code was already sent to the client */
2146                      return;
2147                  }
2148              
2149                  /* Process reqest */
2150 krisbash 1.3     _ProcessPullRequest(selfCD);
2151 mike     1.1 }
2152              
2153              static void _ParseValidateProcessReleaseRequest(
2154                  WSMAN_ConnectionData* selfCD,
2155                  XML*    xml)
2156              {
2157                  /* Parse pull request/body */
2158                  if (WS_ParseReleaseBody(xml, &selfCD->u.wsenumpullbody) != 0)
2159                  {
2160 krisbash 1.3         trace_WsmanRelease_UnableToParseXml();
2161                      _CD_SendFailedResponse(selfCD);
2162 mike     1.1         return;
2163                  }
2164              
2165                  /* Validate enumerate request body */
2166                  /* no validation needed */
2167              
2168 krisbash 1.3     /* Process request */
2169                  _ProcessReleaseRequest(selfCD);
2170 mike     1.1 }
2171              
2172              static void _SendIdentifyResponse(
2173                  WSMAN_ConnectionData* selfCD)
2174              {
2175                  WSBuf out;
2176                  Page* responsePage = 0;
2177              #   define MSG \
2178 krisbash 1.3     ZT("<soap:Envelope ") \
2179                              ZT("xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" ") \
2180                              ZT("xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\">") CR \
2181                      ZT("<soap:Header/>") CR \
2182                      ZT("<soap:Body>") CR \
2183                          ZT("<soap:IdentifyResponse>") CR \
2184                              ZT("<wsmid:ProtocolVersion>") \
2185                                  ZT("http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd") \
2186                              ZT("</wsmid:ProtocolVersion>") CR \
2187                              ZT("<wsmid:ProductVendor>") \
2188                                  CONFIG_FULLPRODUCT \
2189                              ZT("</wsmid:ProductVendor>") CR \
2190                              ZT("<wsmid:ProductVersion>") \
2191                                  CONFIG_VERSION \
2192                              ZT("</wsmid:ProductVersion>") CR \
2193                              ZT("<wsmid:SecurityProfiles>") CR \
2194                              ZT("<wsmid:SecurityProfileName>") \
2195                                  ZT("http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/https/basic") \
2196                              ZT("</wsmid:SecurityProfileName>") CR \
2197                              ZT("</wsmid:SecurityProfiles>") CR \
2198                              ZT("<wsmb:Capability_FaultIncludesCIMError xmlns:wsmb=\"http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xml\"/>") CR \
2199 krisbash 1.3             ZT("</soap:IdentifyResponse>") CR \
2200                      ZT("</soap:Body>") CR \
2201                  ZT("</soap:Envelope>") CR
2202 mike     1.1 
2203                  if (WSBuf_Init(&out, 1024) != MI_RESULT_OK)
2204                  {
2205 krisbash 1.3         GOTO_FAILED;
2206 mike     1.1     }
2207              
2208                  if (WSBuf_AddLit(&out, LIT(MSG)) != MI_RESULT_OK)
2209                  {
2210 krisbash 1.3         GOTO_FAILED;
2211 mike     1.1     }
2212              
2213                  responsePage = WSBuf_StealPage(&out);
2214              
2215                  if (!responsePage)
2216 krisbash 1.3         GOTO_FAILED;
2217 mike     1.1 
2218 krisbash 1.3     _CD_SendResponse(
2219                      selfCD, 
2220 mike     1.1         HTTP_ERROR_CODE_OK, 
2221 krisbash 1.3         responsePage);
2222 mike     1.1 
2223                  return;
2224              
2225              failed:
2226                  WSBuf_Destroy(&out);
2227 krisbash 1.3     _CD_SendFailedResponse(selfCD);
2228 mike     1.1 }
2229              
2230              static void _HandleIdentifyRequest(
2231                  WSMAN_ConnectionData* selfCD,
2232                  XML* xml)
2233              {
2234                  /* Parse pull request/body */
2235                  if (WS_ParseIdentifyBody(xml) != 0)
2236                  {
2237 krisbash 1.3         trace_Wsman_NoActionOrIdentify();
2238                      _CD_SendFailedResponse(selfCD);
2239 mike     1.1         return;
2240                  }
2241              
2242 krisbash 1.3     _SendIdentifyResponse(selfCD);
2243 mike     1.1 }
2244              
2245              /************************************************************************\
2246              *   Dispatcher calls processing
2247              \************************************************************************/
2248              
2249              static void _EC_GetMessageSubset(
2250                  WSMAN_EnumerateContext* selfEC,
2251                  WSMAN_ConnectionData* selfCD,
2252                  PostInstanceMsg** subsetEnd,
2253 krisbash 1.3     MI_Uint32* totalSize,
2254                  MI_ConstString* bookmark)
2255 mike     1.1 {
2256                  MI_Uint32 count = 0;
2257 krisbash 1.3     PostInstanceMsg* lastMsg = NULL; /* Used for tracking the bookmark of the last message */
2258 mike     1.1     *totalSize = 0;
2259                  *subsetEnd = selfEC->head;
2260              
2261                  while (*subsetEnd)
2262                  {
2263 krisbash 1.3         lastMsg = *subsetEnd;
2264              
2265 mike     1.1         if (count + 1 > selfCD->u.wsenumpullbody.maxElements ||
2266 krisbash 1.3             (*totalSize) + (*subsetEnd)->packedInstanceSize + APPROX_ENUM_RESP_ENVELOPE_SIZE > selfCD->wsheader.maxEnvelopeSize)
2267 mike     1.1             break;
2268              
2269                      (*totalSize) += (*subsetEnd)->packedInstanceSize;
2270                      count++;
2271 krisbash 1.3 
2272 mike     1.1         (*subsetEnd) = (PostInstanceMsg*)(*subsetEnd)->base.next;
2273                  }
2274 krisbash 1.3 
2275              #ifndef DISABLE_INDICATION
2276                  /* Subscribe enumerate contexts will only hold indications and
2277                   * bookmarks should only be sent if requested. */
2278                  if (selfEC->sendBookmarks &&
2279                      NULL != lastMsg)
2280                  {
2281                      PostIndicationMsg* indication = (PostIndicationMsg*)lastMsg;
2282                      *bookmark = indication->bookmark;
2283                  }
2284              #endif
2285              
2286              }
2287              
2288              
2289              static void _EC_ProcessPendingMessage(
2290                  WSMAN_EnumerateContext* selfEC)
2291              {
2292                  if (selfEC->pendingMessage)
2293                  {
2294                       if ((selfEC->totalResponseSize + selfEC->pendingMessage->packedInstanceSize <= MAX_WSMAN_BUFFER_SIZE)
2295 krisbash 1.3         && (selfEC->totalResponses < MAX_WSMAN_COLLECTION_SIZE))
2296                       {
2297                          List_Append(
2298                              (ListElem**)&selfEC->head, 
2299                              (ListElem**)&selfEC->tail, 
2300                              (ListElem*)selfEC->pendingMessage);
2301              
2302                          /* Increment total instance size */
2303                          selfEC->totalResponseSize += selfEC->pendingMessage->packedInstanceSize;
2304              
2305                          /* Increment total number of responses */
2306                          selfEC->totalResponses++;
2307              
2308                          selfEC->pendingMessage = NULL;
2309                          StrandBoth_ScheduleAckRight(&selfEC->strand);
2310                       }
2311                  }
2312              
2313                  return;
2314              }
2315              
2316 krisbash 1.3 /*
2317               * Encapsulates the check to see if the last message has been sent for an
2318               * WSMAN_Enumeratecontext.  Returns TRUE if the last message has been sent
2319               * and it is OK to begin cleanup.
2320               */
2321              static MI_Boolean _EC_IsLastMessageSent(
2322                  WSMAN_EnumerateContext* selfEC )
2323              {
2324                  return (selfEC->enumerationCompleted && !selfEC->head);
2325              }
2326              
2327              static void _EC_StartHeartbeatTimer(
2328                  WSMAN_EnumerateContext* selfEC )
2329              {
2330                  if (TIME_NEVER != selfEC->ecTimer.heartbeatInterval &&
2331                      MI_FALSE == _EC_IsLastMessageSent(selfEC))
2332                  {
2333                      /* Timer is not running because it was already fired or never
2334                       * started during the subscribe request. */
2335                      DEBUG_ASSERT( MI_FALSE == Strand_HaveTimer(&selfEC->strand.base) );
2336              
2337 krisbash 1.3         Strand_StartTimer( &selfEC->strand.base, &selfEC->ecTimer.timer, selfEC->ecTimer.heartbeatInterval );
2338                  }
2339 mike     1.1 }
2340              
2341 krisbash 1.3 /* Sends as many instances as possible (based on envelope-size and instance counter) */
2342 mike     1.1 static void _SendEnumPullResponse(
2343 krisbash 1.3     _In_    WSMAN_EnumerateContext* selfEC, 
2344                          MI_Boolean              fromRequest )
2345 mike     1.1 {
2346 krisbash 1.3     WSBuf outBufHeader;
2347                  WSBuf outBufTrailer;
2348                  Page* responsePageCombined = 0;
2349                  Page* responsePageHeader = 0;
2350                  Page* responsePageTrailer = 0;
2351                  MI_Uint32 totalSize, messagesSize = 0;
2352 mike     1.1     WSMAN_ConnectionData* selfCD = selfEC->activeConnection;
2353                  PostInstanceMsg* subsetEnd = 0;
2354 krisbash 1.3     MI_Boolean endOfSequence = selfEC->enumerationCompleted;
2355                  MI_Result result;
2356                  MI_ConstString bookmarkToSend = NULL;
2357              
2358                  DEBUG_ASSERT( NULL != selfCD );
2359              
2360              #ifndef DISABLE_INDICATION
2361                  /* SubscribeResponse messages should NOT contain any indications if they
2362                   * have arrived before the SubscribeResponse message. */
2363                  if (selfCD->wsheader.rqtAction != WSMANTAG_ACTION_SUBSCRIBE)
2364              #endif
2365                  {
2366                      /* Get message subset based on envelope size/ maxElements */
2367                      _EC_GetMessageSubset(selfEC, selfCD, &subsetEnd, &messagesSize, &bookmarkToSend);
2368                  }
2369 mike     1.1 
2370                  /* validate if all mesages can be sent */
2371                  if (endOfSequence && subsetEnd)
2372                  {
2373                      endOfSequence = MI_FALSE;
2374                  }
2375              
2376                  /* check if we can put at least one message in response */
2377 krisbash 1.3     if (NULL != selfEC->head && subsetEnd == selfEC->head)
2378 mike     1.1     {
2379 krisbash 1.3         trace_Wsman_MaxEnvelopeIsTooSmall((int)subsetEnd->packedInstanceSize);
2380                      _CD_SendFaultResponse(selfCD, fromRequest ? NULL : selfEC , WSBUF_FAULT_ENCODING_LIMIT, ZT("insufficient envelope size for instance transferring"));
2381 mike     1.1         /* Note: leaving context 'as is' so advanced client can increase packet size and re-try */
2382 krisbash 1.3         _EC_CloseLeft( selfEC, MI_FALSE );
2383                      /* This also releases the context on WSMAN
2384                       * The response should not be sent while a timer is running.  
2385                       * The timer must be stopped first */
2386                      _EC_CheckCloseRight( selfEC );
2387 mike     1.1         return;
2388                  }
2389              
2390                  /* Create EnumResponse */
2391 krisbash 1.3     if (WSBuf_Init(&outBufHeader, APPROX_ENUM_RESP_ENVELOPE_SIZE) != MI_RESULT_OK)
2392 mike     1.1     {
2393                      outBufTrailer.page = 0;
2394 krisbash 1.3         GOTO_FAILED;
2395 mike     1.1     }
2396              
2397                  if (WSBuf_Init(&outBufTrailer, 256) != MI_RESULT_OK)
2398 krisbash 1.3         GOTO_FAILED;
2399 mike     1.1 
2400                  /* prepare response header */
2401                  if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
2402                  {
2403                      if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
2404 krisbash 1.3             LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse")), selfCD->wsheader.rqtMessageID))
2405                          GOTO_FAILED;
2406                  }
2407              #ifndef DISABLE_INDICATION
2408                  else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
2409                  {
2410                      if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
2411                          LIT(ZT("http://schemas.xmlsoap.org/ws/2004/08/eventing/SubscribeResponse")), selfCD->wsheader.rqtMessageID))
2412 mike     1.1             goto failed;
2413                  }
2414 krisbash 1.3 #endif /* ifndef DISABLE_INDICATION */
2415 mike     1.1     else
2416                  {
2417                      if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
2418 krisbash 1.3             LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse")), selfCD->wsheader.rqtMessageID))
2419                          GOTO_FAILED;
2420              
2421              #ifndef DISABLE_INDICATION
2422                      if (selfEC->sendBookmarks)
2423                      {
2424                          if (NULL == bookmarkToSend)
2425                          {
2426                              /* A bookmark was requested by the client, but not supplied 
2427                               * by the provider.  Pass along the default value. */
2428                              bookmarkToSend = ZT("http://schemas.dmtf.org/wbem/wsman/1/wsman/bookmark/earliest");  // TODO: Appropriate to do?
2429                          }
2430              
2431                          if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2432                              LIT(ZT("<wsman:Bookmark>"))))
2433                              GOTO_FAILED;
2434              
2435                          if (MI_RESULT_OK != WSBuf_AddString(&outBufHeader, 
2436                              bookmarkToSend))
2437                              GOTO_FAILED;
2438              
2439 krisbash 1.3             if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2440                              LIT(ZT("</wsman:Bookmark>"))))
2441                              GOTO_FAILED;
2442                      }
2443              #endif
2444 mike     1.1     }
2445              
2446                  if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2447 krisbash 1.3         LIT(ZT("</SOAP-ENV:Header>")
2448                      ZT("<SOAP-ENV:Body>"))))
2449                      GOTO_FAILED;
2450 mike     1.1 
2451                  if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
2452                  {
2453                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2454 krisbash 1.3             LIT(ZT("<wsen:EnumerateResponse>"))))
2455                          GOTO_FAILED;
2456                  }
2457              #ifndef DISABLE_INDICATION
2458                  else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
2459                  {
2460                      if (MI_RESULT_OK != _WSMAN_AddSubscribeResponse(&outBufHeader, selfEC))
2461                          GOTO_FAILED;
2462 mike     1.1     }
2463 krisbash 1.3 #endif /* ifndef DISABLE_INDICATION */
2464 mike     1.1     else
2465                  {
2466                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2467 krisbash 1.3             LIT(ZT("<wsen:PullResponse>"))))
2468                          GOTO_FAILED;
2469 mike     1.1     }
2470              
2471                  if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2472 krisbash 1.3         LIT(ZT("<wsen:EnumerationContext>"))))
2473                      GOTO_FAILED;
2474 mike     1.1 
2475                  if (MI_RESULT_OK != WSBuf_AddUint32(&outBufHeader,selfEC->enumerationContextID))
2476 krisbash 1.3         GOTO_FAILED;
2477 mike     1.1 
2478                  if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2479 krisbash 1.3         LIT(ZT("</wsen:EnumerationContext>"))))
2480                      GOTO_FAILED;
2481 mike     1.1 
2482                  if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
2483                  {
2484                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2485 krisbash 1.3             LIT(ZT("<wsman:Items>"))))
2486                          GOTO_FAILED;
2487                  }
2488              #ifndef DISABLE_INDICATION
2489                  else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
2490                  {
2491 mike     1.1     }
2492 krisbash 1.3 #endif /* ifndef DISABLE_INDICATION */
2493 mike     1.1     else
2494                  {
2495                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
2496 krisbash 1.3             LIT(ZT("<wsen:Items>"))))
2497                          GOTO_FAILED;
2498 mike     1.1     }
2499              
2500                  /* trailer */
2501                  if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
2502                  {
2503                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2504 krisbash 1.3             LIT(ZT("</wsman:Items>"))))
2505                          GOTO_FAILED;
2506                  }
2507              #ifndef DISABLE_INDICATION
2508                  else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
2509                  {
2510 mike     1.1     }
2511 krisbash 1.3 #endif /* ifndef DISABLE_INDICATION */
2512 mike     1.1     else
2513                  {
2514                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2515 krisbash 1.3             LIT(ZT("</wsen:Items>"))))
2516                          GOTO_FAILED;
2517 mike     1.1     }
2518              
2519                  if (endOfSequence)
2520                  {
2521                      if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
2522                      {
2523                          if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2524 krisbash 1.3                 LIT(ZT("<wsman:EndOfSequence/>"))))
2525                              GOTO_FAILED;
2526 mike     1.1         }
2527                      else
2528                      {
2529                          if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2530 krisbash 1.3                 LIT(ZT("<wsen:EndOfSequence/>"))))
2531                              GOTO_FAILED;
2532 mike     1.1         }
2533                  }
2534              
2535                  if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
2536                  {
2537                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2538 krisbash 1.3             LIT(ZT("</wsen:EnumerateResponse>"))))
2539                          GOTO_FAILED;
2540                  }
2541              #ifndef DISABLE_INDICATION
2542                  else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
2543                  {
2544                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2545                          LIT(MI_T("</e:SubscribeResponse>"))))
2546 mike     1.1             goto failed;
2547                  }
2548 krisbash 1.3 #endif /* ifndef DISABLE_INDICATION */
2549 mike     1.1     else
2550                  {
2551                      if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2552 krisbash 1.3             LIT(ZT("</wsen:PullResponse>"))))
2553                          GOTO_FAILED;
2554 mike     1.1     }
2555                  if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
2556 krisbash 1.3         LIT(ZT("</SOAP-ENV:Body>")
2557                      ZT("</SOAP-ENV:Envelope>"))))
2558                      GOTO_FAILED;
2559 mike     1.1 
2560                  /* all together */
2561                  responsePageHeader = WSBuf_StealPage(&outBufHeader);
2562                  responsePageTrailer = WSBuf_StealPage(&outBufTrailer);
2563              
2564                  if (!responsePageTrailer || !responsePageHeader)
2565 krisbash 1.3         GOTO_FAILED;
2566 mike     1.1 
2567                  /* calculate size */
2568                  totalSize = (MI_Uint32)(responsePageHeader->u.s.size + responsePageTrailer->u.s.size) + messagesSize;
2569              
2570 krisbash 1.3     responsePageCombined = (Page*)PAL_Malloc(sizeof(Page) + totalSize + 1);
2571 mike     1.1 
2572                  if (!responsePageCombined)
2573 krisbash 1.3         GOTO_FAILED;
2574 mike     1.1 
2575                  {
2576                      char* data = (char*) (responsePageCombined + 1);
2577                      data[totalSize] = 0;
2578              
2579                      memcpy(data, responsePageHeader+1, responsePageHeader->u.s.size);
2580                      data += responsePageHeader->u.s.size;
2581              
2582 krisbash 1.3 #ifndef DISABLE_INDICATION
2583                      /* SubscribeResponse messages should NOT contain any indications if they
2584                       * have arrived before the SubscribeResponse message. */
2585                      if (selfCD->wsheader.rqtAction != WSMANTAG_ACTION_SUBSCRIBE)
2586              #endif
2587 mike     1.1         {
2588                          PostInstanceMsg* msg = selfEC->head;
2589                          while (msg != subsetEnd)
2590                          {
2591                              PostInstanceMsg* next = (PostInstanceMsg*)msg->base.next;
2592              
2593                              memcpy(data, msg->packedInstancePtr, msg->packedInstanceSize);
2594                              data += msg->packedInstanceSize;
2595              
2596                              /* remove message from the list */
2597                              selfEC->totalResponses--;
2598                              selfEC->totalResponseSize -= msg->packedInstanceSize;
2599                              List_Remove(
2600                                  (ListElem**)&selfEC->head, 
2601                                  (ListElem**)&selfEC->tail, 
2602                                  (ListElem*)msg);
2603                              PostInstanceMsg_Release(msg);
2604              
2605                              msg = next;
2606                          }
2607                      }
2608 mike     1.1 
2609                      memcpy(data, responsePageTrailer+1, responsePageTrailer->u.s.size);
2610                      data += responsePageTrailer->u.s.size;
2611              
2612                      responsePageCombined->u.s.size = totalSize;
2613                      responsePageCombined->u.s.next = 0;
2614                  }
2615              
2616 krisbash 1.3     PAL_Free(responsePageHeader); responsePageHeader = 0;
2617                  PAL_Free(responsePageTrailer); responsePageTrailer = 0;
2618 mike     1.1 
2619 krisbash 1.3     if( fromRequest )
2620                  {
2621                      STRAND_ASSERTONSTRAND(&selfCD->strand.base);
2622 mike     1.1 
2623 krisbash 1.3         result = _CD_SendResponse(
2624                          selfCD, 
2625                          HTTP_ERROR_CODE_OK, 
2626                          responsePageCombined);
2627                  }
2628                  else
2629 mike     1.1     {
2630 krisbash 1.3         STRAND_ASSERTONSTRAND(&selfEC->strand.base);
2631              
2632                      result = _EC_SendResponse(
2633                          selfEC, 
2634                          HTTP_ERROR_CODE_OK, 
2635                          responsePageCombined);
2636 mike     1.1     }
2637              
2638 krisbash 1.3     _EC_StartHeartbeatTimer( selfEC );
2639                  
2640                  goto Done;
2641 mike     1.1 
2642 krisbash 1.3 failed:
2643                  WSBuf_Destroy(&outBufHeader);
2644                  WSBuf_Destroy(&outBufTrailer);
2645                  if (responsePageCombined) PAL_Free(responsePageCombined);
2646                  if (responsePageHeader) PAL_Free(responsePageHeader);
2647                  if (responsePageTrailer) PAL_Free(responsePageTrailer);
2648              
2649                  if( fromRequest )
2650                  {
2651                      STRAND_ASSERTONSTRAND(&selfCD->strand.base);
2652              
2653                      // There should be no responses at this point
2654                      DEBUG_ASSERT( NULL == selfEC->head );
2655                  
2656                      result = _CD_SendFailedResponse(selfCD);
2657                  }
2658                  else
2659                  {
2660                      STRAND_ASSERTONSTRAND(&selfEC->strand.base);
2661                  
2662                      _EC_ReleaseAllMessages(selfEC);
2663 mike     1.1 
2664 krisbash 1.3         result = _EC_SendResponse(
2665                          selfEC, 
2666                          HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR, 
2667                          NULL);
2668                  }
2669 mike     1.1 
2670 krisbash 1.3 Done:
2671                  DEBUG_ASSERT( MI_RESULT_OK == result );
2672 mike     1.1 
2673 krisbash 1.3     _EC_CloseLeft( selfEC, fromRequest );
2674 mike     1.1 
2675 krisbash 1.3     _EC_ProcessPendingMessage( selfEC );
2676 mike     1.1 }
2677              
2678              static void _SendInvokeResponse(
2679                  WSMAN_ConnectionData* selfCD,
2680                  PostInstanceMsg* message)
2681              {
2682 krisbash 1.3     WSBuf outBuf;
2683                  Page* responsePage = 0;
2684                  ZChar* action = 0;
2685                  MI_Uint32 actionLen;
2686                  Buf buf = BUF_INITIALIZER;    
2687              
2688                  Buf_AppStrN(&buf, LIT(ZT("http://")));
2689                  Buf_AppStr(&buf, selfCD->wsheader.rqtServer);
2690                  Buf_AppStrN(&buf, LIT(ZT("/wbem/wscim/1/cim-schema/2/")));
2691                  Buf_AppStr(&buf, selfCD->wsheader.rqtClassname);
2692                  Buf_AppStrN(&buf, LIT(ZT("/")));
2693                  Buf_AppStr(&buf, selfCD->wsheader.rqtMethod);
2694                  Buf_AppStrN(&buf, LIT(ZT("\0")));
2695 mike     1.1 
2696 krisbash 1.3     action = (ZChar*)buf.data;
2697                  actionLen = (buf.size / sizeof(ZChar)) - 1 ;
2698 mike     1.1 
2699                  /* Create EnumResponse */
2700 krisbash 1.3     if (WSBuf_Init(&outBuf, APPROX_ENUM_RESP_ENVELOPE_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
2701                      GOTO_FAILED;
2702 mike     1.1 
2703                  if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
2704                      action, actionLen, selfCD->wsheader.rqtMessageID))
2705 krisbash 1.3         GOTO_FAILED;
2706 mike     1.1 
2707                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
2708 krisbash 1.3         LIT(ZT("</SOAP-ENV:Header>")
2709                      ZT("<SOAP-ENV:Body>"))))
2710                  {
2711                      GOTO_FAILED;
2712                  }
2713 mike     1.1 
2714 krisbash 1.3     if (WSBuf_AddVerbatim(
2715                      &outBuf,
2716                      message->packedInstancePtr, 
2717                      message->packedInstanceSize) != MI_RESULT_OK)
2718                  {
2719                      GOTO_FAILED;
2720                  }
2721 mike     1.1 
2722 krisbash 1.3     if (MI_RESULT_OK != WSBuf_AddLit(
2723                      &outBuf,
2724                      LIT(ZT("</SOAP-ENV:Body>")
2725                      ZT("</SOAP-ENV:Envelope>"))))
2726                  {
2727                      GOTO_FAILED;
2728                  }
2729 mike     1.1 
2730                  /* all together */
2731                  responsePage = WSBuf_StealPage(&outBuf);
2732              
2733                  if (!responsePage)
2734 krisbash 1.3         GOTO_FAILED;
2735 mike     1.1 
2736                  /*{
2737 krisbash 1.3         FILE* f = File_Open("out_test.xml", "a");
2738 mike     1.1         fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
2739                      fclose(f);
2740                  }*/
2741              
2742 krisbash 1.3     _CD_SendResponse(
2743                      selfCD, 
2744 mike     1.1         HTTP_ERROR_CODE_OK, 
2745 krisbash 1.3         responsePage);
2746 mike     1.1 
2747 krisbash 1.3     Buf_Destroy(&buf);
2748 mike     1.1 
2749                  return;
2750              
2751              failed:
2752 krisbash 1.3 
2753 mike     1.1     WSBuf_Destroy(&outBuf);
2754 krisbash 1.3     Buf_Destroy(&buf);
2755 mike     1.1 
2756 krisbash 1.3     if (responsePage) 
2757                      PAL_Free(responsePage);
2758 mike     1.1 
2759 krisbash 1.3     _CD_SendFailedResponse(selfCD);
2760 mike     1.1 }
2761              
2762 krisbash 1.3 static void _SendSingleResponseHelper(
2763 mike     1.1     WSMAN_ConnectionData* selfCD,
2764 krisbash 1.3     MI_Uint32 packedResultSize,
2765                  void *packedResultPtr,
2766                  const ZChar* action,
2767 mike     1.1     MI_Uint32 actionSize)
2768              {
2769                  WSBuf   outBuf;
2770                  Page*       responsePage = 0;
2771              
2772 krisbash 1.3     if (WSBuf_Init(&outBuf, APPROX_ENUM_RESP_ENVELOPE_SIZE + packedResultSize) != MI_RESULT_OK)
2773                      GOTO_FAILED;
2774 mike     1.1 
2775                  if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
2776                      action, actionSize, selfCD->wsheader.rqtMessageID))
2777 krisbash 1.3         GOTO_FAILED;
2778 mike     1.1 
2779                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
2780 krisbash 1.3         LIT(ZT("</SOAP-ENV:Header>")
2781                      ZT("<SOAP-ENV:Body>")
2782 mike     1.1         )))
2783 krisbash 1.3         GOTO_FAILED;
2784 mike     1.1 
2785 krisbash 1.3     if (0 < packedResultSize)
2786                  {
2787                      if (WSBuf_AddVerbatim(
2788                          &outBuf,
2789                          packedResultPtr, 
2790                          packedResultSize) != MI_RESULT_OK)
2791                      {
2792                          GOTO_FAILED;
2793                      }
2794                  }
2795 mike     1.1 
2796                  /* trailer */
2797                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
2798                      LIT(
2799 krisbash 1.3         ZT("</SOAP-ENV:Body>")
2800                      ZT("</SOAP-ENV:Envelope>"))))
2801                      GOTO_FAILED;
2802 mike     1.1 
2803                  /* all together */
2804                  responsePage = WSBuf_StealPage(&outBuf);
2805              
2806                  if (!responsePage)
2807 krisbash 1.3         GOTO_FAILED;
2808 mike     1.1 
2809 krisbash 1.3     _CD_SendResponse(
2810                      selfCD, 
2811 mike     1.1         HTTP_ERROR_CODE_OK, 
2812 krisbash 1.3         responsePage);
2813 mike     1.1 
2814                  return;
2815              
2816              failed:
2817                  WSBuf_Destroy(&outBuf);
2818 krisbash 1.3     if (responsePage) 
2819                      PAL_Free(responsePage);
2820              
2821                  _CD_SendFailedResponse(selfCD);
2822              }
2823 mike     1.1 
2824 krisbash 1.3 static void _SendSingleInstanceResponse(
2825                  WSMAN_ConnectionData* selfCD,
2826                  PostInstanceMsg* message,
2827                  const ZChar* action,
2828                  MI_Uint32 actionSize)
2829              {
2830                  _SendSingleResponseHelper(selfCD, message->packedInstanceSize,
2831                                              message->packedInstancePtr, action, actionSize);
2832              }
2833 mike     1.1 
2834 krisbash 1.3 static void _SendSingleSchemaResponse(
2835                  WSMAN_ConnectionData* selfCD,
2836                  PostSchemaMsg* message,
2837                  const ZChar* action,
2838                  MI_Uint32 actionSize)
2839              {
2840                  _SendSingleResponseHelper(selfCD, message->packedSchemaWsmanSize,
2841                                              message->packedSchemaWsmanPtr, action, actionSize);
2842 mike     1.1 }
2843              
2844 krisbash 1.3 static void _SendEmptyBodyResponse(WSMAN_ConnectionData* selfCD, 
2845                                                 const ZChar* action, 
2846                                                 MI_Uint32 actionSize)
2847 mike     1.1 {
2848                  WSBuf   outBuf;
2849                  Page*       responsePage = 0;
2850              
2851 krisbash 1.3     if (WSBuf_Init(&outBuf, APPROX_ENUM_RESP_ENVELOPE_SIZE) != MI_RESULT_OK)
2852                      GOTO_FAILED;
2853 mike     1.1 
2854                  if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
2855 krisbash 1.3         action, actionSize, selfCD->wsheader.rqtMessageID))
2856                      GOTO_FAILED;
2857 mike     1.1 
2858                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
2859 krisbash 1.3         LIT(ZT("</SOAP-ENV:Header>")
2860                      ZT("<SOAP-ENV:Body/>")
2861                      ZT("</SOAP-ENV:Envelope>")
2862 mike     1.1         )))
2863 krisbash 1.3         GOTO_FAILED;
2864 mike     1.1 
2865                  /* all together */
2866                  responsePage = WSBuf_StealPage(&outBuf);
2867              
2868                  if (!responsePage)
2869 krisbash 1.3         GOTO_FAILED;
2870              
2871                  _CD_SendResponse(
2872                      selfCD, 
2873                      HTTP_ERROR_CODE_OK, 
2874                      responsePage);
2875 mike     1.1 
2876 krisbash 1.3     return;
2877              
2878              failed:
2879                  WSBuf_Destroy(&outBuf);
2880                  if (responsePage) 
2881                      PAL_Free(responsePage);
2882 mike     1.1 
2883 krisbash 1.3     _CD_SendFailedResponse(selfCD);
2884              }
2885 mike     1.1 
2886 krisbash 1.3 static void _ProcessEmptyBodyResponse(
2887                  WSMAN_ConnectionData* selfCD)
2888              {
2889                  /* send appropriate response */
2890                  switch (selfCD->wsheader.rqtAction)
2891                  {
2892                  case WSMANTAG_ACTION_PUT:
2893                      _SendEmptyBodyResponse(selfCD, LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse")));
2894                      break;
2895                  
2896                  case WSMANTAG_ACTION_DELETE:
2897                      _SendEmptyBodyResponse(selfCD, LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/transfer/DeleteResponse")));
2898                      break;
2899              
2900                  default:
2901                      /* unexpected */
2902                      _CD_SendFaultResponse(
2903                          selfCD, 
2904                          NULL,
2905                          WSBUF_FAULT_INTERNAL_ERROR, 
2906                          ZT("unexpected internal state"));
2907 krisbash 1.3         break;
2908                  }
2909              }
2910 mike     1.1 
2911 krisbash 1.3 static void _SendErrorResponse(
2912                  _In_        WSMAN_ConnectionData*   selfCD, 
2913                  _In_opt_    WSMAN_EnumerateContext* sendECStrand,
2914                  _In_        PostResultMsg*          message)
2915              {
2916                  WSBUF_FAULT_CODE faultCode;
2917                  const ZChar* description = 0;
2918 mike     1.1 
2919 krisbash 1.3     faultCode = WSBuf_CIMErrorToWSFault(message->result, &description);
2920 mike     1.1 
2921 krisbash 1.3     if (message->errorMessage == NULL)
2922                  {
2923                      message->errorMessage = description;
2924                  }
2925 mike     1.1 
2926 krisbash 1.3     /* ATTN! consume text from cim_error if supplied */
2927                  _SendCimFaultResponse(selfCD, sendECStrand, faultCode, message);
2928              }
2929 mike     1.1 
2930              
2931 krisbash 1.3 static void _SendErrorResultResponse(
2932                  _In_        WSMAN_ConnectionData*   selfCD, 
2933                  _In_opt_    WSMAN_EnumerateContext* sendECStrand,
2934                              MI_Result               result )
2935              {
2936                  PostResultMsg message;
2937                  memset(&message, 0, sizeof(message));
2938                  message.result = result;
2939                  _SendErrorResponse(selfCD, sendECStrand, &message);
2940 mike     1.1 
2941 krisbash 1.3     /* This is designed for "simple" CD failure cases */
2942                  if (NULL == sendECStrand &&
2943                      Strand_HaveTimer(&selfCD->strand.base))
2944                  {
2945                      selfCD->cdTimer.cancelledTimer = MI_TRUE;
2946                      Strand_FireTimer( &selfCD->strand.base );
2947                  }
2948 mike     1.1 }
2949              
2950 krisbash 1.3 /* 
2951               * Processes backlog in enumeration context;
2952               * once last response is sent, it closes the interactions so the context can be deleted.
2953               * Regarding timers, it only stops the running timer if a response will be sent.
2954               */
2955              static void _EC_ProcessEnumResponse(
2956                  _In_    WSMAN_EnumerateContext* selfEC,
2957                          MI_Boolean              pullRequestAttached )
2958 mike     1.1 {
2959 krisbash 1.3     STRAND_ASSERTONSTRAND(&selfEC->strand.base);
2960 mike     1.1 
2961 krisbash 1.3     /* If we have been cancelled, it should proceed to allow the strand to 
2962                   * finish gracefully. */
2963                  if (selfEC->strand.base.canceled)
2964                  {
2965                      _EC_CheckCloseLeft( selfEC );
2966                      _EC_CheckCloseRight( selfEC );
2967                      return;
2968                  }
2969 mike     1.1 
2970 krisbash 1.3     /* do we have connected client to send response to? */
2971                  if( selfEC->strand.base.info.thisClosedOther )
2972                  {
2973                      // TODO: Current code keeps acumulating results if client is not connected (that looks wrong)
2974                      // DEBUG_ASSERT(!selfEC->activeConnection);
2975                      return;
2976                  }
2977 mike     1.1 
2978 krisbash 1.3     DEBUG_ASSERT(selfEC->activeConnection);
2979 mike     1.1 
2980 krisbash 1.3     /* Operation completed with ERROR */
2981 mike     1.1     if (selfEC->enumerationCompleted && selfEC->finalResult != MI_RESULT_OK)
2982                  {
2983 krisbash 1.3         if (Strand_HaveTimer(&selfEC->strand.base))
2984                      {
2985                          /* A timer is present, so route the completion through the timer
2986                           * handler to ensure proper timeout handling and clean up */
2987                          selfEC->ecTimer.isPullAttached = pullRequestAttached;
2988                          Strand_FireTimer( &selfEC->strand.base );
2989                          return;
2990                      }
2991                      
2992                      if (selfEC->errorMessage)
2993                      {
2994                          _SendErrorResponse(selfEC->activeConnection, selfEC, selfEC->errorMessage);
2995                          Message_Release(&selfEC->errorMessage->base);
2996                          selfEC->errorMessage = NULL;
2997                      }
2998                      else
2999                      {
3000                          _SendErrorResultResponse( selfEC->activeConnection, selfEC, selfEC->finalResult);
3001                      }
3002 mike     1.1 
3003 krisbash 1.3         _EC_CloseLeft( selfEC, MI_FALSE );
3004                      // This also releases the context on WSMAN
3005                      _EC_CheckCloseRight( selfEC );
3006                      return;
3007 mike     1.1     }
3008              
3009                  /* Check if partial response has to be sent (or enumeration is completed) */
3010                  /* Update: send anything that is available once client re-connects with pull */
3011                  /* Send resposne now if:
3012                      - enumeration is complete
3013                      - queue has enough instances to fill entire packet (by size or number)
3014 krisbash 1.3         - pull request arrives. Normally, network is slower than providers,
3015 mike     1.1             so once client returns with next pull request, lets send all messages
3016                          we have in queue
3017                      - server is stressed (too many instances)
3018                  */
3019 krisbash 1.3     /*
3020                   TODO: (selfEC->data.requestTag == SubscribeReqTag && selfEC->totalResponses > 0 )
3021                         is a workaround for pull subscription due to timeout response is not implemented yet,
3022                         (1) WSMAN needs to send operation timeout 
3023                         response to WSMAN client in case no data is ready to send to
3024                         client yet. So that WSMAN client can eat the response and send
3025                         another pull request. Current behavior is WINRM client sends
3026                         unsubscribe call after certain amount of time, since OMI server
3027                         did not send any response to client.
3028                         (2) We also needs to verify what is the STANDARD behavior once
3029                         there is an indication available but following condition is not
3030                         satisfied yet. Should OMI just send indication directly or Queue
3031                         it up until timeout (OR) totalResponseSize > maxEnvelopSize?
3032                  */
3033                  else if (selfEC->enumerationCompleted ||
3034                      APPROX_ENUM_RESP_ENVELOPE_SIZE + selfEC->totalResponseSize > selfEC->activeConnection->wsheader.maxEnvelopeSize ||
3035 mike     1.1         selfEC->totalResponses >= selfEC->activeConnection->u.wsenumpullbody.maxElements ||
3036 krisbash 1.3         (pullRequestAttached && selfEC->head) ||
3037                      (selfEC->data.requestTag == SubscribeReqTag && selfEC->totalResponses > 0 )
3038 mike     1.1         )
3039                  {
3040 krisbash 1.3         /* We have not yet responded to the original SubscribeReq with a 
3041                       * SubscribeResponse.  This means that a PostIndication arrived 
3042                       * before the SubscribeResponse OR the PostResult with error.  In 
3043                       * that case, hold on to it until after the SubscribeResponse has 
3044                       * been sent.
3045                       */
3046                      if (selfEC->data.requestTag == SubscribeReqTag &&
3047                          MI_FALSE == selfEC->data.responsed)
3048                      {
3049                          return;
3050                      }
3051 mike     1.1 
3052 krisbash 1.3         if (Strand_HaveTimer(&selfEC->strand.base))
3053                      {
3054                          /* A timer is present, so route the completion through the timer
3055                           * handler to ensure proper timeout handling, clean up,
3056                           * and restart if necessary. */
3057                           selfEC->ecTimer.isPullAttached = pullRequestAttached;
3058                          Strand_FireTimer( &selfEC->strand.base );
3059                          return;
3060                      }
3061                      _SendEnumPullResponse(selfEC, MI_FALSE);
3062 mike     1.1     }
3063 krisbash 1.3 #ifndef DISABLE_INDICATION
3064                  /* A Heartbeat event must be sent when no elements are present to send.
3065                   * See R10.2.5-2 and -3. */
3066                  else if (selfEC->ecTimer.forceResult)
3067                  {
3068                      if (Strand_HaveTimer(&selfEC->strand.base))
3069                      {
3070                          /* A timer is present, so route the completion through the timer
3071                           * handler to ensure proper timeout handling, clean up,
3072                           * and restart if necessary. */
3073                           selfEC->ecTimer.isPullAttached = pullRequestAttached;
3074                          Strand_FireTimer( &selfEC->strand.base );
3075                          return;
3076                      }
3077                      // TODO: WinRM Client sent UnsubscribeReq in response to HB event.
3078                      // As a workaround, we send an empty PullResponse instead.
3079                      //_SendHeartbeatResponse( selfEC->activeConnection, selfEC );
3080                      _SendEnumPullResponse(selfEC, MI_FALSE);
3081                      selfEC->ecTimer.forceResult = MI_FALSE;
3082                  }
3083              #endif
3084 mike     1.1 
3085                  /* release context if last message was sent */
3086 krisbash 1.3     if (_EC_IsLastMessageSent( selfEC ))
3087 mike     1.1     {
3088 krisbash 1.3         _EC_CheckCloseLeft( selfEC );
3089                      _EC_CheckCloseRight( selfEC );
3090 mike     1.1     }
3091              }
3092              
3093              static void _ProcessResultEnumerationContext(
3094                  WSMAN_EnumerateContext* selfEC,
3095                  PostResultMsg* message )
3096              {
3097 krisbash 1.3     trace_ProcessResultEnumerationContext( selfEC, message->result );
3098              
3099 mike     1.1     /* mark context as 'completed' */
3100                  selfEC->enumerationCompleted = MI_TRUE;
3101                  selfEC->finalResult = message->result;
3102 krisbash 1.3     Message_AddRef(&message->base);
3103                  selfEC->errorMessage = message;
3104              
3105 mike     1.1     //ATTN!: process error text/messages
3106 krisbash 1.3     _EC_ProcessEnumResponse(selfEC, MI_FALSE);
3107              }
3108              
3109              static void _ProcessSubscribeResponseEnumerationContext(
3110                  WSMAN_EnumerateContext* selfEC,
3111                  SubscribeRes* msg )
3112              {
3113                  trace_ProcessSubscribeResponseEnumerationContext( selfEC );
3114 mike     1.1 
3115 krisbash 1.3     DEBUG_ASSERT(selfEC->data.requestTag == SubscribeReqTag);
3116                  
3117                  /* Success Subscribe Response continues the subscription */
3118                  selfEC->finalResult = MI_RESULT_OK; // TODO: this is not actually a final result
3119                  if (MI_FALSE == selfEC->data.responsed)
3120                  {
3121                      selfEC->data.responsed = MI_TRUE;
3122 mike     1.1 
3123 krisbash 1.3         if (NULL == selfEC->activeConnection)
3124                      {
3125                          trace_ProcessSubscribeResponseEnumerationContext_TimedOutRequest( selfEC );
3126                          if (!selfEC->strand.base.info.thisClosedOther)
3127                          {
3128                              _EC_CheckCloseRight( selfEC );
3129                          }
3130                          return;
3131                      }
3132                      _SendEnumPullResponse(selfEC, MI_FALSE);
3133                      
3134                      trace_ProcessSubscribeResponseEnumerationContext_Success( selfEC );
3135                  }
3136                  else
3137                      trace_ProcessSubscribeResponseEnumerationContext_DuplicateSuccess(selfEC);
3138                  return;
3139 mike     1.1 }
3140              
3141              static void _ProcessInstanceResponse(
3142                  WSMAN_ConnectionData* selfCD,
3143                  PostInstanceMsg* message)
3144              {
3145                  /* send appropriate response */
3146                  switch (selfCD->wsheader.rqtAction)
3147                  {
3148                  case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
3149 krisbash 1.3         _SendInvokeResponse(selfCD, message);
3150 mike     1.1         break;
3151              
3152                  case WSMANTAG_ACTION_GET:
3153 krisbash 1.3         _SendSingleInstanceResponse(selfCD, message, LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")));
3154 mike     1.1         break;
3155              
3156                  case WSMANTAG_ACTION_PUT:
3157 krisbash 1.3         _SendSingleInstanceResponse(selfCD, message, LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse")));
3158 mike     1.1         break;
3159              
3160                  case WSMANTAG_ACTION_CREATE:
3161 krisbash 1.3         _SendSingleInstanceResponse(selfCD, message, LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse")));
3162 mike     1.1         break;
3163              
3164                  default:
3165                      /* unexpected */
3166 krisbash 1.3         _CD_SendFaultResponse(
3167 mike     1.1             selfCD, 
3168 krisbash 1.3             NULL,
3169 mike     1.1             WSBUF_FAULT_INTERNAL_ERROR, 
3170 krisbash 1.3             ZT("unexpected internal state"));
3171 mike     1.1         break;
3172                  }
3173              }
3174              
3175              static void _ProcessResultConnectionData(
3176                  WSMAN_ConnectionData* selfCD,
3177                  PostResultMsg* message )
3178              {
3179                  if (selfCD->outstandingRequest)
3180                  {
3181 krisbash 1.3         // if response was not store yet, store this result (error probably)
3182                      if( NULL == selfCD->single_message )
3183                      {
3184                          _CD_SetSingleMessage(selfCD, &message->base);
3185                      }
3186                  }
3187                  else
3188                  {
3189                      trace_WsmanConnection_ProcessResult_NoRequest( selfCD );
3190                  }
3191              }
3192              
3193              static void _ProcessSingleMessageConnectionData(
3194                  WSMAN_ConnectionData* selfCD,
3195                  Message* message)
3196              {
3197                  /* Ignore expired contexts */
3198                  if( selfCD->outstandingRequest )
3199                  {
3200                      _CD_SetSingleMessage(selfCD, message);
3201                  }
3202 krisbash 1.3     else
3203                  {
3204                      trace_WsmanConnection_ProcessInstance_Expired( selfCD );
3205                  }
3206              }
3207              
3208              static void _ProcessInstanceEnumerationContext(
3209                  WSMAN_EnumerateContext* selfEC,
3210                  PostInstanceMsg* message )
3211              {
3212                  trace_WsmanEnum(
3213                          selfEC,
3214                          selfEC->enumerationCompleted,
3215                          selfEC->totalResponses,
3216                          selfEC->totalResponseSize );
3217                  
3218                  /* Ignore completed contexts */
3219                  if (selfEC->enumerationCompleted || selfEC->strand.base.canceled)
3220                      return;
3221              
3222                  /* add-ref message to keep it alive */
3223 krisbash 1.3     Message_AddRef( &message->base);
3224              
3225                  if ((selfEC->totalResponseSize + message->packedInstanceSize > MAX_WSMAN_BUFFER_SIZE)
3226                      || (selfEC->totalResponses == MAX_WSMAN_COLLECTION_SIZE))
3227                  {
3228                      selfEC->pendingMessage = message;
3229                  }
3230                  else
3231                  {
3232                      /* Add it to the list to process when result is posted */
3233                      List_Append(
3234                          (ListElem**)&selfEC->head, 
3235                          (ListElem**)&selfEC->tail, 
3236                          (ListElem*)message);
3237              
3238                      /* Increment total instance size */
3239                      selfEC->totalResponseSize += message->packedInstanceSize;
3240              
3241                      /* Increment total number of responses */
3242                      selfEC->totalResponses++;
3243                  }
3244 krisbash 1.3 
3245                  /* Check if we need to send response to the client */
3246                  _EC_ProcessEnumResponse(selfEC, MI_FALSE);
3247              }
3248              
3249              //-------------------------------------------------------------------------------------------------------------------
3250              
3251              static void _InteractionWsman_Transport_Post( _In_ Strand* self_, _In_ Message* msg)
3252              {
3253                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3254              
3255                  DEBUG_ASSERT( HttpRequestMsgTag == msg->tag );
3256              
3257                  self->request = (HttpRequestMsg *)msg;
3258              
3259                  Message_AddRef( msg );
3260              
3261                  // Schedule it as an auxiliary method, so anthing else scheduled already 
3262                  // (like a pending ack from Http) is executed first
3263                  StrandBoth_ScheduleAuxLeft( &self->strand, WSMANCONNECTION_STRANDAUX_PROCESSREQUEST );
3264              }
3265 krisbash 1.3 
3266              static void _InteractionWsman_Transport_PostControl( _In_ Strand* self, _In_ Message* msg)
3267              {
3268                  DEBUG_ASSERT( MI_FALSE );  // not used yet
3269              }
3270              
3271              static void _InteractionWsman_Transport_Ack( _In_ Strand* self )
3272              {
3273                  // ignored
3274              }
3275              
3276              static void _InteractionWsman_Transport_Close( _In_ Strand* self_ )
3277              {
3278                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3279              
3280                  if( self->outstandingRequest )
3281                  {
3282                      self->outstandingRequest = MI_FALSE;
3283                      Strand_Cancel( &self->strand.base );
3284                  }
3285              
3286 krisbash 1.3     if (Strand_HaveTimer(&self->strand.base))
3287                  {
3288                      Strand_FireTimer( &self->strand.base );
3289                  }
3290                  
3291                  // Close back on transport (we only do this on transport close)
3292                  StrandBoth_CloseLeft(&self->strand);
3293              }
3294              
3295              static void _InteractionWsman_Transport_Finish( _In_ Strand* self_ )
3296              {
3297                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3298                  _CD_Cleanup( self );
3299                  Strand_Delete( &self->strand.base );
3300              }
3301              
3302              static void _CD_RightPostHandler(
3303                  WSMAN_ConnectionData* self )
3304              {
3305                  /* A result was posted from the right. Handle the result now.
3306                   *
3307 krisbash 1.3      * Note: The result will not actually get posted to the left until
3308                   * the right side closes the operation.
3309                   */
3310                  switch( self->responseMessage->tag )
3311                  {
3312                  case PostResultMsgTag:
3313                      _ProcessResultConnectionData(self, (PostResultMsg*)self->responseMessage );
3314                      break;
3315                  
3316                  case PostInstanceMsgTag:
3317                  case PostSchemaMsgTag:
3318                      _ProcessSingleMessageConnectionData(self, self->responseMessage );
3319                      break;
3320                  
3321                  case HttpResponseMsgTag:
3322                      _CD_SetSingleMessage(self, self->responseMessage);
3323                      break;        
3324                  
3325                  default:
3326                      trace_Wsman_InteractionWsman_Right_Post_UnexpectedMessage( self->responseMessage->tag );
3327                      DEBUG_ASSERT(MI_FALSE);
3328 krisbash 1.3     }
3329              
3330                  Message_Release(self->responseMessage);
3331                  self->responseMessage = NULL;
3332                  
3333                  /* In any case we are not going to send the response now, 
3334                   * therefore we dont wait to the Ack from transport, 
3335                   * so send an Ack here */
3336                  StrandBoth_AckRight( &self->strand );
3337              }
3338              
3339              static void _CD_RightCloseHandler(
3340                  WSMAN_ConnectionData* self )
3341              {    
3342                  // send stored response now (stored so there are no races before close)
3343                  if( self->outstandingRequest && self->single_message )
3344                  {
3345                      switch( self->single_message->tag )
3346                      {
3347                      case PostSchemaMsgTag:
3348                          _SendSingleSchemaResponse(self, (PostSchemaMsg*)self->single_message, LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")));
3349 krisbash 1.3             break;
3350                      case PostInstanceMsgTag:
3351                          _ProcessInstanceResponse(self, (PostInstanceMsg*)self->single_message);
3352                          break;
3353                      case HttpResponseMsgTag:
3354                          // response message from enumeration context, just post it to transport
3355                          StrandBoth_PostLeft( &self->strand, self->single_message );
3356                          self->outstandingRequest = MI_FALSE;
3357                          break;
3358                      default:
3359                          {
3360                              PostResultMsg* message = (PostResultMsg*)self->single_message;
3361                              DEBUG_ASSERT( PostResultMsgTag == self->single_message->tag );
3362                  
3363                              if( MI_RESULT_OK == message->result)
3364                              {
3365                                  _ProcessEmptyBodyResponse(self);
3366                              }
3367                              else
3368                              {
3369                                  _SendErrorResponse(self, NULL, message);
3370 krisbash 1.3                 }
3371                          }
3372                      }
3373                  }
3374                  
3375                  StrandBoth_CloseRight( &self->strand );
3376              }
3377              
3378              /* Since EC uses direct calls to contact CD instead of scheduling them, it will
3379               * often be the case that both CD.Post and CD.Close are called before the timeout
3380               * function has a chance to execute even if it is scheduled during Post (before
3381               * Close is called).  In order to cover those cases, both actions are conditionally 
3382               * executed here to ensure proper clean up.
3383               */
3384              static void _CD_PostHandlerForFiredTimers(
3385                  WSMAN_ConnectionData* self )
3386              {
3387                  /* Called from "Post" 
3388                   * Note: responseMessage becomes NULL once Post has been processed. */
3389                  if ( self->responseMessage )
3390                  {
3391 krisbash 1.3         _CD_RightPostHandler( self );
3392                  }
3393                  
3394                  /* Called from "Close" 
3395                   * OR Close was called prior to execution of this function AFTER it was
3396                   * scheduled. */
3397                  if (self->strand.infoRight.otherClosedThis)
3398                  {
3399                      _CD_RightCloseHandler( self );
3400                  }
3401              }
3402              
3403              //
3404              // Used to track OperationTimeout (and MaxTime) when specified in WSMan requests.
3405              //
3406              // In timeout scenarios, it cancels simple operations (no EnumerationContext) or
3407              // signals the EnumerationContext that a timeout occurred for further processing.
3408              //
3409              static void _InteractionWsman_Transport_Timeout(
3410                  _In_ Strand* self_,
3411                  TimerReason reason )
3412 krisbash 1.3 {
3413                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3414                  
3415                  if (TimerReason_Canceled == reason ||
3416                      MI_TRUE == self->cdTimer.cancelledTimer)  // TODO: Remove once TimerReason_Canceled is supported uniformly
3417                  {
3418                      /* The timer was cancelled, so no action should take place */
3419                      trace_WsmanConnectionData_OperationCancelled(self, self->wsheader.rqtAction);
3420                      return;
3421                  }
3422                  else if (TimerReason_ManuallyFired == reason)
3423                  {
3424                      _CD_PostHandlerForFiredTimers(self);
3425                      return;
3426                  }
3427                  else // TimerReason_Expired (timed out)
3428                  {
3429                      trace_WsmanConnectionData_OperationTimeout(self, self->wsheader.rqtAction);
3430                      DEBUG_ASSERT( TimerReason_Expired == reason ); 
3431              
3432                      if (self->responseMessage)
3433 krisbash 1.3         {
3434                          /* The timeout was detected during Post.
3435                           *
3436                           * A Post was initiated by EC when the timeout occurred, 
3437                           * but the Post has not completed and the message has not yet been 
3438                           * sent via Close. Complete the Post so that the operation can be Closed.
3439                           */
3440                          _CD_PostHandlerForFiredTimers( self );
3441                          return;
3442                      }
3443                      else if (self->single_message && self->outstandingRequest)
3444 mike     1.1         {
3445 krisbash 1.3             /* The timeout was detected during Close.
3446                           *
3447                           * A message has been Posted, but Close has not yet sent it.  Send it now.
3448                           */
3449                          _CD_PostHandlerForFiredTimers( self );
3450                          return;
3451 mike     1.1         }
3452 krisbash 1.3         else if (self->strand.base.info.otherClosedThis)
3453 mike     1.1         {
3454 krisbash 1.3             /* The timeout was detected during Close.
3455                           *
3456                           * No messages are "in progress" via Post, so it is OK to send a timeout.
3457                           * We cannot call the AUX method here because the EC has already Closed the connection.
3458                           */
3459                          if (self->outstandingRequest)
3460                          {
3461                              _CD_SendFaultResponse(
3462                                  self, 
3463                                  NULL, 
3464                                  WSBUF_FAULT_TIMED_OUT, 
3465                                  ZT("A timeout occurred while processing the operation."));
3466                          }
3467                          StrandBoth_CloseRight( &self->strand );  // TODO: Could also do it via _CD_PostHandlerForFiredTimers, but that would count of on the side-effect of it not posting and closing the connection
3468                          return;
3469 mike     1.1         }
3470                      else
3471                      {
3472 krisbash 1.3             /* If the operation is related to a WSMAN_EnumerationContext, 
3473                           * redirect the timeout there for handling (timeout or partial response) */
3474                          if (WSMANTAG_ACTION_ENUMERATE == self->wsheader.rqtAction ||
3475                              WSMANTAG_ACTION_SUBSCRIBE == self->wsheader.rqtAction ||
3476                              WSMANTAG_ACTION_PULL == self->wsheader.rqtAction)
3477                          {
3478                              WSMAN_EnumerateContext* enumContext = NULL;
3479                              MI_Uint32 enumCtxId = 0;
3480              
3481                              /* Since CD has no reference to its EC during SubscribeReq,
3482                               * one is added to make look up possible. */
3483                              if (WSMANTAG_ACTION_SUBSCRIBE == self->wsheader.rqtAction)
3484                                  enumCtxId = self->enumCtxId;
3485                              else
3486                                  enumCtxId = self->u.wsenumpullbody.enumerationContextID;
3487              
3488                              /* find EnumerationContext */
3489                              enumContext = _WSMAN_FindEnumContext(self->wsman, enumCtxId);
3490              
3491                              if (!enumContext)
3492                              {
3493 krisbash 1.3                     _CD_SendFaultResponse(
3494                                      self, 
3495                                      NULL, 
3496                                      WSBUF_FAULT_DESTINATION_UNREACHABLE, 
3497                                      ZT("Enumeration context not found"));
3498                                  _CD_ForceCloseRight(self);
3499                                  return;
3500                              }
3501              
3502                              StrandBoth_ScheduleAuxLeft(&enumContext->strand,ENUMERATIONCONTEXT_STRANDAUX_CONNECTION_DATA_TIMEOUT);
3503                          }
3504                          else // Cancel here for simple operations
3505                          {
3506                              // Send Timeout response message since the action didn't complete in time.
3507                              _CD_SendFaultResponse(
3508                                  self, 
3509                                  NULL, 
3510                                  WSBUF_FAULT_TIMED_OUT, 
3511                                  ZT("A timeout occurred while processing the operation."));
3512              
3513                              Strand_Cancel(&self->strand.base);
3514 krisbash 1.3             }
3515                          return;
3516 mike     1.1         }
3517 krisbash 1.3     }
3518              }
3519              
3520              // WSMANCONNECTION_STRANDAUX_PROCESSREQUEST
3521              static void _InteractionWsman_Transport_ProcessRequest(
3522                  _In_ Strand* self_ )
3523              {
3524                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3525                  HttpRequestMsg * request = self->request;
3526              
3527                  DEBUG_ASSERT( NULL != request );
3528                  self->request = NULL;
3529              
3530                  // Note that page is taken over in _HttpProcessRequest (or released if failure)
3531                  _HttpProcessRequest(
3532                      self,
3533                      request->headers,
3534                      request->page);
3535              
3536                  // request->page freed inside _HttpProcessRequest
3537                  request->page = NULL;
3538 krisbash 1.3     Message_Release( &request->base );
3539              
3540                  // So far all request processing is synchronous so ack here
3541                  // Note that we cannot use StrandBoth_AckLeft as we can abandon the strand inside _HttpProcessRequest
3542                  StrandBoth_ScheduleAckLeft(&self->strand);
3543              }
3544              
3545              /*
3546               * WsmanConnectionData (CD) is a StrandBoth.  This table represents its incoming
3547               * "left" action handlers.  It parses and processes WSMAN requests from HttpSocket
3548               * and establishes strand connections to the right.  For simple operations, it
3549               * forwards them directly to the dispatcher.  For complex operations such as
3550               * Enumeration, Association, References, and Subscription, it creates or attaches
3551               * to a WsmanEnumerationContext prior to forwarding the request to the dispatcher.
3552               *
3553               * Shutdown Behavior:
3554               *     CD has no special cancel handling, but its lifetime is closely tied to the
3555               * lifetime of its HttpSocket.  When the HttpSocket Closes it, it immediately
3556               * begins shutting itself down by cancelling and Closing to the left.  Shutdown
3557               * can also be initiated by the 'right' side via Close calls to its 'right' FT.
3558               * A timeout may also initiate shutdown via Cancel.
3559 krisbash 1.3  *
3560               * Features:
3561               *     1. It has an operation timer to limit the amount of time it will wait for
3562               *        a response from the right.  Posts from the 'right' will fire this timer
3563               *        prior to forwarding the message to the 'left'.
3564               *     2. Incoming Posts from the 'left' are handled via an AUX method to allow
3565               *        other concurrently scheduled strand operations to complete prior to 
3566               *        beginning processing of a new request.
3567               */
3568              static StrandFT _InteractionWsman_TransportFT = { 
3569                  _InteractionWsman_Transport_Post, 
3570                  _InteractionWsman_Transport_PostControl, 
3571                  _InteractionWsman_Transport_Ack,
3572                  NULL,   // cancel will go pass thru if necessary
3573                  _InteractionWsman_Transport_Close,
3574                  _InteractionWsman_Transport_Finish,
3575                  _InteractionWsman_Transport_Timeout,
3576                  _InteractionWsman_Transport_ProcessRequest,
3577                  NULL,
3578                  NULL,
3579                  NULL,
3580 krisbash 1.3     NULL };
3581 mike     1.1 
3582 krisbash 1.3 static void _CD_TriggerOrHandle(
3583                  WSMAN_ConnectionData* self )
3584              {
3585                  if (Strand_HaveTimer(&self->strand.base))
3586                  {
3587                      Strand_FireTimer( &self->strand.base );
3588                  }
3589                  else
3590                  {
3591                      _CD_PostHandlerForFiredTimers( self );
3592                  }
3593              }
3594              
3595              static void _InteractionWsman_Right_Post( _In_ Strand* self_, _In_ Message* msg)
3596              {
3597                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3598                  
3599                  DEBUG_ASSERT( NULL != self );
3600                  
3601                  trace_WsmanConnection_PostingMsg(
3602                      msg,
3603 krisbash 1.3         msg->tag,
3604                      MessageName(msg->tag),
3605                      msg->operationId,
3606                      self->strand.base.info.interaction.other, 
3607                      self_,
3608                      self->strand.infoRight.interaction.other );
3609              
3610                  if( HttpResponseMsgTag != msg->tag )
3611                  {
3612                      PrintProviderMsg(msg);
3613 mike     1.1     }
3614              
3615 krisbash 1.3     /* Preparation for routing the response to the common handler. 
3616                   * The common handler will ACK the request after processing it. */
3617                  if ( self->responseMessage )
3618                      Message_Release(self->responseMessage);
3619                  Message_AddRef(msg);
3620                  self->responseMessage = msg;
3621              
3622                  _CD_TriggerOrHandle( self );
3623 mike     1.1 }
3624              
3625 krisbash 1.3 static void _InteractionWsman_Right_PostControl( _In_ Strand* self, _In_ Message* msg)
3626              {
3627                  DEBUG_ASSERT( MI_FALSE );  // not used yet
3628              }
3629              
3630              static void _InteractionWsman_Right_Ack( _In_ Strand* self_)
3631              {
3632                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3633              
3634                  trace_WsmanConnection_Ack( self_, self->strand.infoRight.interaction.other );
3635                  // Only used for initial open message ack (no "semantic" secondary messages on WSMAN)
3636              
3637                  //
3638                  // Doesn't need to ack to left side (http layer) here
3639                  // since left was aleady acked upon opending this strand
3640                  //
3641              }
3642              
3643              static void _InteractionWsman_Right_Close( _In_ Strand* self_ )
3644              {
3645                  WSMAN_ConnectionData* self = (WSMAN_ConnectionData*)self_;
3646 krisbash 1.3 
3647                  trace_WsmanConnection_Close( self_, self->strand.infoRight.interaction.other, self->outstandingRequest, self->single_message );
3648              
3649                  _CD_TriggerOrHandle( self );
3650              }
3651              
3652              /*
3653               * WsmanConnectionData (CD) is a StrandBoth.  This table represents its incoming
3654               * "right" action handlers.  It forwards Posted messages to its HttpSocket.  An
3655               * initial Post is held and immediately ACK'd.  When the 'right' component calls
3656               * Close, CD Posts the message to its HttpSocket.
3657               *
3658               * Shutdown Behavior:
3659               *     After it Posts via a call to its Close method, it will Close to the 
3660               *     'right'.  Once its 'left' processes the message it will get Closed
3661               *     from the 'left' and Finish.  A timeout can also trigger shutdown, as
3662               *     described in the CD's 'left' FT.
3663               */
3664              static StrandFT _InteractionWsman_RightFT = { 
3665                  _InteractionWsman_Right_Post, 
3666                  _InteractionWsman_Right_PostControl, 
3667 krisbash 1.3     _InteractionWsman_Right_Ack, 
3668                  NULL,   // cancel will go pass thru if necessary 
3669                  _InteractionWsman_Right_Close,
3670                  NULL,   // self delete
3671                  NULL,
3672                  NULL,
3673                  NULL,
3674                  NULL,
3675                  NULL,
3676                  NULL };
3677              
3678              //-------------------------------------------------------------------------------------------------------------------
3679              
3680              static void _InteractionWsmanEnum_Left_Ack( _In_ Strand* self_)
3681              {
3682                  PAL_UNUSED( self_ );  // Implemented to prevent ACK passthrough since this is StrandBoth
3683              }
3684              
3685              static void _InteractionWsmanEnum_Left_Cancel( _In_ Strand* self_)
3686              {
3687                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3688 krisbash 1.3 
3689                  _EC_CheckCloseLeft( self );
3690                  _EC_CheckCloseRight( self );
3691              }
3692              
3693              static void _InteractionWsmanEnum_Left_Close( _In_ Strand* self_)
3694              {
3695                  // do nothing
3696              }
3697              
3698              static void _InteractionWsmanEnum_Finish( _In_ Strand* self_)
3699              {
3700                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3701              
3702                  trace_WsmanEnum_Finish( self_ );
3703                  
3704                  if (NULL != self->errorMessage)
3705                      Message_Release(&self->errorMessage->base);
3706              
3707              #ifdef CONFIG_ENABLE_DEBUG
3708                  // invalidate struct 
3709 krisbash 1.3     memset( ((char*)self) + sizeof(self->strand), 0xcd, sizeof(*self)-sizeof(self->strand) );
3710              #endif
3711              
3712                  Strand_Delete( &self->strand.base );
3713              }
3714              
3715              static void _PostHandlerForFiredTimers(
3716                  WSMAN_EnumerateContext* self )
3717 mike     1.1 {
3718 krisbash 1.3     /* The timer was fired prior to sending a PullResponse.  Send it now
3719                   * and restart the timer. */
3720                  _EC_ProcessEnumResponse(self, self->ecTimer.isPullAttached);
3721              }
3722 mike     1.1 
3723 krisbash 1.3 /*
3724               * Tracks Heartbeat timeouts for subscriptions.
3725               */
3726              static void _InteractionWsmanEnum_Left_Timeout(
3727                  _In_ Strand* self_,
3728                  TimerReason reason )
3729              {
3730                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3731              
3732                  if (TimerReason_Canceled == reason ||
3733                      self->ecTimer.cancelledTimer)  // TODO: Remove once TimerReason_Canceled is supported uniformly
3734                  {
3735                      /* The timer was cancelled, so no action should take place */
3736                      trace_WsmanEnumerationcontext_HeartbeatCancelled(self, self->enumerationContextID);
3737                      self->enumerationCompleted = MI_TRUE;
3738 mike     1.1         return;
3739 krisbash 1.3     }
3740                  else if( TimerReason_ManuallyFired == reason )
3741                  {
3742                      trace_Wsman_ExpiredTimerForEnumerate(self, self->enumerationContextID);
3743              
3744                      _PostHandlerForFiredTimers( self );
3745                      return; /* Prevents shutdown handling from occuring here */
3746                  }
3747                  else
3748                  {
3749                      /* TimerReason_Canceled should never happen here as it always fires 
3750                       * the timer before a close 
3751                       */
3752                      DEBUG_ASSERT( TimerReason_Expired == reason ); 
3753              
3754                      if (NULL != self->activeConnection &&
3755                          WSMANTAG_ACTION_PULL == self->activeConnection->wsheader.rqtAction)
3756                      {
3757                          trace_WsmanEnumerationcontext_HeartbeatTimeout(self, self->enumerationContextID);
3758              
3759                          /* Send what instances are available OR a heartbeat event.
3760 krisbash 1.3              * Return early to prevents shutdown handling from occuring here
3761                           */
3762                          self->ecTimer.forceResult = MI_TRUE;
3763                          _PostHandlerForFiredTimers( self );
3764                          return; /* Prevents shutdown handling from occuring here */
3765                      }
3766                      
3767                      /* Else:
3768                       * Heartbeat expired with NO PULL.  Shutdown subscription, but don't
3769                       * send a message because there is no activeConnection 
3770                       */
3771                      trace_WsmanEnumerationcontext_HeartbeatMissingPull(self, self->enumerationContextID);
3772                      DEBUG_ASSERT(NULL == self->activeConnection);  // TODO: What about unsubscribeAttach?
3773              
3774                      self->enumerationCompleted = MI_TRUE;
3775              
3776                      /* Cancel anything outgoing there */
3777                      Strand_Cancel(&self->strand.base);
3778                      _EC_CheckCloseRight( self );
3779                  }
3780              }
3781 krisbash 1.3 
3782              static void _EC_Left_Attached( _In_ WSMAN_EnumerateContext* self )
3783              {
3784                  DEBUG_ASSERT( NULL != self->attachingConnection );
3785                  DEBUG_ASSERT( NULL == self->activeConnection );
3786                  self->activeConnection = (WSMAN_ConnectionData*)self->attachingConnection;
3787                  self->attachingConnection = NULL;
3788 mike     1.1 
3789 krisbash 1.3     // Receive the Re-Open
3790                  Strand_AcceptOpenAsyncFromStrandBoth( &self->strand.base, &self->activeConnection->strand );
3791 mike     1.1 }
3792              
3793 krisbash 1.3 // ENUMERATIONCONTEXT_STRANDAUX_PULLATTACHED
3794              static void _InteractionWsmanEnum_Left_PullAttached( _In_ Strand* self_)
3795              {
3796                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3797              
3798                  _EC_Left_Attached( self );
3799                  
3800                  if( self->strand.base.canceled )
3801                  {
3802                      _CD_SendFaultResponse(self->activeConnection, self, WSBUF_FAULT_DESTINATION_UNREACHABLE, ZT("Enumeration context not found"));
3803                      _EC_CloseLeft( self, MI_FALSE );
3804                      // This also releases the context on WSMAN
3805                      _EC_CheckCloseRight( self );
3806                  }
3807                  else
3808                  {
3809                      _EC_ProcessEnumResponse(self, MI_TRUE);
3810                  }
3811              }
3812              
3813              /* ENUMERATIONCONTEXT_STRANDAUX_UNSUBSCRIBEATTACHED */
3814 krisbash 1.3 static void _InteractionWsmanEnum_Left_UnsubscribeAttached( _In_ Strand* self_)
3815              {
3816                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3817                  /* Mark the subscribe operation as cancelled, so any indication post will be ignored */
3818                  Strand_Cancel(self_);
3819                  _EC_ReleasePendingMessage(self);
3820              }
3821              
3822              /* ENUMERATIONCONTEXT_STRANDAUX_CONNECTION_DATA_TIMEOUT */
3823              static void _InteractionWsmanEnum_Left_ConnectionDataTimeout( _In_ Strand* self_)
3824 mike     1.1 {
3825 krisbash 1.3     WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3826              
3827                  trace_WSManEnumerationContext_CD_Timeout_notifier(self);
3828              
3829                  if (NULL == self->activeConnection)
3830                  {
3831                      /* EC sent a response via CD while this method was scheduled, but had
3832                       * not yet executed.  In that case, there is nothing to do because
3833                       * a response was already sent and the connection no longer exists. */
3834                      trace_WSManEnumerateContext_CD_Timeout_on_inactive_context();
3835 mike     1.1         return;
3836 krisbash 1.3     }
3837              
3838                  if (WSMANTAG_ACTION_ENUMERATE == self->activeConnection->wsheader.rqtAction ||
3839                      WSMANTAG_ACTION_SUBSCRIBE == self->activeConnection->wsheader.rqtAction)
3840                  {
3841                      DEBUG_ASSERT( MI_FALSE == Strand_HaveTimer(self_) );
3842              
3843                      trace_WSManEnumerateContext_CD_Timeout_during_initial_operation(
3844                          self->activeConnection->wsheader.rqtAction );
3845              
3846                      /* Send Timeout response message since the action didn't complete in time. */
3847                      _CD_SendFaultResponse(
3848                          self->activeConnection, 
3849                          self, 
3850                          WSBUF_FAULT_TIMED_OUT, 
3851                          ZT("A timeout occurred while processing the operation."));
3852              
3853                      _EC_CheckCloseLeft( self );
3854              
3855                      /* Cancel the operation since the CD timed out while the EC and lower layers
3856                       * were processing the request. */
3857 krisbash 1.3         Strand_Cancel(&self->strand.base);
3858                      _EC_CheckCloseRight( self );
3859                  }
3860                  else
3861                  {
3862                      /* Note: Timeout on a PullRequest should not be treated as a terminating failure
3863                       * for the associated subscription ("making the data source invalid"). */
3864              
3865                      DEBUG_ASSERT(WSMANTAG_ACTION_PULL == self->activeConnection->wsheader.rqtAction); // TODO: This must be kept in sync with the caller
3866              
3867                      /* While waiting to execute this method, if:
3868                       * Post occurred on CD ||
3869                       * Close occurred on CD
3870                       * Then treat this as a No-op */
3871                      if (self->activeConnection->responseMessage ||
3872                          self->activeConnection->single_message ||
3873                          self->strand.base.info.thisClosedOther)
3874                      {
3875                          trace_WSManEnumerationContext_CD_Timeout_Notification_Ignored(
3876                              self->activeConnection->responseMessage,
3877                              self->activeConnection->single_message,
3878 krisbash 1.3                 self->strand.base.info.thisClosedOther);
3879                      }
3880                      else
3881                      {
3882                          /* Pull will have already called _EC_Left_Attached, so it should not be done again
3883                           * send what instances are available OR a heartbeat event.
3884                           * The return may be ignored because it doesn't affect the action taken here. */
3885                          self->ecTimer.forceResult = MI_TRUE;
3886                          _EC_ProcessEnumResponse(self, MI_TRUE);
3887              
3888                          /* Return to avoid closing early.  If HB timer is active, it will
3889                           * fire and Close will happen at a later time.  If it is not
3890                           * present, close will happen within the function. */
3891                          return; 
3892                      }
3893                  }
3894                  
3895                  /* Close anything outgoing here to spur sending of the response. */
3896                  _EC_CheckCloseLeft( self );        
3897              }
3898              
3899 krisbash 1.3 /*
3900               * WsmanEnumerationContext (EC) is a StrandBoth.  This table represents its
3901               * incoming "left" action handlers.  These functions will be called 
3902               * exclusively by its connected CD.
3903               *
3904               * Shutdown Behavior:
3905               *     EC shuts down in a number of ways.  _EC_CheckCloseRight is the main
3906               *     controller of the timing of actual shutdown.  Examine calls to that
3907               *     function to see all shutdown scenarios.
3908               *     1. CD calls Cancel, typically the result of an Unsubscribe or a
3909               *         ECONNRESET termination of a running operation.
3910               *     2. The last message for a request has been sent.
3911               *     3. An error occurred during processing of a request.
3912               *     4. Its hearbeat timer expired without a pull attached.
3913               *     5. An incoming request from CD timed out prior to EC sending an
3914               *         initial response.
3915               *
3916               * Features:
3917               *     1. It has a heartbeat timer that tracks the amount of time between
3918               *         responses that are sent to the client.  The timer must be stopped
3919               *         prior to Posting a message to its CD.
3920 krisbash 1.3  *     2. PullAttached prevents multiple CDs from connecting to the same EC
3921               *         at the same time.  Only one may be attached.  The same applies to 
3922               *         Unsubscribe.
3923               *     3. ConnectionDataTimeout processes CD timeouts.  This function allows
3924               *         coordination of responses so that EC can send partial results.
3925               *         For example, if MaxElements has not been reached, it will trigger
3926               *         a Post with the messages in its queue.
3927               */
3928              static StrandFT _InteractionWsmanEnum_Left_FT = { 
3929                  NULL,   // Post from left not used
3930                  NULL,   // Post Control from left not used
3931                  _InteractionWsmanEnum_Left_Ack,   
3932                  _InteractionWsmanEnum_Left_Cancel, 
3933                  _InteractionWsmanEnum_Left_Close,
3934                  _InteractionWsmanEnum_Finish,
3935                  _InteractionWsmanEnum_Left_Timeout,
3936                  _InteractionWsmanEnum_Left_PullAttached,
3937                  _InteractionWsmanEnum_Left_UnsubscribeAttached,
3938                  _InteractionWsmanEnum_Left_ConnectionDataTimeout,
3939                  NULL,
3940                  NULL };
3941 krisbash 1.3 
3942              static void _InteractionWsmanEnum_Right_Post( _In_ Strand* self_, _In_ Message* msg)
3943              {
3944                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3945              
3946                  DEBUG_ASSERT( NULL != self );
3947              
3948                  trace_WsmanEnum_PostingMsg(
3949                      msg, 
3950                      msg->tag,
3951                      MessageName(msg->tag),
3952                      msg->operationId,
3953                      self->strand.base.info.interaction.other,
3954                      self_,
3955                      self->strand.infoRight.interaction.other);
3956              
3957                  PrintProviderMsg(msg);
3958              
3959                  switch( msg->tag )
3960                  {
3961                  case PostResultMsgTag:
3962 krisbash 1.3         _ProcessResultEnumerationContext(self, (PostResultMsg*)msg );
3963                      break;
3964              
3965                  case SubscribeResTag:
3966                      /* Heartbeat timer should start after this (if used) */
3967                      DEBUG_ASSERT(MI_FALSE == Strand_HaveTimer(&self->strand.base));
3968                      _ProcessSubscribeResponseEnumerationContext(self, (SubscribeRes*)msg );
3969                      break;
3970                      
3971                  case PostInstanceMsgTag:
3972                      _ProcessInstanceEnumerationContext(self, (PostInstanceMsg*)msg );
3973                      break;
3974 mike     1.1 
3975 krisbash 1.3     case PostIndicationMsgTag:
3976                      /* See definition of PostIndicationMsg, it is derived from PostInstanceMsg */
3977                      _ProcessInstanceEnumerationContext(self, (PostInstanceMsg*)msg );
3978                      break;
3979              
3980                  default:
3981                      trace_Wsman_InteractionWsmanEnum_Right_Post_UnexpectedMessage( msg->tag );
3982                      DEBUG_ASSERT(MI_FALSE);
3983                  }
3984              
3985                  if( NULL == self->pendingMessage)
3986                  {
3987                      StrandBoth_ScheduleAckRight( &self->strand );
3988                  }
3989                  /* Else we will Ack once we can accomodate pendingMessage in WSMan's queue. */
3990              }
3991 mike     1.1 
3992 krisbash 1.3 static void _InteractionWsmanEnum_Right_Ack( _In_ Strand* self_)
3993              {
3994                  WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)self_;
3995 mike     1.1 
3996 krisbash 1.3     trace_WsmanEnum_Ack( self_, self->strand.infoRight.interaction.other );
3997 mike     1.1 
3998 krisbash 1.3     // We dont need to pass any ack here to the left, just do nothing
3999              }
4000 mike     1.1 
4001 krisbash 1.3 static void _InteractionWsmanEnum_Right_Close( _In_ Strand* self_)
4002              {
4003                  // do nothing
4004              }
4005              
4006              /*
4007               * WsmanEnumerationContext (EC) is a StrandBoth.  This table represents its
4008               * incoming 'right' action handlers.  These functions will be called 
4009               * exclusively by whatever component handled the initial request in the 
4010               * dispatcher.  The only function that really does anything is Post.  It
4011               * processes messages from lower layers and determines when responses should
4012               * be sent to the 'left' via a most-likely attached CD representing a WSMAN
4013               * Pull.  It will process result and instance Posts.
4014               *
4015               * Shutdown Behavior:
4016               *     As with its 'left' FT, _EC_CheckCloseRight initiates shutdown for EC.
4017               *     The scenarios are described in its 'left' FT.
4018               *
4019               * Features:
4020               *     1. It uses a heartbeat timer as described in its 'left' FT.
4021               *     2. ACKs may not be sent immediately for every Post.  If the timer is
4022 krisbash 1.3  *         fired as a result of the Post, it will be delayed and ACK'd in the
4023               *         timer handler.  Also, it if hits flow control where the message
4024               *         queue has reached its limit, the posted message will become
4025               *         "pending" and won't be ACK'd until the pending message is processed.
4026               */
4027              static StrandFT _InteractionWsmanEnum_Right_FT = { 
4028                  _InteractionWsmanEnum_Right_Post,
4029                  NULL,   // not used
4030                  _InteractionWsmanEnum_Right_Ack,
4031                  NULL,   // cancel goes pass thru
4032                  _InteractionWsmanEnum_Right_Close,   
4033                  _InteractionWsmanEnum_Finish,
4034                  NULL,
4035                  NULL,
4036                  NULL,
4037                  NULL,
4038                  NULL,
4039                  NULL };
4040              
4041              //-------------------------------------------------------------------------------------------------------------------
4042              
4043 krisbash 1.3 #if defined(CONFIG_ENABLE_WCHAR)
4044              static Page* _XMLToWideCharPage(const char* data, size_t size)
4045              {
4046                  size_t wsize = size * sizeof(wchar_t);
4047                  Page* page = (Page*)PAL_Malloc(sizeof(Page) + wsize);
4048                  wchar_t* p;
4049              
4050                  if (!page)
4051                      return NULL;
4052              
4053                  page->u.s.independent = 0;
4054                  page->u.s.next = NULL;
4055                  page->u.s.size = wsize; 
4056              
4057                  p = (wchar_t*)(page + 1);
4058              
4059                  while (size--)
4060                  {
4061                      *p++ = *data++;
4062                  }
4063              
4064 krisbash 1.3     return page;
4065              }
4066              #endif /* defined(CONFIG_ENABLE_WCHAR) */
4067              
4068              void ResetUserData(const HttpHeaders* headers)
4069              {
4070                  if (headers->password)
4071                  {
4072                      size_t len = strlen(headers->password);
4073                      memset((void*)headers->password, 0, len);
4074                      MemoryUnlock((void*)headers->password, len);
4075                  }
4076 mike     1.1 }
4077              
4078              static void _HttpCallbackOnNewConnection(
4079 krisbash 1.3     _Inout_     InteractionOpenParams*  interactionParams )
4080 mike     1.1 {
4081 krisbash 1.3     WSMAN* self = (WSMAN*)interactionParams->callbackData;
4082 mike     1.1     WSMAN_ConnectionData* selfConnectionData;
4083              
4084 krisbash 1.3     DEBUG_ASSERT(NULL != self);
4085              
4086                  DEBUG_ASSERT( NULL != interactionParams->interaction );
4087                  DEBUG_ASSERT( NULL == interactionParams->msg );
4088                  DEBUG_ASSERT( NULL != interactionParams->callbackData );
4089              
4090                  selfConnectionData = (WSMAN_ConnectionData*)StrandBoth_New(
4091                                          STRAND_DEBUG( WsmanConnection )
4092                                          &_InteractionWsman_TransportFT,
4093                                          &_InteractionWsman_RightFT,
4094                                          sizeof(WSMAN_ConnectionData),
4095                                          0,
4096                                          interactionParams );
4097              
4098                  if (!selfConnectionData)
4099                  {
4100                      trace_HttpCallbackOnNewConnection_OutOfMemory();
4101                      Strand_FailOpen( interactionParams );
4102                  }
4103                  else
4104                  {
4105 krisbash 1.3         selfConnectionData->wsman = self;
4106                  }
4107              }
4108              
4109              static void _HttpProcessRequest(
4110                  _In_    WSMAN_ConnectionData*   selfCD,
4111                  _In_    const HttpHeaders*      headers,
4112                  _In_    Page*                   page)
4113              {
4114                  XML * xml = (XML *) PAL_Calloc(1, sizeof (XML));
4115              #if defined(CONFIG_ENABLE_WCHAR)
4116                  int adjustForBom = 0;
4117              #endif    
4118              
4119                  STRAND_ASSERTONSTRAND(&selfCD->strand.base);
4120              
4121                  if (!xml)
4122                  {
4123                      trace_OutOfMemory();
4124                      _CD_SendFailedResponse(selfCD);
4125                      if( NULL != page )
4126 krisbash 1.3         {
4127                          PAL_Free(page);
4128                      }
4129                      return;
4130                  }
4131              
4132                  memcpy(xml, &selfCD->wsman->xml, sizeof(XML));
4133              
4134                  /* Cleanup connection data, since it may still store allocated 
4135                   * pointers from previous operation 
4136                   */
4137                  _CD_Cleanup(selfCD);
4138 mike     1.1 
4139 krisbash 1.3 #if defined(CONFIG_ENABLE_HTTPHEADERS)
4140 mike     1.1 
4141 krisbash 1.3     /* Make copy of HTTP headers */
4142 mike     1.1 
4143 krisbash 1.3     if (headers->headersSize)
4144 mike     1.1     {
4145 krisbash 1.3         memcpy(selfCD->headers, headers->headers,
4146                          sizeof(HttpHeader) * headers->headersSize);
4147                      selfCD->headersSize = headers->headersSize;
4148 mike     1.1     }
4149              
4150 krisbash 1.3 #endif
4151 mike     1.1 
4152 krisbash 1.3     /* Determine whether WinRM client */
4153 mike     1.1 
4154 krisbash 1.3     if (headers->userAgent && 
4155                      Strcasecmp(headers->userAgent, "Microsoft WinRM Client") == 0)
4156 mike     1.1     {
4157 krisbash 1.3         selfCD->userAgent = USERAGENT_WINRM;
4158 mike     1.1     }
4159              
4160                  /* Verify content type */
4161 krisbash 1.3     if (!headers->contentType ||
4162 mike     1.1         (Strcasecmp(headers->contentType,"application/soap+xml") != 0 &&
4163 krisbash 1.3          Strcasecmp(headers->contentType,"text/xml") != 0))
4164 mike     1.1     {
4165 krisbash 1.3         trace_Wsman_InvalidMissingContentType(tcs(PageData(page)));
4166              
4167                      _CD_SendErrorFailedResponse(selfCD, HTTP_ERROR_CODE_BAD_REQUEST);
4168                      goto Done;
4169 mike     1.1     }
4170              
4171 krisbash 1.3 #if defined(CONFIG_ENABLE_WCHAR)
4172                      if (headers->charset &&
4173                          Strcasecmp(headers->charset,"utf-8") == 0)
4174                      {
4175                          /* Convert this page to wide-character */
4176                          Page* wpage = _XMLToWideCharPage(
4177                              (const char*)(page + 1), 
4178                              page->u.s.size);
4179                  
4180                          if (!wpage)
4181                          {
4182                              trace_OutOfMemory();
4183                              _CD_SendFailedResponse(selfCD);
4184                              goto Done;
4185                          }
4186                  
4187                          PAL_Free(page);
4188                          page = wpage;
4189                      }
4190                      else if (headers->charset &&
4191                          Strcasecmp(headers->charset,"utf-16") == 0)
4192 krisbash 1.3         {
4193                          adjustForBom = 1;
4194                      }
4195                      else
4196                      {
4197                          trace_Wsman_CharsetIsNotSupported(
4198                              headers->charset);
4199                          _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_ENCODING_LIMIT, 
4200                              ZT("only utf 8 is supported"));
4201                          goto Done;
4202                      }
4203              #else
4204 mike     1.1     if (headers->charset &&
4205                      Strcasecmp(headers->charset,"utf-8") != 0)
4206                  {
4207 krisbash 1.3         trace_Wsman_CharsetIsNotSupported(
4208                          headers->charset);
4209                      _CD_SendFaultResponse( selfCD, NULL, WSBUF_FAULT_ENCODING_LIMIT, 
4210                          PAL_T("only utf 8 is supported"));
4211                      goto Done;
4212                  }
4213              #endif /* defined(CONFIG_ENABLE_WCHAR) */
4214              
4215                  /*
4216                  Check the authentication/authorization type. It has to be "Basic" (That is the one that OMI supports). 
4217                  In case it is not "Basic", we need to inform the user that this is not supported auth.
4218                  Note: the old behavior was, in the http layer. We check if the auth is not "Basic", then we don't set 
4219                  the username and password, so it will fail here in WSMAN layer, but the error will be 500 error code
4220                  which means internal server error which doesn't clarify anything to the user. Now we are returning 401 
4221                  which will be interpereted by the client and give a meaningful message.
4222                  Also, in the wsman specification, it was mentioned that we should return 401 (HTTP_ERROR_CODE_UNAUTHORIZED) 
4223                  with the list of all supported authentication, and they mentioned that this authentication check is prefered 
4224                  to be in the HTTP layer not here but this will be a future change.
4225                  */
4226                  if(headers->authorization && Strncasecmp(headers->authorization, AUTHENTICATION_BASIC, AUTHENTICATION_BASIC_LENGTH) != 0)
4227                  {
4228 krisbash 1.3         trace_Wsman_UnsupportedAuthentication(headers->authorization);
4229                      _CD_SendErrorFailedResponse(selfCD, HTTP_ERROR_CODE_UNAUTHORIZED);
4230                      goto Done;
4231 mike     1.1     }
4232              
4233                  if (!headers->username || !headers->password ||
4234                      0 != AuthenticateUser(headers->username, headers->password))
4235                  {
4236 krisbash 1.3         trace_Wsman_AuthenticationFailed(
4237                          headers->username);
4238              
4239                      _CD_SendErrorFailedResponse(selfCD, HTTP_ERROR_CODE_UNAUTHORIZED);
4240                      ResetUserData(headers);
4241                      goto Done;
4242 mike     1.1     }
4243 krisbash 1.3     ResetUserData(headers);
4244 mike     1.1 
4245 krisbash 1.3     if (0 != LookupUser(headers->username, &selfCD->authInfo.uid, &selfCD->authInfo.gid))
4246 mike     1.1     {
4247 krisbash 1.3         trace_GetUserUidGid_Failed(
4248                          headers->username);
4249              
4250                      _CD_SendFailedResponse(selfCD);
4251                      goto Done;
4252 mike     1.1     }
4253              
4254 krisbash 1.3     if (page->u.s.size == 0)
4255                  {
4256                      trace_Wsman_BufferSizeIsZero();
4257 mike     1.1 
4258 krisbash 1.3         _CD_SendFailedResponse(selfCD);
4259                      goto Done;
4260                  }
4261                      
4262              #if defined(CONFIG_ENABLE_WCHAR)
4263                  if (adjustForBom == 1)
4264                  {
4265                      /* Skip over the BOM */
4266                      ZChar *startOfBuffer = (ZChar*)(page + 1);
4267                      XML_SetText(xml, startOfBuffer+1);
4268                  }
4269                  else
4270 mike     1.1     {
4271 krisbash 1.3         XML_SetText(xml, (ZChar*)(page + 1));
4272                  }
4273              #else
4274                  XML_SetText(xml, (ZChar*)(page + 1));
4275              #endif
4276                      
4277                  /* Parse SOAP Envelope */
4278                  if (WS_ParseSoapEnvelope(xml) != 0 || 
4279                      xml->status)
4280                  {
4281                      trace_Wsman_FailedParseSOAPEnvelope();
4282                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INTERNAL_ERROR, xml->message);
4283                      goto Done;
4284 mike     1.1     }
4285              
4286                  /* Parse WS header */
4287 krisbash 1.3     if (WS_ParseWSHeader(xml, &selfCD->wsheader, selfCD->userAgent) != 0 ||
4288                      xml->status)
4289 mike     1.1     {
4290 krisbash 1.3         trace_Wsman_FailedParseWSHeader();
4291                      _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_INTERNAL_ERROR, xml->message);
4292                      goto Done;
4293 mike     1.1     }
4294 krisbash 1.3     
4295 mike     1.1     /* Validate header */
4296 krisbash 1.3     if (_ValidateHeader(selfCD) != 0)
4297 mike     1.1     {
4298 krisbash 1.3         goto Done;
4299 mike     1.1     }
4300              
4301                  /* See if this is a Identify request */
4302              
4303                  if (!selfCD->wsheader.foundAction)
4304                  {
4305                      _HandleIdentifyRequest(
4306                          selfCD,
4307 krisbash 1.3             xml);
4308                      goto Done;
4309 mike     1.1     }
4310              
4311 krisbash 1.3     /* Take ownership of this page so we can refer to XML strings */
4312                  _CD_SetPage(selfCD, page);
4313                  page = NULL;
4314 mike     1.1 
4315 krisbash 1.3     DEBUG_ASSERT( !selfCD->strand.infoRight.opened || ( selfCD->strand.infoRight.thisClosedOther && selfCD->strand.infoRight.otherClosedThis ) );
4316 mike     1.1     selfCD->outstandingRequest = MI_TRUE;
4317              
4318                  /* Parse body and send request to the dispatcher */
4319                  switch (selfCD->wsheader.rqtAction)
4320                  {
4321                      case WSMANTAG_ACTION_ENUMERATE:
4322                      {
4323 krisbash 1.3             _ParseValidateProcessEnumerateRequest(selfCD, xml);
4324 mike     1.1             break;
4325                      }
4326                      case WSMANTAG_ACTION_PULL:
4327                      {
4328 krisbash 1.3             _ParseValidateProcessPullRequest(selfCD, xml);
4329 mike     1.1             break;
4330                      }
4331                      case WSMANTAG_ACTION_RELEASE:
4332                      {
4333 krisbash 1.3             _ParseValidateProcessReleaseRequest(selfCD, xml);
4334 mike     1.1             break;
4335                      }
4336                      case WSMANTAG_ACTION_GET:
4337                      {
4338 krisbash 1.3             _ParseValidateProcessGetRequest(selfCD, xml);
4339 mike     1.1             break;
4340                      }
4341                      case WSMANTAG_ACTION_PUT:
4342                      {
4343 krisbash 1.3             _ParseValidateProcessPutRequest(selfCD, xml);
4344 mike     1.1             break;
4345                      }
4346                      case WSMANTAG_ACTION_DELETE:
4347                      {
4348 krisbash 1.3             _ParseValidateProcessDeleteRequest(selfCD, xml);
4349 mike     1.1             break;
4350                      }
4351                      case WSMANTAG_ACTION_CREATE:
4352                      {
4353 krisbash 1.3             _ParseValidateProcessCreateRequest(selfCD, xml);
4354 mike     1.1             break;
4355                      }
4356 krisbash 1.3 #ifndef DISABLE_INDICATION
4357                      case WSMANTAG_ACTION_SUBSCRIBE:
4358                      {
4359                          _ParseValidateProcessSubscribeRequest(selfCD, xml);
4360                      }
4361                      break;
4362                      case WSMANTAG_ACTION_UNSUBSCRIBE:
4363                      {
4364                          _ParseValidateProcessUnsubscribeRequest(selfCD, xml);
4365                      }
4366                      break;
4367              #endif /* ifndef DISABLE_INDICATION */
4368              
4369 mike     1.1         case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
4370                      {
4371 krisbash 1.3             _ParseValidateProcessInvokeRequest(selfCD, xml);
4372 mike     1.1             break;
4373                      }
4374                      default:
4375                      {
4376                          /* unsupported action */
4377 krisbash 1.3             trace_Wsman_UnsupportedAction( selfCD->wsheader.rqtAction );
4378                          _CD_SendFaultResponse(selfCD, NULL, WSBUF_FAULT_NOT_SUPPORTED, 0);
4379 mike     1.1             break;
4380                      }
4381                  }
4382 krisbash 1.3 
4383              Done:
4384                  // we should not do anything strand related at this point 
4385                  // as we could have abandoned the strand when opening to the right
4386                  
4387                  PAL_Free(xml);
4388                  if( NULL != page )
4389                  {
4390                      PAL_Free(page);
4391                  }
4392 mike     1.1 }
4393              
4394              /*
4395              **==============================================================================
4396              **
4397              ** Public definitions:
4398              **
4399              **==============================================================================
4400              */
4401              MI_Result WSMAN_New_Listener(
4402 krisbash 1.3     _Out_       WSMAN**                 selfOut,
4403                  _In_opt_    Selector*               selector,       // optional, maybe NULL
4404                  _In_opt_    unsigned short          http_port,      // 0 to disable 
4405                  _In_opt_    unsigned short          https_port,     // 0 to disable 
4406                  _In_opt_z_  const char*             sslCipherSuite, /* NULL to disable */
4407                  _In_opt_    Server_SSL_Options      sslOptions,     // 0 no special options
4408                  _In_        OpenCallback            callback,
4409                  _In_        void*                   callbackData,
4410                  _In_opt_    const WSMAN_Options*    options)
4411 mike     1.1 {
4412                  WSMAN* self;
4413                  MI_Result r;
4414 krisbash 1.3     HttpOptions tmpHttpOptions = DEFAULT_HTTP_OPTIONS;
4415 mike     1.1 
4416                  /* Check parameters */
4417                  if (!selfOut)
4418                      return MI_RESULT_INVALID_PARAMETER;
4419              
4420                  /* Clear output parameter */
4421                  *selfOut = NULL;
4422              
4423                  /* Allocate structure */
4424                  {
4425 krisbash 1.3         self = (WSMAN*)PAL_Calloc(1, sizeof(WSMAN));
4426 mike     1.1 
4427                      if (!self)
4428                          return MI_RESULT_FAILED;
4429                  }
4430              
4431                  /* Save the callback and callbackData */
4432                  self->callback = callback;
4433                  self->callbackData = callbackData;
4434 krisbash 1.3     self->numEnumerateContexts = 0;
4435                  self->deleting = MI_FALSE;
4436 mike     1.1 
4437                  /*ATTN! slector can be null!*/
4438                  self->selector = selector;
4439              
4440 krisbash 1.3     /* Set the magic number */
4441                  self->magic = _MAGIC;
4442              
4443                  // options 
4444                  if( NULL == options )
4445 mike     1.1     {
4446 krisbash 1.3         WSMAN_Options tmpOptions = DEFAULT_WSMAN_OPTIONS;
4447 mike     1.1 
4448 krisbash 1.3         self->options = tmpOptions;
4449 mike     1.1     }
4450 krisbash 1.3     else
4451                  {
4452                      self->options = *options;
4453 mike     1.1 
4454 krisbash 1.3         // Set HTTP options 
4455                      tmpHttpOptions.enableTracing = options->enableHTTPTracing;
4456                  }
4457 mike     1.1 
4458                  /* create a server */
4459                  r = Http_New_Server(
4460 krisbash 1.3         &self->http, 
4461                      selector, 
4462                      http_port, 
4463                      https_port,
4464                      sslCipherSuite,
4465                      sslOptions,
4466                      _HttpCallbackOnNewConnection, 
4467                      self,  
4468                      &tmpHttpOptions );
4469 mike     1.1 
4470                  if (MI_RESULT_OK != r)
4471                  {
4472                      WSMAN_Delete(self);
4473                      return r;
4474                  }
4475              
4476 krisbash 1.3     RecursiveLock_Init(&self->lock);
4477                  
4478 mike     1.1     /* Initialize xml parser */
4479                  XML_Init(&self->xml);
4480              
4481                  XML_RegisterNameSpace(&self->xml, 's', 
4482 krisbash 1.3         ZT("http://www.w3.org/2003/05/soap-envelope"));
4483 mike     1.1 
4484                  XML_RegisterNameSpace(&self->xml, 'a', 
4485 krisbash 1.3         ZT("http://schemas.xmlsoap.org/ws/2004/08/addressing"));
4486 mike     1.1 
4487                  XML_RegisterNameSpace(&self->xml, 'w', 
4488 krisbash 1.3         ZT("http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"));
4489 mike     1.1 
4490                  XML_RegisterNameSpace(&self->xml, 'n', 
4491 krisbash 1.3         ZT("http://schemas.xmlsoap.org/ws/2004/09/enumeration"));
4492 mike     1.1 
4493                  XML_RegisterNameSpace(&self->xml, 'b', 
4494 krisbash 1.3         ZT("http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd"));
4495 mike     1.1 
4496                  XML_RegisterNameSpace(&self->xml, 'p', 
4497 krisbash 1.3         ZT("http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"));
4498 mike     1.1 
4499                  XML_RegisterNameSpace(&self->xml, 'i',
4500 krisbash 1.3         ZT("http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"));
4501              
4502                  XML_RegisterNameSpace(&self->xml, 'x',
4503                      ZT("http://www.w3.org/2001/XMLSchema-instance"));
4504              
4505                  XML_RegisterNameSpace(&self->xml, MI_T('e'), 
4506                      ZT("http://schemas.xmlsoap.org/ws/2004/08/eventing"));
4507 mike     1.1 
4508                  *selfOut = self;
4509              
4510                  return MI_RESULT_OK;
4511              }
4512              
4513              MI_Result WSMAN_Delete(
4514                  WSMAN* self)
4515              {
4516 krisbash 1.3     size_t count;
4517                  
4518 mike     1.1     /* Check parameters */
4519                  if (!self)
4520                      return MI_RESULT_INVALID_PARAMETER;
4521              
4522                  /* Check magic number */
4523                  if (self->magic != _MAGIC)
4524                      return MI_RESULT_INVALID_PARAMETER;
4525              
4526 krisbash 1.3     RecursiveLock_Acquire(&self->lock);
4527              
4528                  // that would take care of canceling all connections (and perhaps some enumeration contexts)
4529 mike     1.1     Http_Delete(self->http);
4530              
4531 krisbash 1.3     // initiate cancel of all outstanding contexts
4532                  _WSMAN_CancelAllEnumerateContexts(self);
4533              
4534                  self->deleting = MI_TRUE;
4535              
4536                  while( ( count = self->numEnumerateContexts ) > 0 )
4537                  {
4538                      RecursiveLock_Release(&self->lock);
4539                      
4540                      CondLock_Wait(
4541                          (ptrdiff_t)self, &self->numEnumerateContexts, count, CONDLOCK_DEFAULT_SPINCOUNT);
4542              
4543                      RecursiveLock_Acquire(&self->lock);
4544                  }
4545 mike     1.1 
4546                  /* Clear magic number */
4547                  self->magic = 0xDDDDDDDD;
4548              
4549 krisbash 1.3     RecursiveLock_Release(&self->lock);
4550                  
4551 mike     1.1     /* Free self pointer */
4552 krisbash 1.3     PAL_Free(self);
4553 mike     1.1 
4554                  return MI_RESULT_OK;
4555              }
4556              
4557              MI_Result WSMAN_Run(
4558                  WSMAN* self,
4559                  MI_Uint64 timeoutUsec)
4560              {
4561                  /* Run the selector */
4562                  return Http_Run(self->http, timeoutUsec);
4563              }
4564              
4565 krisbash 1.3 #ifndef DISABLE_INDICATION
4566              
4567              /*
4568              static void _SendHeartbeatResponse(
4569                  WSMAN_ConnectionData* selfCD,
4570                  WSMAN_EnumerateContext* selfEC )
4571              {
4572                  WSBuf outBuf;
4573                  Page* responsePage = 0;
4574              
4575                  if (WSBuf_Init(&outBuf, APPROX_ENUM_RESP_ENVELOPE_SIZE) != MI_RESULT_OK)
4576                      GOTO_FAILED;
4577              
4578                  if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(
4579                      &outBuf,
4580                      LIT(ZT("http://schemas.dmtf.org/wbem/wsman/1/wsman/Heartbeat")), 
4581                      selfCD->wsheader.rqtMessageID))
4582                      GOTO_FAILED;
4583              
4584                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
4585                      LIT(ZT("</SOAP-ENV:Header>")
4586 krisbash 1.3         ZT("<SOAP-ENV:Body>")
4587                      )))
4588                      GOTO_FAILED;
4589              
4590                  / * trailer * /
4591                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
4592                      LIT(
4593                      ZT("</SOAP-ENV:Body>")
4594                      ZT("</SOAP-ENV:Envelope>"))))
4595                      GOTO_FAILED;
4596              
4597                  / * all together * /
4598                  responsePage = WSBuf_StealPage(&outBuf);
4599              
4600                  if (!responsePage)
4601                      GOTO_FAILED;
4602              
4603                  _EC_SendResponse(
4604                      selfEC, 
4605                      HTTP_ERROR_CODE_OK, 
4606                      responsePage);
4607 krisbash 1.3 
4608                  / * Restart the timer after sending a response * /
4609                  _EC_StartHeartbeatTimer( selfEC );
4610              
4611                  / * Forces the response beyond the CD and initiates CD shutdown * /
4612                  _EC_CloseLeft( selfEC, MI_FALSE );
4613              
4614                  return;
4615              
4616              failed:
4617                  WSBuf_Destroy(&outBuf);
4618                  if (responsePage) 
4619                      PAL_Free(responsePage);
4620              
4621                  _CD_SendFaultResponse(
4622                      selfCD, 
4623                      selfEC, 
4624                      WSBUF_FAULT_ENCODING_LIMIT, 
4625                      ZT("insufficient envelope size for heartbeat transferring"));
4626              }
4627              */
4628 krisbash 1.3 
4629              static void _SendUnsubscribeResponse(
4630                  WSMAN_ConnectionData* selfCD )
4631              {
4632                  WSBuf outBuf;
4633                  Page* responsePage = 0;
4634              
4635                  if (WSBuf_Init(&outBuf, APPROX_ENUM_RESP_ENVELOPE_SIZE) != MI_RESULT_OK)
4636                      GOTO_FAILED;
4637              
4638                  if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(
4639                      &outBuf,
4640                      LIT(ZT("http://schemas.xmlsoap.org/ws/2004/08/eventing/UnsubscribeResponse")),
4641                      selfCD->wsheader.rqtMessageID))
4642                      GOTO_FAILED;
4643              
4644                  if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
4645                      LIT(ZT("</SOAP-ENV:Header>\n<SOAP-ENV:Body/>\n</SOAP-ENV:Envelope>")
4646                      )))
4647                      GOTO_FAILED;
4648              
4649 krisbash 1.3     /* all together */
4650                  responsePage = WSBuf_StealPage(&outBuf);
4651              
4652                  if (!responsePage)
4653                      GOTO_FAILED;
4654              
4655                  _CD_SendResponse(
4656                      selfCD, 
4657                      HTTP_ERROR_CODE_OK, 
4658                      responsePage);
4659              
4660                  return;
4661              
4662              failed:
4663                  WSBuf_Destroy(&outBuf);
4664                  if (responsePage) 
4665                      PAL_Free(responsePage);
4666              
4667                  _CD_SendFaultResponse(
4668                      selfCD, 
4669                      NULL, 
4670 krisbash 1.3         WSBUF_FAULT_ENCODING_LIMIT, 
4671                      ZT("insufficient envelope size for heartbeat transferring"));
4672              }
4673              
4674              static MI_Result _WSMAN_AddSubscribeResponse(
4675                  WSBuf *wsbuf,
4676                  WSMAN_EnumerateContext* selfEC)
4677              {
4678                  if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4679                          LIT(ZT("<e:SubscribeResponse>"))))
4680                          GOTO_FAILED;
4681                  //
4682                  // Add subscription identifier
4683                  //
4684                  //    <e:SubscriptionManager>
4685                  //      <a:Address>http://localhost:5985/wsman</a:Address>
4686                  //      <a:ReferenceProperties>
4687                  //        <w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/*</w:ResourceURI>
4688                  //        <e:Identifier>0860D524-6F0A-46FE-B95E-7CB0C1A2C1B8</e:Identifier>
4689                  //      </a:ReferenceProperties>
4690                  //    </e:SubscriptionManager>
4691 krisbash 1.3     //    <e:Expires>[xs:dateTime | xs:duration]</e:Expires>
4692                  //
4693                  {
4694                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4695                          LIT(ZT("<e:SubscriptionManager>"))))
4696                          GOTO_FAILED;
4697                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4698                          LIT(ZT("<wsa:ReferenceProperties>"))))
4699                          GOTO_FAILED;
4700                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4701                          LIT(ZT("<wsman:ResourceURI>"))))
4702                          GOTO_FAILED;
4703                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4704                          LIT(ZT("http://schemas.dmtf.org/wbem/wscim/1/*"))))
4705                          GOTO_FAILED;
4706                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4707                          LIT(ZT("</wsman:ResourceURI>"))))
4708                          GOTO_FAILED;
4709                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4710                          LIT(ZT("<e:Identifier>"))))
4711                          GOTO_FAILED;
4712 krisbash 1.3 
4713                      trace_Wsman_AddSubscribeResponse( selfEC, selfEC->enumerationContextID );
4714              
4715                      if (MI_RESULT_OK != WSBuf_AddUint32(wsbuf,selfEC->enumerationContextID))
4716                          GOTO_FAILED;
4717                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4718                          LIT(ZT("</e:Identifier>"))))
4719                          GOTO_FAILED;
4720                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4721                          LIT(ZT("</wsa:ReferenceProperties>"))))
4722                          GOTO_FAILED;
4723                      if (MI_RESULT_OK != WSBuf_AddLit(wsbuf,
4724                          LIT(ZT("</e:SubscriptionManager>"))))
4725                          GOTO_FAILED;
4726                  }
4727              
4728                  return MI_RESULT_OK;
4729              
4730              failed:
4731                  return MI_RESULT_FAILED;
4732              }
4733 krisbash 1.3 
4734              static int _ValidateSubscribeRequest(
4735                  WSMAN_ConnectionData* selfCD)
4736              {
4737                  if (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtNamespace ||
4738                      !selfCD->u.wsenumpullbody.filter || !selfCD->u.wsenumpullbody.dialect)
4739                  {
4740                      trace_Wsman_ParametersMissingInSubscribeRequest();
4741                      _CD_SendFaultResponse(
4742                          selfCD, 
4743                          NULL,
4744                          WSBUF_FAULT_INTERNAL_ERROR, 
4745                          ZT("mandatory parameters (className, namesapce) are not provided for subscribe request"));
4746                      return -1;
4747                  }
4748              
4749                  /*R8.2.3; DSP226
4750                    wsmen:Enumerate/wsman:MaxElements
4751                    (optional) indicates the maximum number of items the consumer is willing to accept in the
4752                    EnumerateResponse
4753                    It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
4754 krisbash 1.3       implied value is 1. */
4755                  if (!selfCD->u.wsenumpullbody.maxElements)
4756                      selfCD->u.wsenumpullbody.maxElements = 1;
4757              
4758                  if (selfCD->u.wsenumpullbody.heartbeat.exists &&
4759                      selfCD->u.wsenumpullbody.heartbeat.value.isTimestamp)
4760                  {
4761                      trace_Wsman_InvalidHeartbeatType();
4762                      _CD_SendFaultResponse(
4763                          selfCD, 
4764                          NULL,
4765                          WSBUF_FAULT_INVALID_HEARTBEAT, 
4766                          ZT("Heartbeat must be xs:duration"));
4767                      return -1;
4768                  }
4769              
4770                  if (selfCD->u.wsenumpullbody.connectionRetry.exists)
4771                  {
4772                      trace_Wsman_UnsupportedConnectionRetry();
4773                      _CD_SendFaultResponse(
4774                          selfCD, 
4775 krisbash 1.3             NULL,
4776                          WSBUF_FAULT_CONNECTION_RETRY_NOT_SUPPORTED, 
4777                          ZT("Connection retry is not supported"));
4778                      return -1;
4779                  }
4780              
4781                  if (selfCD->u.wsenumpullbody.initialBookmark &&
4782                      Tcslen(selfCD->u.wsenumpullbody.initialBookmark) == 0)
4783                  {
4784                      trace_Wsman_SubscribeBookmark_Empty();
4785                      _CD_SendFaultResponse(
4786                          selfCD, 
4787                          NULL,
4788                          WSBUF_FAULT_BOOKMARK_INVALID_FORMAT, 
4789                          ZT("The specified bookmark is empty"));
4790                      return -1;
4791                  }
4792              
4793                  return 0;
4794              }
4795              
4796 krisbash 1.3 static int _ValidateUnsubscribeRequest(
4797                  WSMAN_ConnectionData* selfCD)
4798              {
4799                  /* validate selfCD->wsheader.contextID */
4800                  return 0;
4801              }
4802              
4803              static void _ProcessSubscribeRequest(
4804                  WSMAN_ConnectionData* selfCD)
4805 mike     1.1 {
4806 krisbash 1.3     SubscribeReq* msg;
4807                  WSMAN_EnumerateContext* enumContext;
4808 mike     1.1 
4809 krisbash 1.3     /* create EnumerateContext */
4810                  enumContext = _CD_CreateEnumContext(selfCD);
4811 mike     1.1 
4812 krisbash 1.3     if (!enumContext)
4813 mike     1.1     {
4814 krisbash 1.3         _CD_SendFailedResponse(selfCD);
4815                      return;
4816 mike     1.1     }
4817              
4818 krisbash 1.3     /* Create new request */
4819                  msg = SubscribeReq_New(_NextOperationID(), 
4820                      WSMANFlag | _convertWSMANtoMsgEnumerationMode(selfCD->u.wsenumpullbody.enumerationMode));
4821              
4822                  if (!msg || _GetHTTPHeaderOpts(selfCD, &msg->base) != MI_RESULT_OK)
4823                  {
4824                      _CD_ProcessEnumFailed( selfCD, enumContext );
4825                      return;
4826                  }
4827 mike     1.1 
4828 krisbash 1.3     if (selfCD->wsheader.rqtNamespace)
4829 mike     1.1     {
4830 krisbash 1.3         msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtNamespace);
4831                      if (NULL == msg->nameSpace)
4832                      {
4833                          trace_OutOfMemory();
4834                          _CD_SendFailedResponse(selfCD);
4835                          SubscribeReq_Release(msg);
4836                          return;
4837                      }
4838 mike     1.1     }
4839 krisbash 1.3 
4840                  if (selfCD->wsheader.rqtClassname)
4841 mike     1.1     {
4842 krisbash 1.3         msg->className = Batch_Tcsdup(msg->base.base.batch, selfCD->wsheader.rqtClassname);
4843                      if (NULL == msg->className)
4844                      {
4845                          trace_OutOfMemory();
4846                          _CD_SendFailedResponse(selfCD);
4847                          SubscribeReq_Release(msg);
4848                          return;
4849                      }
4850 mike     1.1     }
4851 krisbash 1.3 
4852                  if (selfCD->u.wsenumpullbody.filter)
4853 mike     1.1     {
4854 krisbash 1.3         msg->filter = Batch_Tcsdup(msg->base.base.batch, selfCD->u.wsenumpullbody.filter);
4855                      if (NULL == msg->filter)
4856                      {
4857                          trace_OutOfMemory();
4858                          _CD_SendFailedResponse(selfCD);
4859                          SubscribeReq_Release(msg);
4860                          return;
4861                      }
4862 mike     1.1     }
4863              
4864 krisbash 1.3     if (selfCD->u.wsenumpullbody.dialect)
4865                  {
4866                      msg->language = Batch_Tcsdup(msg->base.base.batch, selfCD->u.wsenumpullbody.dialect);
4867                      if (NULL == msg->language)
4868                      {
4869                          trace_OutOfMemory();
4870                          _CD_SendFailedResponse(selfCD);
4871                          SubscribeReq_Release(msg);
4872                          return;
4873                      }
4874                  }
4875 mike     1.1 
4876 krisbash 1.3     if (selfCD->u.wsenumpullbody.initialBookmark)
4877 mike     1.1     {
4878 krisbash 1.3         msg->bookmark = Batch_Tcsdup(msg->base.base.batch, selfCD->u.wsenumpullbody.initialBookmark);
4879                      if (NULL == msg->bookmark)
4880                      {
4881                          trace_OutOfMemory();
4882                          _CD_SendFailedResponse(selfCD);
4883                          SubscribeReq_Release(msg);
4884                          return;
4885                      }
4886                  }
4887              
4888                  enumContext->sendBookmarks = selfCD->u.wsenumpullbody.sendBookmarks;
4889 mike     1.1 
4890 krisbash 1.3     AuthInfo_Copy( &msg->base.authInfo, &selfCD->authInfo );
4891 mike     1.1 
4892 krisbash 1.3     /* attach request tag to context */
4893                  enumContext->data.requestTag = msg->base.base.tag;
4894 mike     1.1 
4895 krisbash 1.3     /* mark the response flag to false */
4896                  enumContext->data.responsed = MI_FALSE;
4897 mike     1.1 
4898 krisbash 1.3     if (selfCD->u.wsenumpullbody.heartbeat.exists)
4899                  {
4900                      /* Move heartbeat value to EC so it will be preserved across
4901                       * connections and requests */
4902                      if (0 != DatetimeToUsec(&selfCD->u.wsenumpullbody.heartbeat.value, &enumContext->ecTimer.heartbeatInterval))
4903                      {
4904                          enumContext->ecTimer.heartbeatInterval = WSMAN_TIMEOUT_DEFAULT;
4905              #if defined(_MSC_VER)
4906                          trace_Wsman_UnableToconvertDatetimeToUsec_MSCVER( enumContext->ecTimer.heartbeatInterval, enumContext->data.requestTag );
4907              #else
4908                          trace_Wsman_UnableToconvertDatetimeToUsec_POSIX( enumContext->ecTimer.heartbeatInterval, enumContext->data.requestTag );
4909              #endif
4910                      }
4911 mike     1.1     }
4912              
4913 krisbash 1.3     _OpenRightEnum(selfCD,enumContext,&msg->base,MI_FALSE);
4914              
4915                  SubscribeReq_Release(msg);
4916 mike     1.1 }
4917              
4918 krisbash 1.3 static void _ProcessUnsubscribeRequest(
4919                  WSMAN_ConnectionData* selfCD)
4920 mike     1.1 {
4921 krisbash 1.3     WSMAN_EnumerateContext* enumContext;
4922                  trace_ProcessUnsubscribeRequest( selfCD );
4923              
4924                  enumContext = _WSMAN_FindAndDeleteEnumContext( selfCD->wsman, selfCD->wsheader.contextID );
4925              
4926                  if( NULL == enumContext )
4927                  {
4928                      trace_Wsman_UnableToFindContext( selfCD->wsheader.contextID );
4929                  }
4930                  else
4931                  {
4932                      //only one unsubscribe can attach and the entry got deleted in _WSMAN_FindAndDeleteEnumContext call
4933                      StrandBoth_ScheduleAuxLeft(&enumContext->strand,ENUMERATIONCONTEXT_STRANDAUX_UNSUBSCRIBEATTACHED);
4934                  }
4935 mike     1.1 
4936 krisbash 1.3     _SendUnsubscribeResponse(selfCD);
4937 mike     1.1 
4938 krisbash 1.3     _CD_ForceCloseRight(selfCD);
4939 mike     1.1 
4940 krisbash 1.3     trace_ProcessUnsubscribeRequest_Complete(
4941                      selfCD, 0, MessageName(UnsubscribeReqTag));
4942 mike     1.1 }
4943              
4944 krisbash 1.3 static void _ParseValidateProcessSubscribeRequest(
4945                  WSMAN_ConnectionData* selfCD,
4946                  XML*    xml)
4947 mike     1.1 {
4948 krisbash 1.3     /* Parse subscribe request/body */
4949                  if (WS_ParseSubscribeBody(xml, &selfCD->u.wsenumpullbody) != 0)
4950                  {
4951                      trace_Wsman_UnableToParseXMLSubscribe();
4952                      _CD_SendFailedResponse(selfCD);
4953                      return;
4954                  }
4955 mike     1.1 
4956 krisbash 1.3     /* Validate subscribe request body */
4957                  if (_ValidateSubscribeRequest(selfCD) != 0)
4958 mike     1.1     {
4959 krisbash 1.3         /* appropriate error code was already sent to the client */
4960                      return;
4961 mike     1.1     }
4962              
4963 krisbash 1.3     /* Process reqest */
4964                  _ProcessSubscribeRequest(selfCD);
4965              }
4966              
4967              static void _ParseValidateProcessUnsubscribeRequest(
4968                  WSMAN_ConnectionData* selfCD,
4969                  XML*    xml)
4970              {
4971                      /* Parse enumerate request/body */
4972                  if (WS_ParseUnsubscribeBody(xml, &selfCD->u.wsenumpullbody) != 0)
4973                  {
4974                      trace_Wsman_UnableToParseXMLUnsubscribe();
4975                      _CD_SendFailedResponse(selfCD);
4976                      return;
4977                  }
4978 mike     1.1 
4979 krisbash 1.3     /* Validate enumerate request body */
4980                  if (_ValidateUnsubscribeRequest(selfCD) != 0)
4981 mike     1.1     {
4982 krisbash 1.3         /* appropriate error code was already sent to the client */
4983                      return;
4984 mike     1.1     }
4985              
4986 krisbash 1.3     /* Process reqest */
4987                  _ProcessUnsubscribeRequest(selfCD);
4988 mike     1.1 }
4989 krisbash 1.3 
4990              #endif /* #ifndef DISABLE_INDICATION */

ViewCVS 0.9.2