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

  1 krisbash 1.1 /*============================================================================
  2               * Copyright (C) Microsoft Corporation, All rights reserved. 
  3               *============================================================================
  4               */
  5              
  6              #include <base/paths.h>
  7              #include "ProtocolHandlerCache.h"
  8              #include "InteractionProtocolHandler.h"
  9              #include <pal/atomic.h>
 10              #include <base/conf.h>
 11              
 12              struct _staticProtocolHandlers
 13              {
 14                  MI_Char *name;
 15                  ProtocolHandlerInitializeV1 dllFunctionPointer;
 16                  MI_Boolean defaultLocal;
 17                  MI_Boolean defaultRemote;
 18              }  g_staticallyLoadedProtocolHandlers[] =
 19              {
 20                  { MI_T("OMI_SOCKETS"), InteractionProtocolHandler_Application_Initialize, MI_TRUE, MI_FALSE}
 21              };
 22 krisbash 1.1 
 23              _Success_(return == MI_RESULT_OK)
 24              MI_Result ProtocolHandlerCache_InsertProtocolEntries(_Inout_ ProtocolHandlerCache *cache,
 25                          _In_z_ const char *protocolHandlerName,
 26                          _In_z_ const char *protocolHandlerDLL,
 27                          _In_z_ const char *protocolHandlerDllEntryPoint,
 28                          MI_Uint32 protocolHandlerMajorVersion,
 29                          MI_Uint32 protocolHandlerMinorVersion,
 30                          _Outptr_ ProtocolHandlerCacheItem **cacheItem)
 31              {
 32                  ProtocolHandlerCacheItem *item;
 33              
 34                  item = PAL_Malloc(sizeof(ProtocolHandlerCacheItem));
 35                  if (item == NULL)
 36                  {
 37                      return  MI_RESULT_SERVER_LIMITS_EXCEEDED;
 38                  }
 39              
 40                  memset(item, 0, sizeof(ProtocolHandlerCacheItem));
 41                  
 42                  TcsStrlcpy(item->name, protocolHandlerName, (sizeof(item->name)/sizeof(item->name[0])));
 43 krisbash 1.1     Strlcpy(item->dllPath, protocolHandlerDLL, sizeof(item->dllPath)/sizeof(item->dllPath[0]));
 44                  Strlcpy(item->dllEntryPoint, protocolHandlerDllEntryPoint, sizeof(item->dllEntryPoint)/sizeof(item->dllEntryPoint[0]));
 45              
 46                  /* Plug this into the head of the list */
 47                  item->nextItem = cache->cacheList;
 48                  cache->cacheList = item;
 49                  *cacheItem = item;
 50              
 51                  return MI_RESULT_OK;
 52              }
 53              
 54              _Success_(return == MI_RESULT_OK)
 55              MI_Result ProtocolHandlerCache_CreateAllProtocolEntries(_Inout_ ProtocolHandlerCache *cache)
 56              {
 57                  char _path[PAL_MAX_PATH_SIZE];
 58                  const char *path = NULL;
 59                  Conf *configSubSystem;
 60                  MI_Result ret = MI_RESULT_OK;
 61                  int staticHandlerLoop;
 62                  MI_Char defaultremoteprotocolhandler[30] = { 0 };
 63                  MI_Char defaultlocalprotocolhandler[30] = { 0 };
 64 krisbash 1.1     ProtocolHandlerCacheItem *cacheItem = NULL;
 65              
 66                  path = OMI_GetPath(ID_SYSCONFDIR);
 67                  if (path == NULL)
 68                  {
 69                      return MI_RESULT_FAILED;
 70                  }
 71              
 72                  /* Only need to copy on Windows as the paths are dynamic */
 73                  Strlcpy(_path, path, sizeof(_path)/sizeof(_path[0]));
 74                  Strlcat(_path, "/omicli.conf", PAL_MAX_PATH_SIZE);
 75                  path = _path;
 76              
 77                  configSubSystem = Conf_Open(path);
 78                  if (!configSubSystem)
 79                  {
 80                      /* err(ZT("failed to open configuration file: %s"), scs(path)); */
 81                      return MI_RESULT_FAILED;
 82                  }
 83              
 84                  for (;;)
 85 krisbash 1.1     {
 86                      const char* key;
 87                      const char* value;
 88                      int r = Conf_Read(configSubSystem, &key, &value);
 89              
 90                      if (r == -1)
 91                      {
 92                          /* err(ZT("%s: %s\n"), path, scs(Conf_Error(conf)));*/
 93                          ret = MI_RESULT_FAILED;
 94                          break;
 95                      }
 96              
 97                      if (r == 1)
 98                          break;
 99              
100                      if (strncmp(key, "protocolhandler", 15) == 0)
101                      {
102                          char *cursor;
103                          const char *protocolHandlerName;
104                          const char *protocolHandlerDLL;
105                          const char *protocolHandlerDllEntryPoint;
106 krisbash 1.1             MI_Uint32 protocolHandlerMajorVersion;
107                          MI_Uint32 protocolHandlerMinorVersion;
108              
109                          /* We found a protocol handler, need to */
110              
111                          /* First protocol handler name */
112                          cursor = Strchr(value, ',');
113                          if (cursor == NULL)
114                          {
115                              ret = MI_RESULT_FAILED;
116                              break;
117                          }
118                          *cursor = '\0';
119                          protocolHandlerName = value;
120              
121                          value = cursor+1; /* move past ',' */
122                          
123                          /* Second DLL*/
124                          cursor = Strchr(value, ',');
125                          if (cursor == NULL)
126                          {
127 krisbash 1.1                 ret = MI_RESULT_FAILED;
128                              break;
129                          }
130              
131                          protocolHandlerDLL = value;
132                          value = cursor+1; /* move past ',' */
133              
134                          /* Third DLL entry point */
135                          cursor = Strchr(value, ',');
136                          if (cursor == NULL)
137                          {
138                              ret = MI_RESULT_FAILED;
139                              break;
140                          }
141                          protocolHandlerDllEntryPoint = value;
142                          value = cursor+1; /* move past ',' */
143              
144                          /* Forth is major version */
145                          protocolHandlerMajorVersion = Strtoul(value, &cursor, 10);
146                          if (*cursor != ',')
147                          {
148 krisbash 1.1                 ret = MI_RESULT_FAILED;
149                              break;
150                          }
151                          value = cursor+1; /* move past ',' */
152              
153                          /* Fifth is minor version */
154                          protocolHandlerMinorVersion = Strtoul(value, &cursor, 10);
155                          if (*cursor != '\0')
156                          {
157                              ret = MI_RESULT_FAILED;
158                              break;
159                          }
160                          ret = ProtocolHandlerCache_InsertProtocolEntries(cache, protocolHandlerName, protocolHandlerDLL, protocolHandlerDllEntryPoint, protocolHandlerMajorVersion, protocolHandlerMinorVersion, &cacheItem);
161                          if (ret != MI_RESULT_OK)
162                              break;
163                      }
164                      else if (strncmp(key, "defaultlocalprotocolhandler", 27) == 0)
165                      {
166                          TcsStrlcpy(defaultlocalprotocolhandler, value, sizeof(defaultlocalprotocolhandler)/sizeof(defaultlocalprotocolhandler[0]));
167                      }
168                      else if (strncmp(key, "defaultremoteprotocolhandler", 28) == 0)
169 krisbash 1.1         {
170                          TcsStrlcpy(defaultremoteprotocolhandler, value, sizeof(defaultremoteprotocolhandler)/sizeof(defaultremoteprotocolhandler[0]));
171                      }
172                  }
173                  /* Close configuration file */
174                  Conf_Close(configSubSystem);
175              
176                  /* Fix up the config-based default handlers */
177                  if (defaultlocalprotocolhandler[0] || defaultremoteprotocolhandler[0])
178                  {
179                      cacheItem = cache->cacheList;
180                      while (cacheItem)
181                      {
182                          if (Tcscmp(defaultlocalprotocolhandler, cacheItem->name) == 0)
183                          {
184                              cache->defaultLocalItem = cacheItem;
185                          }
186                          else if (Tcscmp(defaultremoteprotocolhandler, cacheItem->name) == 0)
187                          {
188                              cache->defaultRemoteItem = cacheItem;
189                          }
190 krisbash 1.1             cacheItem = cacheItem->nextItem;
191                      }
192                  }
193              
194                  if (ret == MI_RESULT_OK)
195                  {
196                      /* Handler staticly compiled in ones now */
197                      for (staticHandlerLoop = 0; staticHandlerLoop != sizeof(g_staticallyLoadedProtocolHandlers)/sizeof(g_staticallyLoadedProtocolHandlers[0]); staticHandlerLoop++)
198                      {
199                          ProtocolHandlerCacheItem *item;
200                          if (g_staticallyLoadedProtocolHandlers[staticHandlerLoop].name == NULL)
201                              break;
202              
203                          item = PAL_Malloc(sizeof(ProtocolHandlerCacheItem));
204                          if (item == NULL)
205                          {
206                              ret = MI_RESULT_SERVER_LIMITS_EXCEEDED;
207                              break;
208                          }
209                          memset(item, 0, sizeof(ProtocolHandlerCacheItem));
210              
211 krisbash 1.1             Tcslcpy(item->name, g_staticallyLoadedProtocolHandlers[staticHandlerLoop].name, sizeof(item->name)/sizeof(item->name[0]));
212              
213                          item->dllFunctionPointer = g_staticallyLoadedProtocolHandlers[staticHandlerLoop].dllFunctionPointer;
214              
215                          /* Plug this into the head of the list */
216                          item->nextItem = cache->cacheList;
217                          cache->cacheList = item;
218              
219                          if (g_staticallyLoadedProtocolHandlers[staticHandlerLoop].defaultLocal && (cache->defaultLocalItem == NULL))
220                              cache->defaultLocalItem = item;
221                          if (g_staticallyLoadedProtocolHandlers[staticHandlerLoop].defaultRemote && (cache->defaultRemoteItem == NULL))
222                              cache->defaultRemoteItem = item;
223                      }
224                  }
225              
226                  /* if there is an error, free all transports */
227                  if (ret != MI_RESULT_OK)
228                  {
229                      while (cache->cacheList)
230                      {
231                          ProtocolHandlerCacheItem *item;
232 krisbash 1.1             item = cache->cacheList;
233              
234                          /* unlink this item from list */
235                          cache->cacheList = item->nextItem;
236              
237                          PAL_Free(item);
238                      }
239                  }
240                  return ret;
241              }
242              
243              /* PUBLIC: ProtocolHandlerCache_Initialize
244               * Initializes the cache.  Cache needs to be deinitialized when finished with.
245               *
246               * cache - Pointer to a ProtocolHandlerCache to be initialized
247               *
248               * Returns:
249               *      ERROR_OUTOFMEMORY
250               *      ERROR_SUCCESS
251               */
252              MI_EXTERN_C MI_Result ProtocolHandlerCache_Initialize(_In_opt_z_ const MI_Char *applicationId, _Out_ ProtocolHandlerCache *cache)
253 krisbash 1.1 {
254                  memset(cache, 0, sizeof(ProtocolHandlerCache));
255              
256                  cache->applicationID = applicationId;
257              
258                  /* Initialize the cache lock */
259                  if (CachedLock_Init(&cache->lock, CACHEDLOCK_FLAG_SHARED) != 0)
260                  {
261                      return MI_RESULT_SERVER_LIMITS_EXCEEDED;
262                  }
263              
264                  return ProtocolHandlerCache_CreateAllProtocolEntries(cache);
265              }
266              
267              /* PRIVATE: Unload a protocol handler.  This will call MI_Application_Close on the handler
268               * if there is a function table, which is a blocking option... therefore
269               * it will try and cancel all active sessions and operations.  The client
270               * will need to close any outstanding handles otherwise this will block forever.
271               * When closed it unloads the DLL, so if there are any active threads after the 
272               * fact things will crash.  It is the responsibility of the protocol handler
273               * to make sure this does not happen.
274 krisbash 1.1  */
275              void ProtocolHandlerCache_UnloadProtocolHandler(_Inout_  ProtocolHandlerCacheItem *itemPointer)
276              {
277                  ptrdiff_t currentApiCount;
278              
279                  if (itemPointer->dllInitialized == MI_TRUE)
280                  {
281                      /*Wait for the API count to hit 0 */
282                      currentApiCount = itemPointer->outstandingProtocolHandlerCalls;
283                      while (currentApiCount != 0)
284                      {
285                          CondLock_Wait((ptrdiff_t)itemPointer, &(itemPointer)->outstandingProtocolHandlerCalls, currentApiCount, CONDLOCK_DEFAULT_SPINCOUNT);
286                          currentApiCount = (itemPointer)->outstandingProtocolHandlerCalls;
287                      }
288              
289                      if (itemPointer->application.ft)
290                      {
291                          MI_Application_Close(&itemPointer->application);
292                      }
293                      if (itemPointer->dllHandle != NULL)
294                      {
295 krisbash 1.1             Shlib_Close(itemPointer->dllHandle);
296                      }
297              
298                      itemPointer->dllInitialized = MI_FALSE;
299                  }
300              }
301              
302              /* PUBLIC: ProtocolHandlerCache_DeInitialize
303               * Shuts down the cache, unloading all cache entries in the process.
304               *
305               * cache - Pointer to a ProtocolHandlerCache to be deinitialized
306               *
307               * Returns:
308               *      ERROR_SUCCESS
309               */
310              MI_EXTERN_C MI_Result ProtocolHandlerCache_DeInitialize(_Inout_ ProtocolHandlerCache *cache)
311              {
312                  CachedLock_AcquireWrite(&cache->lock);
313              
314                  /* Free all transports */
315                  while (cache->cacheList)
316 krisbash 1.1     {
317                      ProtocolHandlerCacheItem *item = cache->cacheList;
318              
319                      /* unlink this item from list */
320                      cache->cacheList = cache->cacheList->nextItem;
321              
322                      /* unload and free it */
323                      ProtocolHandlerCache_UnloadProtocolHandler(item);
324                      PAL_Free(item);
325                  }
326              
327                  CachedLock_ReleaseWrite(&cache->lock);
328              
329                  /* Cleanup lock */
330                  CachedLock_Destroy(&cache->lock);
331              
332                  return MI_RESULT_OK;
333              }
334              
335              /* LOCK MUST ALREADY BE AQUIRED */
336              _Success_(return == MI_RESULT_OK)
337 krisbash 1.1 MI_Result ProtocolHandlerCache_FindProtocolHandler(_Inout_ ProtocolHandlerCache *cache, _In_z_ const MI_Char *name, _Outptr_ ProtocolHandlerCacheItem **cacheItem)
338              {
339                  ProtocolHandlerCacheItem *currentItem = cache->cacheList;
340              
341                  while (currentItem)
342                  {
343                      if (Tcscmp(name, currentItem->name) == 0)
344                      {
345                          /* Found it! */
346                          break;
347                      }
348                      currentItem = currentItem->nextItem;
349                  }
350                  if (currentItem)
351                  {
352                      *cacheItem = currentItem;
353                      return MI_RESULT_OK;
354                  }
355                  else
356                  {
357                      /* Not there */
358 krisbash 1.1         return MI_RESULT_NOT_FOUND;
359                  }
360              }
361              
362              
363              /* Assumption: Protocol handler has not already been loaded.
364               * This method will get the details of the protocol handler from config, load it
365               * and call the MI_Application_Initialize method on the handler.
366              */
367              _Success_(return == MI_RESULT_OK)
368              MI_Result ProtocolHandlerCache_LoadProtocolHandler(_Inout_ ProtocolHandlerCache *cache, _Inout_ ProtocolHandlerCacheItem *item)
369              {
370                  MI_Result returnCode;
371                  ProtocolHandlerInitializeV1 initializerFunction;
372              
373                  if (item->dllInitialized == MI_TRUE)
374                  {
375                      /* Already initialized */
376                      return MI_RESULT_OK;
377                  }
378              
379 krisbash 1.1     if ((item->majorVersion != 1) && (item->minorVersion != 0))
380                  {
381                      /* Not a supported version */
382                      return MI_RESULT_FAILED;
383                  }
384              
385                  if (item->dllFunctionPointer)
386                  {
387                      initializerFunction = item->dllFunctionPointer;
388                  }
389                  else
390                  {
391                      TChar buf[PAL_MAX_PATH_SIZE];
392                      if (TcsStrlcpy(buf, item->dllPath, PAL_MAX_PATH_SIZE) >= PAL_MAX_PATH_SIZE)
393                          return MI_RESULT_FAILED;
394              
395                      item->dllHandle = Shlib_Open(buf);
396                      if (item->dllHandle == NULL)
397                      {
398                          return MI_RESULT_FAILED;
399                      }
400 krisbash 1.1 
401                      initializerFunction = (ProtocolHandlerInitializeV1)Shlib_Sym(item->dllHandle, item->dllEntryPoint);
402                      if (initializerFunction == NULL)
403                      {
404                          Shlib_Close(item->dllHandle);
405                          item->dllHandle = NULL;
406                          return MI_RESULT_NOT_SUPPORTED;
407                      }
408                  }
409              
410                  /* Handle flags, and extendedError! */
411                  returnCode = initializerFunction(0, cache->applicationID, NULL, &item->application);
412                  if (returnCode != MI_RESULT_OK)
413                  {
414                      if (item->dllHandle)
415                      {
416                          Shlib_Close(item->dllHandle);
417                          item->dllHandle = NULL;
418                      }
419              
420                      if (item->dllEntryPoint)
421 krisbash 1.1         {
422                          item->dllFunctionPointer = NULL;
423                      }
424                      return returnCode;
425                  }
426              
427                  item->dllInitialized = MI_TRUE;
428                  return MI_RESULT_OK;
429              }
430              
431              /* Retrieves a protocol handler.  If it has not been loaded and initialized it will do so.
432               * Fast case is when it has already been loaded and it grabs a fast read lock.  If an update
433               * is being done this call will block until that is complete.
434               */
435              _Success_(return == MI_RESULT_OK)
436              MI_EXTERN_C MI_Result ProtocolHandlerCache_GetProtocolHandler(_Inout_ ProtocolHandlerCache *cache, _In_z_ const MI_Char *name, _Outptr_ ProtocolHandlerCacheItem **cacheItem)
437              {
438                  MI_Result returnCode = MI_RESULT_OK;
439              
440                  *cacheItem = NULL;
441              
442 krisbash 1.1     /* Read lock to determine if the object exists.  This is the fast path. */
443                  ReadWriteLock_AcquireRead(&cache->lock);
444              
445                  returnCode = ProtocolHandlerCache_FindProtocolHandler(cache, name, cacheItem);
446              
447                  ReadWriteLock_ReleaseRead(&cache->lock);
448              
449                  if (returnCode != MI_RESULT_OK)
450                  {
451                      return returnCode;
452                  }
453              
454                  if ((*cacheItem)->dllInitialized == MI_FALSE)
455                  {
456                      ReadWriteLock_AcquireWrite(&cache->lock);
457                      returnCode = ProtocolHandlerCache_LoadProtocolHandler(cache, *cacheItem);
458                      ReadWriteLock_ReleaseWrite(&cache->lock);
459                  }
460              
461                  return returnCode;
462              }
463 krisbash 1.1 
464              MI_Result ProtocolHandlerCache_IncrementApiCount(_Inout_ ProtocolHandlerCacheItem *cacheItem)
465              {
466                  Atomic_Inc(&cacheItem->outstandingProtocolHandlerCalls);
467                  return MI_RESULT_OK;
468              }
469              MI_Result ProtocolHandlerCache_DecrementApiCount(_Inout_ ProtocolHandlerCacheItem *cacheItem)
470              {
471                  if (Atomic_Dec(&cacheItem->outstandingProtocolHandlerCalls) == 0)
472                  {
473                      //Signal we are at 0 in case we are trying to shutdown this item
474                      CondLock_Broadcast((ptrdiff_t)cacheItem);
475              
476                  }
477                  return MI_RESULT_OK;
478              }

ViewCVS 0.9.2