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 "provmgr.h"
26 #include "context.h"
27 #include <base/log.h>
28 #include <base/strings.h>
29 #include <base/atomic.h>
30 #include <base/paths.h>
31 #include <base/time.h>
32 #include <wql/wql.h>
33
34 #if defined(CONFIG_POSIX)
35 # include <unistd.h>
36 #endif
37
38 /* ATTN: libraryName is key (switch to module name) */
39 /* ATTN: implement module provider Unload() methods */
40 /* ATTN: implement propertySet */
41
42 /* Suppress casat error from 'void*' to 'MI_Main' */
43 mike 1.1 #if defined(_MSC_VER)
44 # pragma warning(disable : 4055)
45 #endif
46
47 #define T MI_T
48
49 /*
50 **=============================================================================
51 **
52 ** Local defintions
53 **
54 **=============================================================================
55 */
56
57 typedef MI_Module* (*MI_Main)(MI_Server* server);
58
59 extern MI_ContextFT __mi_contextFT;
60
61 static MI_Result MI_CALL _Server_GetVersion(MI_Uint32* version)
62 {
63 if (!version)
64 mike 1.1 return MI_RESULT_INVALID_PARAMETER;
65
66 *version = MI_VERSION;
67 return MI_RESULT_OK;
68 }
69
70 static MI_Result MI_CALL _Server_GetSystemName(const MI_Char** systemName)
71 {
72 #if defined(CONFIG_OS_WINDOWS)
73 *systemName = MI_T("unknown");
74 return MI_RESULT_OK;
75 #else
76 static char buf[256];
77
78 if (buf[0] == '\0')
79 {
80 if (gethostname(buf, sizeof(buf)) != 0)
81 return MI_RESULT_FAILED;
82 }
83
84 *systemName = buf;
85 mike 1.1 return MI_RESULT_OK;
86 #endif
87 }
88
89 #if 0
90 static MI_ServerFT _serverFT =
91 {
92 _Server_GetVersion,
93 _Server_GetSystemName,
94 };
95 #endif
96
97 typedef struct InternalFT
98 {
99 ProvMgrFT provMgrFT;
100 MI_ServerFT serverFT;
101 }
102 InternalFT;
103
104 /* warning C4054: 'type cast': from function pointer to void* */
105 #if defined(_MSC_VER)
106 mike 1.1 # pragma warning(disable : 4054)
107 #endif
108
109 static void* _FindSymbol(const char* name)
110 {
111 if (strcmp(name, "GetPath") == 0)
112 return (void*)&GetPath;
113
114 /* Not found */
115 return NULL;
116 }
117
118 static InternalFT _internalFT =
119 {
120 { PROVMGRFT_MAGIC, _FindSymbol },
121 {
122 _Server_GetVersion,
123 _Server_GetSystemName
124 },
125 };
126
127 mike 1.1 static MI_Server _server =
128 {
129 &_internalFT.serverFT,
130 &__mi_contextFT,
131 &__mi_instanceFT,
132 NULL, /* MI_PropertySetFT */
133 NULL, /* MI_FilterFT */
134 };
135
136 typedef struct _Library Library;
137
138 struct _Provider
139 {
140 struct _Provider* next;
141 struct _Provider* prev;
142
143 const MI_ClassDecl* classDecl;
144 void* self;
145
146 /* number of outstanding requests */
147 AtomicInt refCounter;
148 mike 1.1
149 /* time when last outstanding request was handled */
150 MI_Uint64 idleSince;
151
152 /* indicator if Provider refused idle-unload */
153 MI_Boolean refusedUnload;
154
155 /* pointer to lib object */
156 Library* lib;
157
158 /* indications support */
159 Context ctxIndications;
160
161 };
162
163 struct _Library
164 {
165 struct _Library* next;
166 struct _Library* prev;
167 char libraryName[MAX_PATH_SIZE];
168 void* handle;
169 mike 1.1 const MI_Module* module;
170 MI_Module_Self* self;
171 struct _Provider* head;
172 struct _Provider* tail;
173 ProvMgr* provmgr;
174 };
175
176 static Library* _OpenLibrary(
177 ProvMgr* self,
178 const char* libraryName)
179 {
180 Library* p;
181
182 /* Search cache first */
183 for (p = self->head; p; p = p->next)
184 {
185 if (strcmp(p->libraryName, libraryName) == 0)
186 {
187 return p;
188 }
189 }
190 mike 1.1
191 /* Allocate new libray object */
192 p = (Library*)calloc(1, sizeof(Library));
193
194 if (!p)
195 return NULL;
196
197 /* Library.refs */
198 p->provmgr = self;
199
200 /* Open the library */
201 {
202 char path[MAX_PATH_SIZE];
203 Lib_Format(path, self->providerDir, libraryName);
204 p->handle = Lib_Open(path);
205
206 if (!p->handle)
207 {
208 /* ATTN: one more attempt */
209 p->handle = Lib_Open(libraryName);
210 }
211 mike 1.1
212 if (!p->handle)
213 {
214 free(p);
215 return NULL;
216 }
217 }
218
219 /* Lib_Open.libraryName */
220 Strlcpy(p->libraryName, libraryName, sizeof(p->libraryName));
221
222 /* Invoke MI_Main() entry point */
223 {
224 MI_Main statikMain;
225
226 /* Lookup symbol */
227 {
228 void* ptr = Lib_Sym(p->handle, "MI_Main");
229
230 statikMain = (MI_Main)ptr;
231
232 mike 1.1 if (!statikMain)
233 {
234 free(p);
235 return NULL;
236 }
237 }
238
239 /* Call MI_Main */
240 {
241 p->module = (*statikMain)(&_server);
242 }
243 }
244
245 /* Invoke the module initialize function */
246 if (p->module->Load)
247 {
248 Context ctx;
249 Context_Init(&ctx, 0);
250 (p->module->Load)(&p->self, (MI_Context*)&ctx);
251 Context_Destroy(&ctx);
252 }
253 mike 1.1
254 /* Add library to the list */
255 List_Prepend(
256 (ListElem**)&self->head,
257 (ListElem**)&self->tail,
258 (ListElem*)p);
259
260 return p;
261 }
262
263 static Provider* _OpenProvider(
264 Library* self,
265 const MI_Char* className)
266 {
267 Provider* p;
268
269 /* Search cache first */
270 for (p = self->head; p; p = p->next)
271 {
272 if (Zcasecmp(p->classDecl->name, className) == 0)
273 {
274 mike 1.1 AtomicInc(&p->refCounter);
275 return p;
276 }
277 }
278
279 /* New Provider */
280 p = (Provider*)calloc(1, sizeof(Provider));
281
282 if (!p)
283 {
284 return NULL;
285 }
286
287 /* Provider.refs */
288 p->refCounter = 1;
289 p->lib = self;
290
291 /* Provider.classDecl */
292 {
293 p->classDecl = SchemaDecl_FindClassDecl(self->module->schemaDecl,
294 className);
295 mike 1.1
296 if (!p->classDecl)
297 {
298 free(p);
299 return NULL;
300 }
301 }
302
303 /* Initialize context - used for indication providers */
304 Context_Init(&p->ctxIndications, 0);
305 p->ctxIndications.chainType = CTX_TYPE_IND_NOTINITIALIZED;
306
307 /* Call provider Load() method */
308 if (p->classDecl->providerFT->Load)
309 {
310 Context ctx;
311 MI_Result r = MI_RESULT_OK;
312
313 Context_Init(&ctx, p);
314 ctx.result = &r;
315
316 mike 1.1 (*p->classDecl->providerFT->Load)(&p->self, self->self, &ctx.base);
317
318 DEBUG_ASSERT(ctx.magic == (MI_Uint32)-1);
319
320 if (MI_RESULT_OK != r)
321 {
322 LOGW((T("failed to call provider's load with result %d; class: %s"), (int)r, className));
323 free(p);
324 return NULL;
325 }
326 }
327
328 /* Prepend to list */
329 List_Prepend(
330 (ListElem**)&self->head,
331 (ListElem**)&self->tail,
332 (ListElem*)p);
333
334 return p;
335 }
336
337 mike 1.1 static MI_Result _GetProviderByClassName(
338 ProvMgr* self,
339 const char* libraryName,
340 MI_ConstString cn,
341 Provider** provOut
342 )
343 {
344 Library* lib;
345 Provider* prov;
346
347 /* Open the library */
348 {
349 lib = _OpenLibrary(self, libraryName);
350
351 if (!lib)
352 {
353 LOGW_CHAR(("failed to open provider library: %s", libraryName));
354 return MI_RESULT_FAILED;
355 }
356 }
357
358 mike 1.1 /* Open the provider */
359 {
360 prov = _OpenProvider(lib, cn);
361
362 if (!prov)
363 {
364 LOGW_CHAR(("failed to open the provider %s for class %s",
365 libraryName, cn));
366 return MI_RESULT_FAILED;
367 }
368 }
369
370 *provOut = prov;
371 return MI_RESULT_OK;
372 }
373
374 static MI_Result _Instance_InitConvert_FromBatch(
375 Batch* batch,
376 const MI_ClassDecl* cd,
377 const MI_SchemaDecl* sd,
378 MI_Instance* inst_in,
379 mike 1.1 MI_Boolean keys_only,
380 MI_Boolean allow_keyless_inst,
381 MI_Instance** instOut
382 )
383 {
384 MI_Instance* inst;
385 MI_Result r;
386
387 MI_UNUSED(sd);
388
389 /* Allocate the instance for the provider */
390 inst = (MI_Instance*)Batch_GetClear(batch, cd->size);
391
392 if (!inst)
393 {
394 LOGF((T("allocation failed")));
395 return MI_RESULT_FAILED;
396 }
397
|
415 mike 1.1 batch);
416
417 if (r != MI_RESULT_OK)
418 {
419 LOGW((T("instance conversion failed: %s, err %d"), cd->name, r));
420 return r;
421 }
422
423 *instOut = inst;
424 return MI_RESULT_OK;
425 }
426
427 static MI_Result _HandleGetInstanceReq(
428 ProvMgr* self,
429 const char* libraryName,
430 GetInstanceReq* msg,
431 Provider** prov)
432 {
433 MI_Instance* inst;
434 MI_Result r;
435 const MI_Char* className;
436 mike 1.1
437 /* Get classname from instance */
438 r = __MI_Instance_GetClassName(msg->instanceName, &className);
439
440 if (r != MI_RESULT_OK)
441 return r;
442
443 /* find provider */
444 r = _GetProviderByClassName(self, libraryName, className, prov);
445
446 if ( MI_RESULT_OK != r )
447 return r;
448
449 /* Allocate the instance for the provider */
450 r = _Instance_InitConvert_FromBatch(
451 msg->base.batch,
452 (*prov)->classDecl,
453 (*prov)->lib->module->schemaDecl,
454 msg->instanceName,
455 MI_TRUE,
456 MI_FALSE,
457 mike 1.1 &inst );
458
459 if (MI_RESULT_OK != r)
460 return r;
461
462 #if 0
463 /* Print instance */
464 Instance_Print(inst, stdout, 0);
465 #endif
466
467 /* If provider's GetInstance method null, use EnumerateInstances */
468 if ((*prov)->classDecl->providerFT->GetInstance == NULL)
469 {
470 Context* ctx;
471
472 if ((*prov)->classDecl->providerFT->EnumerateInstances == NULL)
473 return MI_RESULT_INVALID_CLASS;
474
475 /* Create context */
476 ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));;
477 Context_Init(ctx, (*prov));
478 mike 1.1 ctx->request = &msg->base;
479
480 /* _PostInstance() filters by this if not null */
481 ctx->instanceName = inst;
482
483 /* message will be freed in context release*/
484 Message_AddRef(&msg->base);
485
486 /* Invoke provider */
487 (*(*prov)->classDecl->providerFT->EnumerateInstances)(
488 (*prov)->self,
489 &ctx->base,
490 msg->nameSpace,
491 className,
492 NULL, /* propertSet */
493 MI_FALSE, /* keysOnly */
494 NULL); /* filter */
495 }
496 else
497 {
498 Context* ctx;
499 mike 1.1
500 /* Create context */
501 ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));;
502 Context_Init(ctx, (*prov));
503 ctx->request = &msg->base;
504
505 /* message will be freed in context release*/
506 Message_AddRef(&msg->base);
507
508 /* Invoke provider */
509 (*(*prov)->classDecl->providerFT->GetInstance)(
510 (*prov)->self,
511 &ctx->base,
512 msg->nameSpace,
513 className,
514 inst,
515 NULL);
516 }
517
518 return MI_RESULT_OK;
519 }
520 mike 1.1
521 static MI_Result _HandleCreateInstanceReq(
522 ProvMgr* self,
523 const char* libraryName,
524 CreateInstanceReq* msg,
525 Provider** prov)
526 {
527 MI_Instance* inst;
528 MI_Result r;
529 const MI_Char* className;
530
531 /* Get classname from instance */
532 r = __MI_Instance_GetClassName(msg->instance, &className);
533
534 if (r != MI_RESULT_OK)
535 return r;
536
537 /* find provider */
538 r = _GetProviderByClassName(self, libraryName, className, prov);
539
540 if ( MI_RESULT_OK != r )
541 mike 1.1 return r;
542
543 /* Allocate the instance for the provider */
544 r = _Instance_InitConvert_FromBatch(
545 msg->base.batch,
546 (*prov)->classDecl,
547 (*prov)->lib->module->schemaDecl,
548 msg->instance,
549 MI_FALSE,
550 MI_TRUE,
551 &inst );
552
553 if (MI_RESULT_OK != r)
554 return r;
555
556 /* Invoke provider */
557 if (!(*prov)->classDecl->providerFT->CreateInstance)
558 return MI_RESULT_INVALID_CLASS;
559
560 {
561 Context* ctx = (Context*)Batch_GetClear(msg->base.batch,
562 mike 1.1 sizeof(Context));;
563 Context_Init(ctx, (*prov));
564 ctx->request = &msg->base;
565 /* message will be freed in context release*/
566 Message_AddRef(&msg->base);
567 (*(*prov)->classDecl->providerFT->CreateInstance)((*prov)->self, &ctx->base,
568 msg->nameSpace, className, inst);
569 }
570
571 return MI_RESULT_OK;
572 }
573
574 static MI_Result _HandleModifyInstanceReq(
575 ProvMgr* self,
576 const char* libraryName,
577 ModifyInstanceReq* msg,
578 Provider** prov)
579 {
580 MI_Instance* inst;
581 MI_Result r;
582 const MI_Char* className;
583 mike 1.1
584 /* Get classname from instance */
585 r = __MI_Instance_GetClassName(msg->instance, &className);
586
587 if (r != MI_RESULT_OK)
588 return r;
589
590 /* find provider */
591 r = _GetProviderByClassName(self, libraryName, className, prov);
592
593 if ( MI_RESULT_OK != r )
594 return r;
595
596 /* Allocate the instance for the provider */
597 r = _Instance_InitConvert_FromBatch(
598 msg->base.batch,
599 (*prov)->classDecl,
600 (*prov)->lib->module->schemaDecl,
601 msg->instance,
602 MI_FALSE,
603 MI_FALSE,
604 mike 1.1 &inst );
605
606 if (MI_RESULT_OK != r)
607 return r;
608
609 /* Invoke provider */
610 if (!(*prov)->classDecl->providerFT->ModifyInstance)
611 return MI_RESULT_INVALID_CLASS;
612
613 {
614 Context* ctx = (Context*)Batch_GetClear(msg->base.batch,
615 sizeof(Context));;
616 Context_Init(ctx, (*prov));
617 ctx->request = &msg->base;
618 /* message will be freed in context release*/
619 Message_AddRef(&msg->base);
620 (*(*prov)->classDecl->providerFT->ModifyInstance)((*prov)->self, &ctx->base,
621 msg->nameSpace, className, inst, NULL);
622 }
623
624 return MI_RESULT_OK;
625 mike 1.1 }
626
627 static MI_Result _HandleDeleteInstanceReq(
628 ProvMgr* self,
629 const char* libraryName,
630 DeleteInstanceReq* msg,
631 Provider** prov)
632 {
633 MI_Instance* inst;
634 MI_Result r;
635 const MI_Char* className;
636
637 /* Get classname from instance */
638 r = __MI_Instance_GetClassName(msg->instanceName, &className);
639
640 if (r != MI_RESULT_OK)
641 return r;
642
643 /* find provider */
644 r = _GetProviderByClassName(self, libraryName, className, prov);
645
646 mike 1.1 if ( MI_RESULT_OK != r )
647 return r;
648
649 /* Allocate the instance for the provider */
650 r = _Instance_InitConvert_FromBatch(
651 msg->base.batch,
652 (*prov)->classDecl,
653 (*prov)->lib->module->schemaDecl,
654 msg->instanceName,
655 MI_TRUE,
656 MI_FALSE,
657 &inst);
658
659 if (MI_RESULT_OK != r)
660 return r;
661
662 /* Invoke provider */
663 if (!(*prov)->classDecl->providerFT->DeleteInstance)
664 return MI_RESULT_INVALID_CLASS;
665
666 {
667 mike 1.1 Context* ctx = (Context*)Batch_GetClear(msg->base.batch,
668 sizeof(Context));;
669 Context_Init(ctx, (*prov));
670 ctx->request = &msg->base;
671 /* message will be freed in context release*/
672 Message_AddRef(&msg->base);
673 (*(*prov)->classDecl->providerFT->DeleteInstance)((*prov)->self, &ctx->base,
674 msg->nameSpace, className, inst);
675 }
676
677 return MI_RESULT_OK;
678 }
679
680 static MI_Result _HandleSubscribeReq(
681 ProvMgr* self,
682 const char* libraryName,
683 SubscribeReq* msg,
684 Provider** prov)
685 {
686 MI_Result r;
687
688 mike 1.1 /* find provider */
689 r = _GetProviderByClassName( self, libraryName, msg->className, prov );
690
691 if ( MI_RESULT_OK != r )
692 return r;
693
694 /* Invoke provider */
695 if (!(*prov)->classDecl->providerFT->EnableIndications || !(*prov)->classDecl->providerFT->Subscribe)
696 return MI_RESULT_INVALID_CLASS;
697
698 if ((*prov)->ctxIndications.chainType == CTX_TYPE_IND_NOTINITIALIZED)
699 {
700 /* have to initialize provider first */
701 (*prov)->ctxIndications.chainType = CTX_TYPE_IND_READY;
702
703 (*prov)->classDecl->providerFT->EnableIndications((*prov)->self,
704 &(*prov)->ctxIndications.base, msg->nameSpace, msg->className);
705 }
706
707 if ((*prov)->ctxIndications.chainType == CTX_TYPE_IND_READY)
708 {
709 mike 1.1 /* provider is ready for subscriptions */
710 Context* ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));
711 Context_Init(ctx, (*prov));
712 ctx->request = &msg->base;
713 /* message will be freed in context release*/
714 Message_AddRef(&msg->base);
715 (*(*prov)->classDecl->providerFT->Subscribe)((*prov)->self, &ctx->base,
716 msg->nameSpace, msg->className, 0, __bookmark, msg->subscriptionID,
717 __subscriptionSelfPtr);
718 }
719 else
720 return MI_RESULT_FAILED; /* unexpected state */
721
722 return MI_RESULT_OK;
723 }
724
725 static MI_Result _HandleInvokeReq(
726 ProvMgr* self,
727 const char* libraryName,
728 InvokeReq* msg,
729 Provider** prov)
730 mike 1.1 {
731 MI_Instance* inst = 0;
732 MI_Instance* instParams = 0;
733 MI_Result r;
734 MI_ConstString cn = 0;
735 MI_MethodDecl* md = 0;
736
737 /* parameter validation */
738 if (!msg || !msg->function)
739 return MI_RESULT_INVALID_PARAMETER;
740
741 if (msg->className)
742 cn = msg->className;
743 else if (msg->instance)
744 cn = ((Instance*) msg->instance)->classDecl->name;
745
746 if (!cn)
747 return MI_RESULT_INVALID_CLASS;
748
749 /* find provider */
750 r = _GetProviderByClassName( self, libraryName, cn, prov );
751 mike 1.1
752 if ( MI_RESULT_OK != r )
753 return r;
754
755 /* find method declaration */
756 md = SchemaDecl_FindMethodDecl( (*prov)->classDecl, msg->function );
757
758 if (!md)
759 return MI_RESULT_FAILED;
760
761 /* if method is not static, instance must be provided */
762 if (!msg->instance && (md->flags & MI_FLAG_STATIC) != MI_FLAG_STATIC)
763 return MI_RESULT_INVALID_PARAMETER;
764
765 if (msg->instance)
766 {
767
768 r = _Instance_InitConvert_FromBatch(
769 msg->base.batch,
770 (*prov)->classDecl,
771 (*prov)->lib->module->schemaDecl,
772 mike 1.1 msg->instance,
773 MI_TRUE,
774 MI_FALSE,
775 &inst );
776
777 if (MI_RESULT_OK != r)
778 return r;
779 }
780
781 if (msg->instanceParams)
782 {
783 /* paramters (if any) */
784 r = _Instance_InitConvert_FromBatch(
785 msg->base.batch,
786 (const MI_ClassDecl*)md,
787 (*prov)->lib->module->schemaDecl,
788 msg->instanceParams,
789 MI_FALSE,
790 MI_TRUE,
791 &instParams );
792
793 mike 1.1 if (MI_RESULT_OK != r)
794 return r;
795 }
796
797 #if 0
798 /* Print instance */
799 Instance_Print(inst, stdout, 0);
800 #endif
801
802 /* Invoke provider */
803 if (!md->function)
804 return MI_RESULT_INVALID_CLASS;
805
806 {
807 Context* ctx = (Context*)Batch_GetClear(msg->base.batch, sizeof(Context));;
808 Context_Init(ctx, (*prov));
809 ctx->request = &msg->base;
810 /* message will be freed in context release*/
811 Message_AddRef(&msg->base);
812
813 /* call get first if fn is non-static */
814 mike 1.1 /*if (inst && (*prov)->classDecl->providerFT->GetInstance)
815 {
816 ctx->chainType = CTX_TYPE_INVOKE_WITH_INSTANCE;
817 ctx->inst = inst;
818 ctx->instParams = instParams;
819 ctx->md = md;
820 ctx->prov_self = (*prov)->self;
821
822 (*(*prov)->classDecl->providerFT->GetInstance)((*prov)->self, &ctx->base,
823 __nameSpace, __className, inst, NULL);
824 }
825 else */ /* for static - call invoke directly */
826 (*md->function)((*prov)->self, &ctx->base,
827 msg->nameSpace, cn, msg->function, inst, instParams);
828 }
829
830 return MI_RESULT_OK;
831 }
832
833 static MI_Result _HandleEnumerateInstancesReq(
834 ProvMgr* self,
835 mike 1.1 const char* libraryName,
836 EnumerateInstancesReq* msg,
837 Provider** prov)
838 {
839 Context* ctx;
840 MI_Result r;
841
842 /* find provider */
843 r = _GetProviderByClassName( self, libraryName, msg->className, prov );
844
845 if ( MI_RESULT_OK != r )
846 return r;
847
848 /* Validate WQL query (if any) against provider's class declaration */
849 if (msg->wql)
850 {
851 if (WQL_Validate(msg->wql, (*prov)->classDecl) != 0)
852 {
853 LOGW((T("query validation failed: %s"), msg->wql->text));
854 return MI_RESULT_INVALID_QUERY;
855 }
856 mike 1.1 }
857
858 /* Invoke provider */
859 if (!(*prov)->classDecl->providerFT->EnumerateInstances)
860 return MI_RESULT_NOT_SUPPORTED;
861
862 /* Create the context object */
863 {
864 ctx = (Context*)Batch_GetClear(
865 msg->base.batch, sizeof(Context));;
866
867 if (!ctx)
868 {
869 LOGF((T("allocation failed")));
870 return MI_RESULT_FAILED;
871 }
872
873 Context_Init(ctx, (*prov));
874 ctx->request = &msg->base;
875 }
876
877 mike 1.1 LOGD((T("enumerate instances of %s"), msg->className));
878
879 /* message will be freed in context release */
880 Message_AddRef(&msg->base);
881 (*(*prov)->classDecl->providerFT->EnumerateInstances)(
882 (*prov)->self, &ctx->base,
883 msg->nameSpace, msg->className, NULL, MI_FALSE, NULL);
884
885 return MI_RESULT_OK;
886 }
887
888 static MI_Result _HandleAssociatorsOfReq(
889 ProvMgr* self,
890 const char* libraryName,
891 AssociatorsOfReq* msg,
892 Provider** prov)
893 {
894 Context* ctx;
895 MI_Result r;
896 MI_Instance* inst = 0;
897
898 mike 1.1 /* find provider */
899 r = _GetProviderByClassName( self, libraryName, msg->className, prov );
900
901 if ( MI_RESULT_OK != r )
902 return r;
903
904 /* Invoke provider */
905 if (!(*prov)->classDecl->providerFT->AssociatorInstances)
906 return MI_RESULT_NOT_SUPPORTED;
907
908 if (!msg->instance)
909 return MI_RESULT_INVALID_PARAMETER;
910
911 {
912 Provider* provInst = 0;
913
914 r = _GetProviderByClassName( self, libraryName, ((Instance*) msg->instance)->classDecl->name, &provInst );
915
916 if ( MI_RESULT_OK != r )
917 return r;
918
919 mike 1.1 r = _Instance_InitConvert_FromBatch(
920 msg->base.batch,
921 provInst->classDecl,
922 (*prov)->lib->module->schemaDecl,
923 msg->instance,
924 MI_TRUE,
925 MI_FALSE,
926 &inst );
927
928 Provider_Release(provInst);
929
930 if (MI_RESULT_OK != r)
931 return r;
932 }
933
934 ctx = (Context*)Batch_GetClear(
935 msg->base.batch, sizeof(Context));;
936
937 if (!ctx)
938 {
939 LOGF((T("allocation failed")));
940 mike 1.1 return MI_RESULT_FAILED;
941 }
942
943 Context_Init(ctx, (*prov));
944 ctx->request = &msg->base;
945
946 /* message will be freed in context release */
947 Message_AddRef(&msg->base);
948 (*(*prov)->classDecl->providerFT->AssociatorInstances)(
949 (*prov)->self,
950 &ctx->base,
951 msg->nameSpace,
952 msg->className,
953 inst,
954 msg->resultClass,
955 msg->role,
956 msg->resultRole,
957 NULL, MI_FALSE, NULL);
958
959 return MI_RESULT_OK;
960 }
961 mike 1.1
962 static MI_Result _HandleReferencesOfReq(
963 ProvMgr* self,
964 const char* libraryName,
965 ReferencesOfReq* msg,
966 Provider** prov)
967 {
968 Context* ctx;
969 MI_Result r;
970 MI_Instance* inst = 0;
971
972 /* find provider */
973 r = _GetProviderByClassName( self, libraryName, msg->className, prov );
974
975 if ( MI_RESULT_OK != r )
976 return r;
977
978 /* Invoke provider */
979 if (!(*prov)->classDecl->providerFT->ReferenceInstances)
980 return MI_RESULT_NOT_SUPPORTED;
981
982 mike 1.1 if (!msg->instance)
983 return MI_RESULT_INVALID_PARAMETER;
984
985 {
986 Provider* provInst = 0;
987
988 r = _GetProviderByClassName(
989 self,
990 libraryName,
991 ((Instance*) msg->instance)->classDecl->name,
992 &provInst );
993
994 if ( MI_RESULT_OK != r )
995 return r;
996
997 r = _Instance_InitConvert_FromBatch(
998 msg->base.batch,
999 provInst->classDecl,
1000 (*prov)->lib->module->schemaDecl,
1001 msg->instance,
1002 MI_TRUE,
1003 mike 1.1 MI_FALSE,
1004 &inst );
1005
1006 Provider_Release(provInst);
1007
1008 if (MI_RESULT_OK != r)
1009 return r;
1010 }
1011
1012 ctx = (Context*)Batch_GetClear(
1013 msg->base.batch, sizeof(Context));;
1014
1015 if (!ctx)
1016 {
1017 LOGF((T("allocation failed")));
1018 return MI_RESULT_FAILED;
1019 }
1020
1021 Context_Init(ctx, (*prov));
1022 ctx->request = &msg->base;
1023
1024 mike 1.1 /* message will be freed in context release */
1025 Message_AddRef(&msg->base);
1026 (*(*prov)->classDecl->providerFT->ReferenceInstances)(
1027 (*prov)->self,
1028 &ctx->base,
1029 msg->nameSpace,
1030 msg->className,
1031 inst,
1032 msg->role,
1033 NULL, MI_FALSE, NULL);
1034
1035 return MI_RESULT_OK;
1036 }
1037
1038 static void _UnloadAllProviders(
1039 ProvMgr* self,
1040 Library* lib,
1041 MI_Boolean idleOnly,
1042 MI_Uint64 currentTimeUsec,
1043 MI_Uint64* nextFireAtTime)
1044 {
1045 mike 1.1 Provider* p, *p_next;
1046
1047 for (p = lib->head; p; )
1048 {
1049 MI_Uint64 provFireAtTime = p->idleSince + self->idleTimeoutUsec;
1050
1051 p_next = p->next;
1052
1053 /* unload if 'force' option passed or provider is idle long enough */
1054 if (!idleOnly ||
1055 (!p->refusedUnload && 0 == p->refCounter && provFireAtTime <= currentTimeUsec))
1056 {
1057 LOGD((T("Unloading provider %s"), p->classDecl->name));
1058
1059 /* Call provider unload() method */
1060 if (p->classDecl->providerFT->Unload)
1061 {
1062 Context ctx;
1063 Context_Init(&ctx, 0);
1064 (*p->classDecl->providerFT->Unload)(p->self, &ctx.base);
1065
1066 mike 1.1 DEBUG_ASSERT(ctx.magic == (MI_Uint32)-1);
1067 }
1068
1069 Context_Destroy(&p->ctxIndications);
1070
1071 if (p->refCounter != 0)
1072 {
1073 /* Error condition - unloading active rpovider! */
1074 LOGE((T("Unloading active provider %s, with ref counter %d"), p->classDecl->name, (int)p->refCounter));
1075 LOGE_CHAR(("Unloading active provider for lib %s, with ref counter %d", lib->libraryName, (int)p->refCounter));
1076
1077 // ATTN: _exit is a good option here, since provider's behavior maybe undefined
1078 _exit(1);
1079 }
1080
1081 List_Remove(
1082 (ListElem**)&lib->head,
1083 (ListElem**)&lib->tail,
1084 (ListElem*)p);
1085
1086 free(p);
1087 mike 1.1 }
1088 else if (idleOnly && 0 == p->refCounter && nextFireAtTime)
1089 {
1090 /* re-calculate idle timeout */
1091
1092 if (provFireAtTime < *nextFireAtTime)
1093 *nextFireAtTime = provFireAtTime;
1094 }
1095
1096 /* move to next one */
1097 p = p_next;
1098 }
1099 }
1100
1101 static void _UnloadAllLibraries(
1102 ProvMgr* self,
1103 MI_Boolean idleOnly,
1104 MI_Uint64 currentTimeUsec,
1105 MI_Uint64* nextFireAtTime)
1106 {
1107 Library* p, *p_next;
1108 mike 1.1
1109 /* release all (or idle-only) opened libraries */
1110 for (p = self->head; p; )
1111 {
1112 p_next = p->next;
1113
1114 _UnloadAllProviders(self,p,idleOnly,currentTimeUsec,nextFireAtTime);
1115
1116 /* Unload libraries that have no loaded providers */
1117 if (!p->head)
1118 {
1119 /* Invoke the module un-initialize function */
1120 if (p->module->Unload)
1121 {
1122 Context ctx;
1123 Context_Init(&ctx, 0);
1124 (p->module->Unload)(p->self, (MI_Context*)&ctx);
1125 Context_Destroy(&ctx);
1126 }
1127
1128 Lib_Close(p->handle);
1129 mike 1.1 LOGD_CHAR(("Unloading lib %s", p->libraryName));
1130
1131 List_Remove(
1132 (ListElem**)&self->head,
1133 (ListElem**)&self->tail,
1134 (ListElem*)p);
1135
1136 free(p);
1137 }
1138
1139 p = p_next;
1140 }
1141 }
1142
1143 /*
1144 Timeout handler: unloads idle providers and libraris,
1145 re-calculates new timeout (for next provider),
1146 notifies server/agent if all libraries are unloaded
1147 */
1148 static MI_Boolean _TimeoutCallback(
1149 Selector* sel,
1150 mike 1.1 Handler* handler,
1151 MI_Uint32 mask,
1152 MI_Uint64 currentTimeUsec)
1153 {
1154 MI_UNUSED(sel);
1155
1156 if (mask & SELECTOR_TIMEOUT)
1157 {
1158 ProvMgr* self = (ProvMgr*)handler->data;
1159 const MI_Uint64 u64max = ~ MI_ULL(0);
1160 MI_Uint64 nextFireAtTime = u64max;
1161
1162 /* Unload all idle providers */
1163 //LOGI((T("Unloading idle providers")));
1164
1165 _UnloadAllLibraries(self, MI_TRUE, currentTimeUsec, &nextFireAtTime);
1166
1167 if (u64max != nextFireAtTime)
1168 {
1169 /* re-set timeout */
1170 handler->fireTimeoutAt = nextFireAtTime;
1171 mike 1.1 }
1172 else
1173 {
1174 /* disbale timeout, since no more idle providers */
1175 handler->fireTimeoutAt = TIME_NEVER;
1176 }
1177
1178 /* If all libraries are gone, notify caller */
1179 if (!self->head && self->idleCallback)
1180 (*self->idleCallback)(self,self->idleCallbackData);
1181
1182 return MI_TRUE;
1183 }
1184
1185 if (mask & (SELECTOR_REMOVE | SELECTOR_DESTROY))
1186 {
1187 /* ignore it */
1188 }
1189
1190 return MI_TRUE;
1191 }
1192 mike 1.1
1193 /*
1194 **=============================================================================
1195 **
1196 ** Public defintions
1197 **
1198 **=============================================================================
1199 */
1200
1201 MI_Result ProvMgr_Init(
1202 ProvMgr* self,
1203 Selector* selector,
1204 ProvMgrCallbackOnIdle idleCallback,
1205 void* idleCallbackData,
1206 const char* providerDir)
1207 {
1208 if (!self || !providerDir)
1209 return MI_RESULT_INVALID_PARAMETER;
1210
1211 memset(self, 0, sizeof(ProvMgr));
1212
1213 mike 1.1 Strlcpy(self->providerDir, providerDir, sizeof(self->providerDir)-1);
1214
1215 self->idleTimeoutUsec = MI_ULL(90) * MI_ULL(1000000);
1216
1217 /* Add socket handler to catch timeout event */
1218
1219 self->timeoutHandler.sock = INVALID_SOCK;
1220 self->timeoutHandler.data = self;
1221 self->timeoutHandler.callback = _TimeoutCallback;
1222 self->idleCallback = idleCallback;
1223 self->idleCallbackData = idleCallbackData;
1224 self->selector = selector;
1225
1226 Selector_AddHandler(selector, &self->timeoutHandler);
1227
1228 return MI_RESULT_OK;
1229 }
1230
1231 MI_Result ProvMgr_Destroy(
1232 ProvMgr* self)
1233 {
1234 mike 1.1 if (!self)
1235 return MI_RESULT_INVALID_PARAMETER;
1236
1237 /* release opened libraries */
1238 _UnloadAllLibraries(self, MI_FALSE, 0, NULL);
1239
1240 memset(self, -1, sizeof(ProvMgr));
1241
1242 return MI_RESULT_OK;
1243 }
1244
1245 /*
1246 Routes incoming message to appropriate
1247 message handler based on message tag
1248 */
1249 MI_Result ProvMgr_PostMessage(
1250 ProvMgr* self,
1251 const char* libraryName,
1252 Message* msg)
1253 {
1254 Provider* prov = 0;
1255 mike 1.1 MI_Result r = MI_RESULT_INVALID_PARAMETER;
1256
1257 /* Check parameters */
1258 if (!self || !msg)
1259 return MI_RESULT_INVALID_PARAMETER;
1260
1261 /* Dispatch the message */
1262 switch (msg->tag)
1263 {
1264 case GetInstanceReqTag:
1265 {
1266 r = _HandleGetInstanceReq(self, libraryName,
1267 (GetInstanceReq*)msg, &prov);
1268 break;
1269 }
1270 case CreateInstanceReqTag:
1271 {
1272 r = _HandleCreateInstanceReq(self, libraryName,
1273 (CreateInstanceReq*)msg, &prov);
1274 break;
1275 }
1276 mike 1.1 case ModifyInstanceReqTag:
1277 {
1278 r = _HandleModifyInstanceReq(self, libraryName,
1279 (ModifyInstanceReq*)msg, &prov);
1280 break;
1281 }
1282 case DeleteInstanceReqTag:
1283 {
1284 r = _HandleDeleteInstanceReq(self, libraryName,
1285 (DeleteInstanceReq*)msg, &prov);
1286 break;
1287 }
1288 case InvokeReqTag:
1289 {
1290 r = _HandleInvokeReq(self, libraryName,
1291 (InvokeReq*)msg, &prov);
1292 break;
1293 }
1294 case EnumerateInstancesReqTag:
1295 {
1296 r = _HandleEnumerateInstancesReq(self, libraryName,
1297 mike 1.1 (EnumerateInstancesReq*)msg, &prov);
1298 break;
1299 }
1300 case AssociatorsOfReqTag:
1301 {
1302 r = _HandleAssociatorsOfReq(self, libraryName,
1303 (AssociatorsOfReq*)msg, &prov);
1304 break;
1305 }
1306 case ReferencesOfReqTag:
1307 {
1308 r = _HandleReferencesOfReq(self, libraryName,
1309 (ReferencesOfReq*)msg, &prov);
1310 break;
1311 }
1312 case SubscribeReqTag:
1313 {
1314 r = _HandleSubscribeReq(self, libraryName,
1315 (SubscribeReq*)msg, &prov);
1316 break;
1317 }
1318 mike 1.1
1319 default:
1320 break;
1321 }
1322
1323 Provider_Release(prov);
1324 return r;
1325 }
1326
1327 /*
1328 Increments provider's ref-counter
1329 */
1330 void Provider_Addref(Provider* provider)
1331 {
1332 if (provider)
1333 AtomicInc(&provider->refCounter);
1334 }
1335
1336 /*
1337 Decrements provider's ref-counter and
1338 marks provider as idle if ref-counter is 0 and
1339 mike 1.1 'refuse-unload' was not called
1340 */
1341 void Provider_Release(Provider* provider)
1342 {
1343 if (provider && AtomicDec(&provider->refCounter))
1344 {
1345 //LOGD((T("Releasing provider %s"), provider->classDecl->name));
1346
1347 if (!provider->refusedUnload)
1348 {
1349 /* Provider becomes idle */
1350 if (MI_RESULT_OK != Time_Now(&provider->idleSince))
1351 provider->idleSince = ~ (MI_Uint64)0;
1352
1353 //LOGD((T("Setting idle-since to ") UINT64_FMT_T T(" for provider %s"), provider->idleSince, provider->classDecl->name));
1354
1355 /* Set timer if it's first idle provider */
1356 if (TIME_NEVER == provider->lib->provmgr->timeoutHandler.fireTimeoutAt)
1357 {
1358 if (MI_RESULT_OK == Time_Now(&provider->lib->provmgr->timeoutHandler.fireTimeoutAt))
1359 {
1360 mike 1.1 provider->lib->provmgr->timeoutHandler.fireTimeoutAt += provider->lib->provmgr->idleTimeoutUsec;
1361
1362 //LOGD((T("Setting fire-at to ") UINT64_FMT_T, provider->lib->provmgr->timeoutHandler.fireTimeoutAt));
1363
1364 /* wakeup main thread */
1365 Selector_Wakeup(provider->lib->provmgr->selector);
1366 }
1367 }
1368 }
1369 }
1370 }
1371
1372 void Provider_SetRefuseUnloadFlag(Provider* provider, MI_Boolean flag)
1373 {
1374 provider->refusedUnload = flag;
1375 }
1376
1377 void Provider_NewInstanceCreated(
1378 Provider* provider,
1379 Message* msg)
1380 {
1381 mike 1.1 Selector_NewInstanceCreated(provider->lib->provmgr->selector, msg);
1382 }
|