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

  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 <protocol/protocol.h>
 26 krisbash 1.3 #include <pal/sleep.h>
 27 mike     1.1 #include <provmgr/provmgr.h>
 28 krisbash 1.3 #include <pal/strings.h>
 29 mike     1.1 #include <base/log.h>
 30              #include <base/env.h>
 31              #include <base/paths.h>
 32 krisbash 1.3 #include <base/omigetopt.h>
 33              #include <base/multiplex.h>
 34              #include <base/Strand.h>
 35              #include <pal/format.h>
 36 mike     1.1 #include <sys/types.h>
 37 krisbash 1.3 #include <sys/resource.h>
 38 mike     1.1 #include <pwd.h>
 39              #include <grp.h>
 40              
 41 krisbash 1.3 STRAND_DEBUGNAME( IdleNotification );
 42 mike     1.1 
 43              typedef struct _AgentData AgentData;
 44              
 45              struct _AgentData
 46              {
 47 krisbash 1.3     MuxIn                   mux;
 48                  ProtocolSocketAndBase*  protocol;
 49                  ProvMgr                 provmgr;
 50                  Selector                selector;
 51                  Strand                  idleNotificationStrand;
 52 mike     1.1 } ;
 53              
 54              typedef struct _Options
 55              {
 56                  const char* provDir;
 57                  MI_Boolean help;
 58                  MI_Uint32   idletimeout;
 59              } 
 60              Options;
 61              
 62              static AgentData  s_data;
 63              
 64              static Options s_opts;
 65              static const char* arg0 = 0;
 66 krisbash 1.3 static const ZChar HELP[] = ZT("\
 67 mike     1.1 Usage: %s [OPTIONS]\n\
 68              \n\
 69              This program starts the OMI agent.\n\
 70              \n\
 71              OPTIONS:\n\
 72                  --version           Print version information.\n\
 73                  --providerdir       Find providers in this directory.\n\
 74 krisbash 1.3     --loglevel LEVEL    Set the log level (0-5).\n\
 75              \n");
 76 mike     1.1 
 77              PRINTF_FORMAT(1, 2)
 78 krisbash 1.3 static void FUNCTION_NEVER_RETURNS err(const ZChar* fmt, ...)
 79 mike     1.1 {
 80 krisbash 1.3     ZChar* buf = NULL;
 81                  ZChar* buf2 = NULL;
 82 mike     1.1     va_list ap;
 83 krisbash 1.3     size_t buflen = PAL_MAX_PATH_SIZE;
 84                  buf = (ZChar*) PAL_Malloc( sizeof(ZChar) * buflen * 2 );
 85                  if (buf)
 86                  {
 87                      buf2 = buf + buflen;
 88              
 89                      memset(&ap, 0, sizeof(ap));
 90                      va_start(ap, fmt);
 91                      Vstprintf(buf, buflen, fmt, ap);
 92                      va_end(ap);
 93                      Stprintf(buf2, buflen, ZT("%s: %T"), scs(arg0), buf);
 94 mike     1.1 
 95 krisbash 1.3         Ftprintf(stderr, ZT("%T\n"), buf2);
 96                      trace_CriticalError(buf2);
 97 mike     1.1 
 98 krisbash 1.3         PAL_Free(buf);
 99                  }
100                  exit(1);
101              }
102 mike     1.1 
103 krisbash 1.3 /* enable core dump for current process */
104              static void _EnableCoreDump()
105              {
106                  struct rlimit core_limits;
107                  core_limits.rlim_cur = RLIM_INFINITY;
108                  core_limits.rlim_max = RLIM_INFINITY;
109                  setrlimit(RLIMIT_CORE, &core_limits);
110 mike     1.1 }
111              
112 krisbash 1.3 void _IdleNotification_Post( _In_ Strand* self_, _In_ Message* msg)
113 mike     1.1 {
114 krisbash 1.3     DEBUG_ASSERT( MI_FALSE );  // not used
115              }
116 mike     1.1 
117 krisbash 1.3 void _IdleNotification_PostControl( _In_ Strand* self_, _In_ Message* msg)
118              {
119                  DEBUG_ASSERT( MI_FALSE );  // not used
120              }
121 mike     1.1 
122 krisbash 1.3 void _IdleNotification_Ack( _In_ Strand* self_ )
123              {
124                  // Nothing to do
125 mike     1.1 }
126              
127 krisbash 1.3 void _IdleNotification_Finish( _In_ Strand* self_ )
128 mike     1.1 {
129 krisbash 1.3     // Nothing to do
130              }
131 mike     1.1 
132 krisbash 1.3 /*
133                  Object that is just used to send to agent manager BinProtocolNotification 
134 mike     1.1 
135 krisbash 1.3     Behavior:
136                  - It is created when the initial BinProtocolNotification is sent by the server
137                     then kept alive as long as the connection is alive.
138                  - Post, PostControl and Ack are not actually used
139                  - Shutdown: 
140                     The objects are deleted thru the normal Strand logic once the connection is closed.
141              
142                  Unique features and special Behavior:
143                  - If the agent is idle it will be use to post a BinProtocolNotification
144                     thru the many-to-one interface so there are no problem or races with
145                     a request being received or a response to a normal request going out 
146                     at the same time
147              */
148              static StrandFT _IdleNotification_FT = { 
149                  _IdleNotification_Post, 
150                  _IdleNotification_PostControl, 
151                  _IdleNotification_Ack, 
152                  NULL, 
153                  NULL,
154                  _IdleNotification_Finish,
155                  NULL,
156 krisbash 1.3     NULL,
157                  NULL,
158                  NULL,
159                  NULL,
160                  NULL };
161              
162              /* Called by mux to dispatch an incoming request message */
163              static void _RequestCallback(
164                  _Inout_     InteractionOpenParams*    interactionParams )
165              {
166                  DEBUG_ASSERT( NULL != interactionParams );
167                  DEBUG_ASSERT( NULL != interactionParams->msg );
168                  DEBUG_ASSERT( NULL == interactionParams->callbackData );
169 mike     1.1 
170 krisbash 1.3     if (BinProtocolNotificationTag == interactionParams->msg->tag)
171 mike     1.1     {
172 krisbash 1.3         BinProtocolNotification* notification = (BinProtocolNotification*)interactionParams->msg;
173                      (void) notification; /* In case DEBUG_ASSERT is compiled out, avoid compiler warnings */
174 mike     1.1 
175 krisbash 1.3         DEBUG_ASSERT(BinNotificationAgentIdle == notification->type);
176                      
177                      Strand_Init( STRAND_DEBUG(IdleNotification) &s_data.idleNotificationStrand, &_IdleNotification_FT, 0, interactionParams );
178                  }
179                  else
180                  {
181                      MI_Result result;
182                      ProvRegEntry regentry;
183                      RequestMsg* request = (RequestMsg*)interactionParams->msg;
184 mike     1.1 
185 krisbash 1.3         DEBUG_ASSERT( Message_IsRequest(interactionParams->msg) );
186 mike     1.1 
187 krisbash 1.3         memset(&regentry, 0, sizeof(regentry));
188                      regentry.libraryName = request->libraryName;
189                      regentry.instanceLifetimeContext = request->instanceLifetimeContext;
190 mike     1.1 
191 krisbash 1.3         result = ProvMgr_NewRequest(&s_data.provmgr, &regentry, interactionParams );
192                      
193                      if (MI_RESULT_OK != result)
194                      {
195                          trace_Agent_ProvMgrNewRequest_Failed( result );
196                          Strand_FailOpenWithResult(interactionParams, result, PostResultMsg_NewAndSerialize);
197                      }
198 mike     1.1     }
199              }
200              
201              static void GetCommandLineDestDirOption(
202                  int* argc_,
203                  const char* argv[])
204              {
205                  int argc = *argc_;
206                  int i;
207                  const char* destdir = NULL;
208              
209                  for (i = 1; i < argc; )
210                  {
211                      if (strcmp(argv[i], "--destdir") == 0)
212                      {
213                          if (i + 1 == argc)
214 krisbash 1.3                 err(ZT("missing argument for --destdir option"));
215 mike     1.1 
216                          destdir = argv[i+1];
217                          memmove((char*)&argv[i], (char*)&argv[i+2], 
218                              sizeof(char*) * (argc-i-1));
219                          argc -= 2;
220                      }
221                      else if (strncmp(argv[i], "--destdir=", 10) == 0)
222                      {
223                          destdir = argv[i] + 10;
224                          memmove((char*)&argv[i], (char*)&argv[i+1], 
225                              sizeof(char*) * (argc-i));
226              
227                          argc -= 1;
228                      }
229                      else
230                          i++;
231                  }
232              
233                  if (destdir)
234                  {
235                      if (SetPath(ID_DESTDIR, destdir) != 0)
236 krisbash 1.3             err(ZT("failed to set destdir"));
237 mike     1.1     }
238              
239                  *argc_ = argc;
240              }
241              
242              static void GetCommandLineOptions(int* argc, const char* argv[])
243              {
244                  GetOptState state = GETOPTSTATE_INITIALIZER;
245                  const char* opts[] =
246                  {
247                      "-h",
248                      "--help",
249                      "-v",
250                      "--version",
251                      "--providerdir:",
252                      "--idletimeout:",
253                      "--loglevel:",
254                      NULL,
255                  };
256              
257                  for (;;)
258 mike     1.1     {
259                      int r = GetOpt(argc, argv, opts, &state);
260              
261                      if (r == 1)
262                          break;
263              
264                      if (r == -1)
265 krisbash 1.3             err(ZT("%s"), scs(state.err));
266 mike     1.1 
267                      /* Check for -h option */
268                      if (strcmp(state.opt, "-h") == 0 || strcmp(state.opt, "--help") == 0)
269                      {
270                          s_opts.help = MI_TRUE;
271                      }
272                      else if (strcmp(state.opt, "--version") == 0)
273                      {
274 krisbash 1.3             Tprintf(ZT("%s: %s\n"), scs(arg0),
275                              scs(CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE));
276 mike     1.1             exit(0);
277                      }
278                      else if (strcmp(state.opt, "--providerdir") == 0)
279                      {
280                          s_opts.provDir = state.arg;
281                      }
282                      else if (strcmp(state.opt, "--idletimeout") == 0)
283                      {
284                          char* end;
285                          MI_Uint64 x = Strtoull(state.arg, &end, 10);
286              
287                          if (*end != '\0')
288 krisbash 1.3             {
289                              err(ZT("bad option argument for --idletimeout: %s"), 
290                                  scs(state.arg));
291                          }
292 mike     1.1 
293                          s_opts.idletimeout = x;
294                      }
295                      else if (strcmp(state.opt, "--loglevel") == 0)
296                      {
297                          if (Log_SetLevelFromString(state.arg) != 0)
298                          {
299 krisbash 1.3                 err(ZT("bad option argument for %s: %s"), 
300                                  scs(state.opt), scs(state.arg));
301 mike     1.1             }
302                      }
303                  }
304              }
305              
306 krisbash 1.3 static void _OnCloseCallback(
307                  _In_        void*       object)
308              {
309                  MI_UNUSED(object);
310 mike     1.1 
311 krisbash 1.3     trace_Agent_DisconnectedFromServer();
312                  Selector_StopRunning(&s_data.selector);
313 mike     1.1 }
314              
315              static void _ProvMgrCallbackOnIdle(
316                  ProvMgr* mgr,
317                  void* callbackData)
318              {
319                  BinProtocolNotification* notification;
320              
321                  MI_UNUSED(mgr);
322                  MI_UNUSED(callbackData);
323              
324 krisbash 1.3     DEBUG_ASSERT( s_data.idleNotificationStrand.info.opened );
325              
326                  trace_Agent_SendingIdleNotification();
327 mike     1.1 
328                  notification = BinProtocolNotification_New( BinNotificationAgentIdle );
329              
330                  if (!notification)
331 krisbash 1.3     {
332                      // Nothing we can do here
333                      DEBUG_ASSERT( MI_FALSE );
334 mike     1.1         return;
335 krisbash 1.3     }
336                  
337                  // Call on the always opened idle notification strand
338                  Strand_SchedulePost( &s_data.idleNotificationStrand, &notification->base);
339 mike     1.1 
340                  BinProtocolNotification_Release(notification);
341              }
342              
343              int agent_main(int argc, const char* argv[])
344              {
345                  MI_Result r;
346                  Sock fd;
347                  int logfd;
348              
349                  arg0 = argv[0];
350              
351                  memset(&s_data, 0, sizeof(s_data));
352              
353 krisbash 1.3     /* Enable core dump */
354                  _EnableCoreDump();
355              
356 mike     1.1     /* Get --destdir option first (other options may depend on it) */
357                  GetCommandLineDestDirOption(&argc, argv);
358              
359                  /* Extract options */
360                  GetCommandLineOptions(&argc, argv);
361              
362                  /* Print help */
363                  if (s_opts.help)
364                  {
365 krisbash 1.3         Ftprintf(stderr, HELP, scs(arg0));
366 mike     1.1         exit(1);
367                  }
368              
369                  /* extract socket number */
370                  if (argc < 3)
371                  {
372 krisbash 1.3         trace_Agent_FDParameterIsMissing();
373 mike     1.1         exit(1);
374                  }
375              
376                  fd = Strtol(argv[1], 0, 10);
377                  logfd = Strtol(argv[2], 0, 10);
378              
379                  /* Attach log file */
380                  {
381                      /* Open the log file */
382                      if (Log_OpenFD(logfd) != MI_RESULT_OK)
383                      {
384 krisbash 1.3             err(ZT("failed to attach log file to fd: %d; errno %d"), logfd, 
385 mike     1.1                 (int)errno);
386                      }
387                  }
388              
389                  /* selector */
390                  {
391                      /* Initialize the network */
392                      Sock_Start();
393              
394                      if(Selector_Init(&s_data.selector) != MI_RESULT_OK)
395 krisbash 1.3             err(ZT("Selector_Init() failed"));
396              
397                      Timer_SetSelector(&s_data.selector);
398 mike     1.1     }
399              
400 krisbash 1.3     /* mux */
401                  {
402                      if(MuxIn_Init(&s_data.mux, _RequestCallback, NULL, _OnCloseCallback, PostResultMsg_NewAndSerialize) != MI_RESULT_OK)
403                          err(ZT("MuxIn_Init() failed"));
404                  }
405                  
406 mike     1.1     /* Create new protocol object */
407                  {
408 krisbash 1.3         r = ProtocolSocketAndBase_New_Agent(
409 mike     1.1             &s_data.protocol,
410                          &s_data.selector,
411                          fd,
412 krisbash 1.3             MuxIn_Open,
413                          &s_data.mux);
414 mike     1.1 
415                      if (r != MI_RESULT_OK)
416 krisbash 1.3             err(ZT("ProtocolSocketAndBase_New_Agent() failed"));
417 mike     1.1     }
418              
419                  /* Provider manager */
420                  {
421                      r = ProvMgr_Init(&s_data.provmgr, &s_data.selector, _ProvMgrCallbackOnIdle, &s_data, s_opts.provDir);
422              
423                      if (r != MI_RESULT_OK)
424 krisbash 1.3             err(ZT("ProvMgr_Init() failed"));
425 mike     1.1     }
426              
427                  /* idle timeout */
428                  if (s_opts.idletimeout)
429                  {
430                      /* convert it to usec */
431                      s_data.provmgr.idleTimeoutUsec = s_opts.idletimeout * 1000000;
432 krisbash 1.3         trace_Agent_ChangingIdleTimeout(s_opts.idletimeout);
433 mike     1.1 
434                  }
435              
436                  /* Log start up message */
437 krisbash 1.3     trace_Agent_Started((int)fd);
438 mike     1.1 
439                  /* Run the protocol object (waiting for new messages) */
440 krisbash 1.3     r = Protocol_Run( &s_data.protocol->internalProtocolBase, TIME_NEVER);
441 mike     1.1 
442                  if (r != MI_RESULT_OK)
443 krisbash 1.3         err(ZT("Protocol_Run() failed (%d)"), (int)r);
444 mike     1.1 
445                  // Destroy all global objects
446                  Selector_RemoveAllHandlers(&s_data.selector);
447                  Selector_Destroy(&s_data.selector);
448 krisbash 1.3     ProvMgr_Destroy(&s_data.provmgr);
449                  ProtocolSocketAndBase_ReadyToFinish(s_data.protocol);
450 mike     1.1 
451                  return 0;
452              }

ViewCVS 0.9.2