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( ¶ms );
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 ¶ms );
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 */
|