1 krisbash 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 krisbash 1.1 **==============================================================================
23 */
24
25 #include <pal/format.h>
26 #include <indication/common/indilog.h>
27 #include "SubscriptionContext.h"
28 #include "SubMgr.h"
29 #include "filter.h"
30 #include "context.h"
31 #include "nioproc.h"
32 #include <omi_error/errorutil.h>
33
34 /*
35 * Perform initialization of a SubscriptionContext object.
36 */
37 _Use_decl_annotations_
38 MI_Result SubscrContext_Init(
39 SubscriptionContext* subCtx,
40 Provider* provider,
41 Context_Type type,
42 InteractionOpenParams* interactionParams,
43 krisbash 1.1 struct _SubMgrSubscription* subscription)
44 {
45 MI_Result r;
46 if (!subCtx || !interactionParams || !interactionParams->msg || !subscription)
47 {
48 trace_SubscriptionContext_NullParameter();
49 return MI_RESULT_INVALID_PARAMETER;
50 }
51
52 DEBUG_ASSERT( CTX_TYPE_IND_SUBSCRIPTION == type || CTX_TYPE_IND_LIFECYCLE == type );
53
54 subCtx->subscription = subscription;
55
56 r = Context_Init_ByType( &subCtx->baseCtx, provider, interactionParams, type );
57 if ( MI_RESULT_OK != r )
58 subCtx->subscription = NULL;
59 else
60 {
61 /*
62 * Add refcount to subscription before calling into Subscribe,
63 * which means the provider owning one refcount to the subscription,
64 krisbash 1.1 * the refcount will be released released within context.c:Context_PostMessageLeft
65 *
66 * Lifecycle contexts do not increment here because they do not call
67 * subscribe.
68 *
69 */
70 SubMgrSubscription_Addref(subCtx->subscription);
71 }
72 return r;
73 }
74
75 _Use_decl_annotations_
76 void SubscrContext_Close(
77 SubscriptionContext* subCtx )
78 {
79 if (subCtx)
80 {
81 /* SubsriptionContext was allocated from the SubscribeReq Batch,
82 * so it will be freed when the message's batch is freed. */
83 subCtx->subscription = NULL;
84 Context_Close(&subCtx->baseCtx);
85 krisbash 1.1 }
86 else
87 DEBUG_ASSERT(MI_FALSE); // Double free of Context / called on a NULL context
88 }
89
90 void _SendMessage(
91 _In_ Context* ctx,
92 _In_ Message* msgToSend )
93 {
94 if (ctx->request->base.flags & WSMANFlag)
95 {
96 msgToSend->flags |= ctx->request->base.flags;
97 }
98 else /* Binary protocol */
99 {
100 msgToSend->flags |= BinaryProtocolFlag;
101 }
102
103 Context_PostMessageLeft( ctx, msgToSend );
104 }
105
106 krisbash 1.1 /*
107 * Notifies the indication manager of a state change in a subscription.
108 */
109 _Use_decl_annotations_
110 MI_Result SubscrContext_SendFinalResultMsg(
111 SubscriptionContext* subCtx,
112 MI_Result result,
113 const ZChar* errorMessage,
114 const MI_Instance* cimError )
115 {
116 Context* ctx = (Context*)subCtx;
117 SubMgrSubscription* sub = subCtx->subscription;
118 DEBUG_ASSERT( ctx && sub && ctx->request );
119
120 /* check if final message already sent or not */
121 if ( MI_FALSE == SubMgrSubscription_ShouldSendFinalMsg(sub) )
122 return MI_RESULT_FAILED;
123
124 trace_SubscrContext_SendFinalResultMsg( subCtx, result );
125
126 /* Send PostResultMsg Message */
127 krisbash 1.1 {
128 PostResultMsg* resp;
129
130 if (result == MI_RESULT_OK)
131 resp = PostResultMsg_New( ctx->request->base.operationId );
132 else
133 {
134 resp = PostResultMsg_NewAndSerialize(&ctx->request->base, cimError, errorMessage, MI_RESULT_TYPE_MI, result);
135 }
136 if (!resp)
137 {
138 return MI_RESULT_FAILED;
139 }
140
141 _SendMessage( ctx, (Message*)resp );
142
143 trace_SubscrContext_SendFinalResultMsg_Sent(
144 subCtx, result, resp, MessageName(resp->base.tag));
145
146 PostResultMsg_Release(resp);
147
148 krisbash 1.1 if (ctx->result)
149 *ctx->result = result;
150 }
151 return MI_RESULT_OK;
152 }
153
154 _Use_decl_annotations_
155 MI_Result SubscrContext_SendSubscribeResponseMsg(
156 SubscriptionContext* subCtx )
157 {
158 Context* ctx = (Context*)subCtx;
159 trace_SubscrContext_SendSubscribeResponseMsg( subCtx );
160
161 DEBUG_ASSERT( ctx->request );
162
163 /* Send SubscribeRes Message */
164 {
165 SubscribeRes* resp = SubscribeRes_New( ctx->request->base.operationId );
166 if (!resp)
167 {
168 return MI_RESULT_FAILED;
169 krisbash 1.1 }
170
171 _SendMessage( ctx, (Message*)resp );
172
173 trace_SubscrContext_SendSubscribeResponseMsg_Sent(
174 subCtx, resp, MessageName(resp->base.tag) );
175
176 SubscribeRes_Release(resp);
177
178 if (ctx->result)
179 *ctx->result = MI_RESULT_OK;
180 }
181 return MI_RESULT_OK;
182 }
183
184 SubMgrSubscription* SubscrContext_GetSubscription(
185 _In_ SubscriptionContext* subCtx )
186 {
187 return subCtx->subscription;
188 }
189
190 krisbash 1.1 _Use_decl_annotations_
191 void SubscrContext_UnsubprvdOrSendfinalmsg(
192 SubscriptionContext* subCtx,
193 MI_Boolean invokeUnsubscribe,
194 MI_Result finalResult)
195 {
196 Provider* provider = subCtx->baseCtx.provider;
197 SubMgrSubscription* subscription = subCtx->subscription;
198
199 trace_SubscrContext_UnsubprvdOrSendfinalmsgStart( subCtx, provider, subscription, invokeUnsubscribe );
200
201 if ( MI_TRUE == invokeUnsubscribe )
202 {
203 /*
204 * Invoke Unsubscribe and get final result
205 */
206 Context ctx;
207 MI_Result r = MI_RESULT_OK;
208 Subunsub_Context_Init(&ctx, &r, subCtx->baseCtx.request);
209 (*provider->classDecl->providerFT->Unsubscribe)(
210 provider->self,
211 krisbash 1.1 &ctx.base,
212 subscription->msg->nameSpace,
213 subscription->msg->className,
214 subscription->msg->subscriptionID,
215 subCtx->subself);
216 Context_Close(&ctx);
217 finalResult = r;
218 }
219
220 /*
221 * PostResult to Unsubscribe context does not send final result message,
222 * thus send final result message explicitly
223 */
224 MI_Context_PostResult ( &subCtx->baseCtx.base, finalResult );
225
226 trace_SubscrContext_UnsubprvdOrSendfinalmsgFinish( subCtx, provider, subscription, invokeUnsubscribe );
227 }
228
229 _Use_decl_annotations_
230 MI_Result SubscrContext_Unsubscribe(
231 SubscriptionContext* subCtx)
232 krisbash 1.1 {
233 MI_Boolean invokeUnsubscribe = MI_FALSE;
234 MI_Result result = MI_RESULT_OK;
235 Provider* provider = subCtx->baseCtx.provider;
236 SubMgrSubscription* subscription = subCtx->subscription;
237
238 trace_SubscrContext_Unsubscribe( subCtx, provider, subscription );
239
240 DEBUG_ASSERT(provider && subscription);
241 DEBUG_ASSERT( (subCtx->baseCtx.ctxType == CTX_TYPE_IND_SUBSCRIPTION) ||
242 (subCtx->baseCtx.ctxType == CTX_TYPE_IND_LIFECYCLE) );
243
244 if (subCtx->baseCtx.ctxType == CTX_TYPE_IND_LIFECYCLE)
245 {
246 goto DONE;
247 }
248
249 if (subscription->state == SubscriptionState_Unsubscribing ||
250 subscription->state == SubscriptionState_Unsubscribed)
251 {
252 trace_SubscrContext_AlreadyUnsubscribed( subscription );
253 krisbash 1.1 result = MI_RESULT_FAILED;
254 goto DONE;
255 }
256 else if (SubscriptionState_Subscribed != subscription->state)
257 {
258 trace_SubscrState_InvalidForUnsubscribe(
259 (int)subscription->state, tcs(subscription->msg->className));
260 result = MI_RESULT_FAILED;
261 goto DONE;
262 }
263
264 DEBUG_ASSERT (provider->classDecl->providerFT &&
265 provider->classDecl->providerFT->DisableIndications &&
266 provider->classDecl->providerFT->Unsubscribe );
267
268 SubMgrSubscription_SetState(subscription, SubscriptionState_Unsubscribing);
269
270 if ( MI_FALSE == SubMgrSubscription_ShouldCallUnsubscribe(subscription) )
271 {
272 result = MI_RESULT_FAILED;
273 goto DONE;
274 krisbash 1.1 }
275
276 /* Leave strand here due to provider could post result on same thread */
277 /* Otherwise could cause deadlock */
278 Strand_Leave(&subCtx->baseCtx.strand);
279
280 invokeUnsubscribe = MI_TRUE;
281
282 DONE:
283 /* There is only one IO thread in current process, */
284 /* which has dead lock issue if have multi-thread (include IO thread) posting messages */
285 /* simultaneously. To resolve the issue, unsubscribe has to be invoked from a separate thread */
286 /* Upon implementing multi-thread IO for OMI server, this workaround should be removed */
287 Schedule_UnsubscribeProvider( subCtx, invokeUnsubscribe, result );
288
289 trace_SubscrContext_UnsubscribeDone(subCtx, provider, subscription);
290 return result;
291 }
292
|