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

   1 mike  1.1 /*
   2           **==============================================================================
   3           **
   4           ** Open Management Infrastructure (OMI)
   5           **
   6           ** Copyright (c) Microsoft Corporation
   7           ** 
   8           ** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
   9           ** use this file except in compliance with the License. You may obtain a copy 
  10           ** of the License at 
  11           **
  12           **     http://www.apache.org/licenses/LICENSE-2.0 
  13           **
  14           ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15           ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
  16           ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
  17           ** MERCHANTABLITY OR NON-INFRINGEMENT. 
  18           **
  19           ** See the Apache 2 License for the specific language governing permissions 
  20           ** and limitations under the License.
  21           **
  22 mike  1.1 **==============================================================================
  23           */
  24           
  25           #include "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           
 398 mike  1.2 #if 0
 399               if (inst_in)
 400               {
 401                   printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
 402                   MI_Instance_Print(inst_in, stdout, 1);
 403                   printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
 404               }
 405           #endif
 406           
 407 mike  1.1     /* Convert instance name to provider's format (borrow storage) */
 408 mike  1.2     r = Instance_InitConvert(
 409                   inst, 
 410                   cd, 
 411                   inst_in, 
 412                   keys_only, 
 413                   allow_keyless_inst, 
 414                   MI_FALSE,
 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           }

ViewCVS 0.9.2