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 <limits.h>
26 #include <protocol/protocol.h>
|
27 krisbash 1.4 #include <pal/sleep.h>
|
28 mike 1.2 #include <wsman/wsman.h>
|
29 mike 1.1 #include <provreg/provreg.h>
30 #include <provmgr/provmgr.h>
31 #include <disp/disp.h>
|
32 krisbash 1.4 #include <pal/strings.h>
33 #include <pal/dir.h>
|
34 mike 1.1 #include <base/log.h>
35 #include <base/env.h>
36 #include <base/process.h>
37 #include <base/pidfile.h>
38 #include <base/paths.h>
39 #include <base/conf.h>
40 #include <base/user.h>
|
41 krisbash 1.4 #include <base/omigetopt.h>
42 #include <base/multiplex.h>
43 #include <base/Strand.h>
44 #include <pal/format.h>
|
45 krisbash 1.5 #include <pal/lock.h>
|
46 mike 1.1
47 #if defined(CONFIG_POSIX)
48 # include <signal.h>
49 # include <sys/wait.h>
|
50 krisbash 1.4 # include <pthread.h>
|
51 mike 1.1 #endif
52
53 typedef struct _ServerData ServerData;
54
55 typedef enum _ServerTransportType
56 {
57 SRV_PROTOCOL,
58 SRV_WSMAN
59 }
60 ServerTransportType;
61
62 typedef struct _ServerCallbackData
63 {
64 ServerData* data;
65 ServerTransportType type;
66 }
67 ServerCallbackData;
68
69 struct _ServerData
70 {
|
71 krisbash 1.4 Disp disp;
72 MuxIn mux;
73 ProtocolBase* protocol;
|
74 krisbash 1.5 WSMAN** wsman;
75 int wsman_size;
|
76 krisbash 1.4 Selector selector;
77 MI_Boolean selectorInitialized;
|
78 krisbash 1.5 MI_Boolean reloadDispFlag;
|
79 krisbash 1.4 MI_Boolean terminated;
|
80 mike 1.1
81 /* pointers to self with different types - one per supported transport */
82 ServerCallbackData protocolData;
83 ServerCallbackData wsmanData;
84 } ;
85
86 typedef struct _Options
87 {
88 MI_Boolean help;
|
89 krisbash 1.4 #if !defined(CONFIG_FAVORSIZE)
|
90 mike 1.1 MI_Boolean trace;
|
91 krisbash 1.4 #endif
|
92 mike 1.2 MI_Boolean httptrace;
|
93 mike 1.1 MI_Boolean terminateByNoop;
94 #if defined(CONFIG_POSIX)
95 MI_Boolean daemonize;
96 MI_Boolean stop;
97 MI_Boolean reloadConfig;
|
98 krisbash 1.5 MI_Boolean reloadDispatcher;
|
99 mike 1.1 #endif
100 /* mostly for unittesting in non-root env */
101 MI_Boolean ignoreAuthentication;
102 MI_Boolean locations;
103 MI_Boolean logstderr;
|
104 krisbash 1.5 unsigned short *httpport;
105 int httpport_size;
106 unsigned short *httpsport;
107 int httpsport_size;
|
108 krisbash 1.4 char* sslCipherSuite;
109 Server_SSL_Options sslOptions;
|
110 mike 1.1 MI_Uint64 idletimeout;
111 MI_Uint64 livetime;
112 Log_Level logLevel;
113 }
114 Options;
115
|
116 krisbash 1.5 static Lock s_disp_mutex = LOCK_INITIALIZER;
117
|
118 mike 1.1 static Options s_opts;
119
120 static ServerData s_data;
121
122 static const char* arg0 = 0;
123
|
124 krisbash 1.4 static const ZChar HELP[] = ZT("\
|
125 mike 1.1 Usage: %s [OPTIONS]\n\
126 \n\
127 This program starts the server.\n\
128 \n\
129 OPTIONS:\n\
130 -h, --help Print this help message.\n\
131 -d Daemonize the server process (POSIX only).\n\
132 -s Stop the server process (POSIX only).\n\
133 -r Re-read configuration by the running server (POSIX only).\n\
|
134 krisbash 1.5 --reload-dispatcher Re-read configuration by the running server (POSIX only), but don't unload providers.\n\
|
135 mike 1.1 --httpport PORT HTTP protocol listener port.\n\
136 --httpsport PORT HTTPS protocol listener port.\n\
137 --idletimeout TIMEOUT Idle providers unload timeout (in seconds).\n\
138 -v, --version Print version information.\n\
139 -l, --logstderr Send log output to standard error.\n\
140 --loglevel LEVEL Set logging level to one of the following\n\
141 symbols/numbers: fatal/0, error/1, warning/2,\n\
|
142 krisbash 1.4 info/3, debug/4, verbose/5 (default 2).\n\
|
143 mike 1.2 --httptrace Enable logging of HTTP traffic.\n\
|
144 krisbash 1.4 --timestamp Print timestamp server was built with.\n\
145 \n");
146
147 STRAND_DEBUGNAME( NoopRequest );
|
148 mike 1.1
|
149 krisbash 1.4 static void FUNCTION_NEVER_RETURNS err(const ZChar* fmt, ...)
|
150 mike 1.1 {
151 va_list ap;
152 memset(&ap, 0, sizeof(ap));
153
|
154 krisbash 1.4 Ftprintf(stderr, ZT("%s: "), scs(arg0));
|
155 mike 1.1
156 va_start(ap, fmt);
|
157 krisbash 1.4 Vftprintf(stderr, fmt, ap);
|
158 mike 1.1 va_end(ap);
159
160 /* Write to log as well */
161 va_start(ap, fmt);
|
162 krisbash 1.4 __LOGE((fmt, ap));
|
163 mike 1.1 va_end(ap);
164
|
165 krisbash 1.4 Ftprintf(stderr, ZT("\n"));
|
166 mike 1.1 exit(1);
167 }
168
|
169 krisbash 1.4 static void FUNCTION_NEVER_RETURNS info_exit(const ZChar* fmt, ...)
|
170 mike 1.1 {
|
171 krisbash 1.4 va_list ap;
172 memset(&ap, 0, sizeof(ap));
173
174 Ftprintf(stderr, ZT("%s: "), scs(arg0));
175
176 va_start(ap, fmt);
177 Vftprintf(stderr, fmt, ap);
178 va_end(ap);
179
180 /* Write to log as well */
181 va_start(ap, fmt);
182 __LOGI((fmt, ap));
183 va_end(ap);
184
185 Ftprintf(stderr, ZT("\n"));
186 exit(0);
187 }
|
188 mike 1.1
|
189 krisbash 1.4 void PrintProviderMsg( _In_ Message* msg)
190 {
191 #if !defined(CONFIG_FAVORSIZE)
192 if (s_opts.trace)
|
193 mike 1.1 {
|
194 krisbash 1.4 switch ( msg->tag )
|
195 mike 1.1 {
|
196 krisbash 1.4 case PostResultMsgTag:
|
197 mike 1.1 {
|
198 krisbash 1.4 const PostResultMsg* rsp = (const PostResultMsg*)msg;
|
199 mike 1.1 PostResultMsg_Print(rsp, stdout);
200 }
|
201 krisbash 1.4 break;
|
202 mike 1.1
|
203 krisbash 1.4 case PostInstanceMsgTag:
|
204 mike 1.1 {
|
205 krisbash 1.4 const PostInstanceMsg* rsp = (const PostInstanceMsg*)msg;
|
206 mike 1.1 PostInstanceMsg_Print(rsp, stdout);
207 }
|
208 krisbash 1.4 break;
|
209 mike 1.1
|
210 krisbash 1.4 case PostSchemaMsgTag:
|
211 mike 1.1 {
|
212 krisbash 1.4 const PostSchemaMsg* rsp = (const PostSchemaMsg*)msg;
213 PostSchemaMsg_Print(rsp, stdout);
|
214 mike 1.1 }
|
215 krisbash 1.4 break;
|
216 mike 1.1
|
217 krisbash 1.4 case NoOpRspTag:
218 break; // send noop confirmation to the client
|
219 mike 1.1
|
220 krisbash 1.4 default:
221 {
222 trace_UnknownMessageType(msg->tag);
223 exit(1);
224 }
|
225 mike 1.1 }
226 }
|
227 krisbash 1.4 #endif // !defined(CONFIG_FAVORSIZE)
228 }
|
229 mike 1.1
|
230 krisbash 1.4 /*
231 Simple interaction object to respond to the noop request.
232 It just sends a noop response and closes the interaction
233 (therefore shutting down)
234 */
235 void _NoopInteractionAck( _In_ Strand* self)
236 {
237 // do nothing
238 }
|
239 mike 1.1
|
240 krisbash 1.4 StrandFT _NoopInteractionUserFT = {
241 NULL,
242 NULL,
243 _NoopInteractionAck,
244 NULL,
245 NULL,
246 NULL,
247 NULL,
248 NULL,
249 NULL,
250 NULL,
251 NULL,
252 NULL };
|
253 mike 1.1
|
254 krisbash 1.4 static void _ProcessNoopRequest(
255 _Inout_ InteractionOpenParams* params )
|
256 mike 1.1 {
|
257 krisbash 1.4 Strand* strand;
258 NoOpReq* req = (NoOpReq*)params->msg;
259 NoOpRsp* rsp;
|
260 mike 1.1
|
261 krisbash 1.4 #if !defined(CONFIG_FAVORSIZE)
262 if (s_opts.trace)
263 {
264 NoOpReq_Print(req, stdout);
265 }
266 #endif
267
268 strand = Strand_New( STRAND_DEBUG( NoopRequest ) &_NoopInteractionUserFT, 0, STRAND_FLAG_ENTERSTRAND, params );
|
269 mike 1.1
|
270 krisbash 1.4 if( NULL == strand )
|
271 mike 1.1 {
|
272 krisbash 1.4 err(ZT("out of memory"));
273 trace_OutOfMemory();
274 Strand_FailOpen(params);
275 return;
276 }
|
277 mike 1.1
|
278 krisbash 1.4 /* Send NoOp response back */
279 rsp = NoOpRsp_New(req->base.base.operationId);
|
280 mike 1.1
|
281 krisbash 1.4 if (!rsp)
282 {
283 err(ZT("out of memory"));
284 trace_OutOfMemory();
285 Strand_FailOpen(params);
286 return;
287 }
|
288 mike 1.1
|
289 krisbash 1.4 #if !defined(CONFIG_FAVORSIZE)
290 if (s_opts.trace)
291 {
292 NoOpRsp_Print(rsp, stdout);
293 }
294 #endif
|
295 mike 1.1
|
296 krisbash 1.4 Strand_Ack( strand ); // Ack open msg
297 Strand_Post( strand, &rsp->base );
298 Strand_Close( strand );
299 Strand_Leave( strand);
300
301 NoOpRsp_Release(rsp);
302
303 trace_ServerReceivedNoOpReqTag( (int)s_opts.terminateByNoop );
304
305 if (s_opts.terminateByNoop)
306 {
307 s_data.terminated = MI_TRUE;
308 Selector_StopRunning(&s_data.selector);
309 }
310 }
|
311 mike 1.1
|
312 krisbash 1.4 /* Called by protocol stack to dispatch an incoming request message */
313 static void _RequestCallback(
314 _Inout_ InteractionOpenParams* interactionParams )
315 {
316 ServerCallbackData* self = (ServerCallbackData*)interactionParams->callbackData;
317 Message* msg = interactionParams->msg;
318 MI_Result result;
319
320 DEBUG_ASSERT( NULL != interactionParams );
321 DEBUG_ASSERT( NULL != msg );
322
323 if (NoOpReqTag == msg->tag)
324 {
325 _ProcessNoopRequest( interactionParams );
326 return;
|
327 mike 1.1 }
328
|
329 krisbash 1.4 #if 1 // !defined(CONFIG_FAVORSIZE)
|
330 mike 1.1 if (s_opts.trace)
331 {
332 MessagePrint(msg, stdout);
333 }
|
334 krisbash 1.4 #endif
|
335 krisbash 1.5
336 Lock_Acquire(&s_disp_mutex);
|
337 krisbash 1.4 result = Disp_HandleInteractionRequest(
338 &self->data->disp,
339 interactionParams );
|
340 krisbash 1.5 Lock_Release(&s_disp_mutex);
|
341 krisbash 1.4 if( result != MI_RESULT_OK )
|
342 mike 1.1 {
|
343 krisbash 1.4 Strand_FailOpenWithResult(interactionParams, result, PostResultMsg_NewAndSerialize);
|
344 mike 1.1 }
345 }
|
346 krisbash 1.4
|
347 mike 1.1 static void GetCommandLineDestDirOption(
348 int* argc_,
349 const char* argv[])
350 {
351 int argc = *argc_;
352 int i;
353 const char* destdir = NULL;
354
355 for (i = 1; i < argc; )
356 {
357 if (strcmp(argv[i], "--destdir") == 0)
358 {
359 if (i + 1 == argc)
|
360 krisbash 1.4 err(ZT("missing argument for --destdir option"));
|
361 mike 1.1
362 destdir = argv[i+1];
363 memmove((char*)&argv[i], (char*)&argv[i+2],
364 sizeof(char*) * (argc-i-1));
365 argc -= 2;
366 }
367 else if (strncmp(argv[i], "--destdir=", 10) == 0)
368 {
369 destdir = argv[i] + 10;
370 memmove((char*)&argv[i], (char*)&argv[i+1],
371 sizeof(char*) * (argc-i));
372
373 argc -= 1;
374 }
375 else
376 i++;
377 }
378
379 if (destdir)
380 {
381 if (SetPath(ID_DESTDIR, destdir) != 0)
|
382 krisbash 1.4 err(ZT("failed to set destdir"));
|
383 mike 1.1 }
384
385 *argc_ = argc;
386 }
387
|
388 krisbash 1.5 /*
389 * Parse an HTTP or HTTPS port specification:
390 *
391 * "1270" would simply place 1270 in the list,
392 * "1270,5599" would place port 1270 and port 5599 to the list
393 *
394 * Returns 0 if parameter was good, non-zero if parameter was bad
395 */
396 static int ParseHttpPortSpecification(unsigned short **ports, int *size, const char *spec, unsigned short defport)
397 {
398 // defport is unused (no longer support "+" to add default port
399 (void) defport;
400
401 // Ignore anything that is already stored
402 *size = 0;
403
404 // Skip leading spaces
405 char *saveptr;
406 char *ptr = (char *) spec;
407 while (*ptr == ' ')
408 {
409 krisbash 1.5 ptr++;
410 }
411
412 while ( 1 )
413 {
414 unsigned long x;
415 char *end = NULL;
416
417 char *token = Strtok(ptr, ",", &saveptr);
418 ptr = NULL;
419 if (NULL == token)
420 {
421 break;
422 }
423
424 x = Strtoul(token, &end, 10);
425 if (*end != '\0' || x > USHRT_MAX)
426 {
427 return 1;
428 }
429
430 krisbash 1.5 /* Don't add a port of '0' */
431 if ( x != 0 )
432 {
433 /* Don't add duplicate ports; just ignore second port */
434 int found = 0, i;
435 for (i = 0; i < (*size); ++i)
436 {
437 if ( (*ports)[i] == x )
438 {
439 found = 1;
440 break;
441 }
442 }
443
444 if ( ! found )
445 {
446 int bytes = ++(*size) * sizeof(unsigned int);
447 *ports = PAL_Realloc(*ports, bytes);
448 if ( (*ports) == 0 )
449 {
450 err(ZT("memory allocation failure allocating %d bytes"), bytes);
451 krisbash 1.5 }
452
453 (*ports)[(*size) - 1] = x;
454 }
455 }
456 }
457
458 return 0;
459 }
460
|
461 mike 1.1 static void GetCommandLineOptions(
462 int* argc_,
463 const char* argv[])
464 {
465 int argc = *argc_;
466 GetOptState state = GETOPTSTATE_INITIALIZER;
467 static const char* opts[] =
468 {
469 "-h",
470 "--help",
471 "-p",
472 "-t",
|
473 mike 1.2 "--httptrace",
|
474 krisbash 1.4 "--timestamp",
|
475 mike 1.1 "--stopnoop",
476 "-v",
477 "--version",
478 "-d",
479 "-s",
480 "-r",
481 "--httpport:",
482 "--httpsport:",
483 "--idletimeout:",
484 "--livetime:",
485 "--ignoreAuthentication",
486 "-i",
487 "--prefix:",
488 "--libdir:",
489 "--bindir:",
490 "--localstatedir:",
491 "--sysconfdir:",
492 "--providerdir:",
|
493 krisbash 1.4 "--registerdir:",
|
494 mike 1.1 "--certsdir:",
495 "--rundir:",
496 "--logdir:",
497 "--pidfile:",
498 "--logfile:",
|
499 krisbash 1.4 "--configfile:",
|
500 mike 1.1 "--socketfile:",
501 "--pemfile:",
502 "--keyfile:",
503 "--agentprogram:",
504 "--serverprogram:",
505 "--logstderr",
506 "--loglevel:",
507 "-l",
|
508 krisbash 1.4 "--testopts",
|
509 krisbash 1.5 "--reload-dispatcher",
|
510 mike 1.1 NULL,
511 };
512
513 for (;;)
514 {
515 int r = GetOpt(&argc, argv, opts, &state);
516
517 if (r == 1)
518 break;
519
520 if (r == -1)
521 {
|
522 krisbash 1.4 Ftprintf(stderr, ZT("error: %s\n"), scs(state.err));
|
523 mike 1.1 exit(1);
524 }
525
526 if (strcmp(state.opt, "-h") == 0 ||
527 strcmp(state.opt, "--help") == 0)
528 {
529 s_opts.help = MI_TRUE;
530 }
531 else if (strcmp(state.opt, "-p") == 0)
532 {
533 s_opts.locations = MI_TRUE;
534 }
|
535 krisbash 1.4 #if !defined(CONFIG_FAVORSIZE)
|
536 mike 1.1 else if (strcmp(state.opt, "-t") == 0)
537 {
538 s_opts.trace = MI_TRUE;
539 }
|
540 krisbash 1.4 #endif
|
541 mike 1.2 else if (strcmp(state.opt, "--httptrace") == 0)
542 {
543 s_opts.httptrace = MI_TRUE;
544 }
|
545 krisbash 1.4 else if (strcmp(state.opt, "--timestamp") == 0)
546 {
547 #if defined(CONFIG_OS_WINDOWS)
548 Tprintf(PAL_T("%s: %T\n"), scs(arg0), tcs(CONFIG_TIMESTAMP));
549 #else
550 Tprintf(ZT("%s: %s\n"), scs(arg0), scs(CONFIG_TIMESTAMP));
551 #endif
552 exit(0);
553 }
|
554 mike 1.1 else if (strcmp(state.opt, "--stopnoop") == 0)
555 {
556 s_opts.terminateByNoop = MI_TRUE;
557 }
558 else if (strcmp(state.opt, "-v") == 0 ||
559 strcmp(state.opt, "--version") == 0)
560 {
|
561 krisbash 1.4 #if defined(CONFIG_OS_WINDOWS)
562 Tprintf(PAL_T("%s: %T\n"), scs(arg0),
563 tcs(CONFIG_PRODUCT PAL_T("-") CONFIG_VERSION PAL_T(" - ") CONFIG_DATE));
564 #else
565 Tprintf(ZT("%s: %s\n"), scs(arg0),
566 scs(CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE));
567 #endif
|
568 mike 1.1 exit(0);
569 }
570 #if defined(CONFIG_POSIX)
571 else if (strcmp(state.opt, "-d") == 0)
572 {
573 s_opts.daemonize = MI_TRUE;
574 }
575 else if (strcmp(state.opt, "-s") == 0)
576 {
577 s_opts.stop = MI_TRUE;
578 }
579 else if (strcmp(state.opt, "-r") == 0)
580 {
581 s_opts.reloadConfig = MI_TRUE;
582 }
|
583 krisbash 1.5 else if (strcmp(state.opt, "--reload-dispatcher") == 0)
584 {
585 s_opts.reloadDispatcher = MI_TRUE;
586 }
|
587 mike 1.1 #endif
588 else if (strcmp(state.opt, "--httpport") == 0)
589 {
|
590 krisbash 1.5 if ( ParseHttpPortSpecification(&s_opts.httpport, &s_opts.httpport_size, state.arg, CONFIG_HTTPPORT) )
|
591 krisbash 1.4 {
592 err(ZT("bad option argument for --httpport: %s"),
593 scs(state.arg));
594 }
|
595 mike 1.1 }
596 else if (strcmp(state.opt, "--httpsport") == 0)
597 {
|
598 krisbash 1.5 if ( ParseHttpPortSpecification(&s_opts.httpsport, &s_opts.httpsport_size, state.arg, CONFIG_HTTPSPORT) )
|
599 krisbash 1.4 {
600 err(ZT("bad option argument for --httpsport: %s"),
601 scs(state.arg));
602 }
|
603 mike 1.1 }
604 else if (strcmp(state.opt, "--idletimeout") == 0)
605 {
606 char* end;
607 MI_Uint64 x = Strtoull(state.arg, &end, 10);
608
609 if (*end != '\0')
|
610 krisbash 1.4 {
611 err(ZT("bad option argument for --idletimeout: %s"),
612 scs(state.arg));
613 }
|
614 mike 1.1
615 s_opts.idletimeout = x;
616 }
617 else if (strcmp(state.opt, "--livetime") == 0)
618 {
619 char* end;
620 MI_Uint64 x = Strtoull(state.arg, &end, 10);
621
622 if (*end != '\0')
|
623 krisbash 1.4 {
624 err(ZT("bad option argument for --livetime: %s"),
625 scs(state.arg));
626 }
|
627 mike 1.1
628 s_opts.livetime = x;
629 }
630 else if (strcmp(state.opt, "--ignoreAuthentication") == 0 ||
631 strcmp(state.opt, "-i") == 0)
632 {
633 s_opts.ignoreAuthentication = MI_TRUE;
634 }
635 else if (strcmp(state.opt, "--logstderr") == 0 ||
636 strcmp(state.opt, "-l") == 0)
637 {
638 s_opts.logstderr = MI_TRUE;
639 }
640 else if (strcmp(state.opt, "--loglevel") == 0)
641 {
642 if (Log_SetLevelFromString(state.arg) != 0)
643 {
|
644 krisbash 1.4 err(ZT("bad option argument for %s: %s"),
645 scs(state.opt), scs(state.arg));
646 }
647 }
648 else if (strcmp(state.opt, "--testopts") == 0)
649 {
650 s_opts.httptrace = MI_TRUE;
651
652 if (Log_SetLevelFromString("DEBUG") != 0)
653 {
654 err(ZT("bad argument for Log_SetLevelFromString()"));
|
655 mike 1.1 }
656 }
657 else if (strncmp(state.opt, "--", 2) == 0 && IsNickname(state.opt+2))
658 {
659 if (SetPathFromNickname(state.opt+2, state.arg) != 0)
|
660 krisbash 1.4 err(ZT("SetPathFromNickname() failed"));
|
661 mike 1.1 }
662 }
663
664 *argc_ = argc;
665 }
666
667 static void OpenLogFile()
668 {
669 if (s_opts.logstderr)
670 {
671 if (Log_OpenStdErr() != MI_RESULT_OK)
|
672 krisbash 1.4 err(ZT("failed to open log file to stderr"));
|
673 mike 1.1 }
674 else
675 {
|
676 krisbash 1.4 TChar path[PAL_MAX_PATH_SIZE];
677 TcsStrlcpy(path, OMI_GetPath(ID_LOGFILE), MI_COUNT(path));
|
678 mike 1.1
679 /* Open the log file */
680 if (Log_Open(path) != MI_RESULT_OK)
|
681 krisbash 1.4 err(PAL_T("failed to open log file: %T"), tcs(path));
|
682 mike 1.1 }
683 }
684
685 #if defined(CONFIG_POSIX)
|
686 krisbash 1.4
|
687 mike 1.1 static void _HandleSIGTERM(int sig)
688 {
689 if (sig == SIGTERM && s_data.selectorInitialized)
690 {
|
691 krisbash 1.4 const char* socketFile = OMI_GetPath(ID_SOCKETFILE);
|
692 mike 1.1 s_data.terminated = MI_TRUE;
693 Selector_StopRunning(&s_data.selector);
|
694 krisbash 1.4 if (socketFile != NULL && *socketFile != '\0')
695 unlink(socketFile);
|
696 mike 1.1 }
697 }
698
699 static void _HandleSIGHUP(int sig)
700 {
701 if (sig == SIGHUP && s_data.selectorInitialized)
702 {
703 Selector_StopRunning(&s_data.selector);
704 }
705 }
706
|
707 krisbash 1.5 // We reload the ProvReg structure in the Dispatcher when this signal is received.
708 // This gives us access to providers that are installed after the omiserver is running without terminating current providers that are running.
709 static void _HandleSIGUSR1(int sig)
710 {
711 if (sig == SIGUSR1)
712 {
713 s_data.reloadDispFlag = MI_TRUE;
714 }
715 }
716
|
717 krisbash 1.4 /* An array of PIDS that abnormally exited */
718 #define NPIDS 16
719 static pid_t _pids[NPIDS];
720 static volatile size_t _npids;
721
|
722 mike 1.1 static void _HandleSIGCHLD(int sig)
723 {
724 if (sig == SIGCHLD)
725 {
|
726 krisbash 1.4 for (;;)
727 {
728 int status = 0;
729 pid_t pid = waitpid(-1, &status, WNOHANG);
730
731 /* If abnormal exit, append to PIDs array */
732 if (pid > 0 && !WIFEXITED(status))
733 {
734 /* Save PID so error can be logged outside this function */
735 if (_npids < NPIDS)
736 _pids[_npids++] = pid;
737 }
738
739 if (pid > 0 || (pid == -1 && errno == EINTR))
740 continue;
741
742 break;
743 }
|
744 mike 1.1 }
745 }
|
746 krisbash 1.4
747 #endif /* defined(CONFIG_POSIX) */
|
748 mike 1.1
749 static void _PrintPaths()
750 {
751 PrintPaths();
752 }
753
754 static void GetConfigFileOptions()
755 {
|
756 krisbash 1.4 char path[PAL_MAX_PATH_SIZE];
|
757 mike 1.1 Conf* conf;
758
759 /* Form the configuration file path */
|
760 krisbash 1.4 Strlcpy(path, OMI_GetPath(ID_CONFIGFILE), sizeof(path));
|
761 mike 1.1
762 /* Open the configuration file */
763 conf = Conf_Open(path);
764 if (!conf)
|
765 krisbash 1.4 err(ZT("failed to open configuration file: %s"), scs(path));
|
766 mike 1.1
767 /* For each key=value pair in configuration file */
768 for (;;)
769 {
770 const char* key;
771 const char* value;
772 int r = Conf_Read(conf, &key, &value);
773
774 if (r == -1)
|
775 krisbash 1.4 err(ZT("%s: %s\n"), path, scs(Conf_Error(conf)));
|
776 mike 1.1
777 if (r == 1)
778 break;
779
780 if (strcmp(key, "httpport") == 0)
781 {
|
782 krisbash 1.5 if ( ParseHttpPortSpecification(&s_opts.httpport, &s_opts.httpport_size, value, CONFIG_HTTPPORT) )
|
783 mike 1.1 {
|
784 krisbash 1.4 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
785 Conf_Line(conf), scs(key), scs(value));
|
786 mike 1.1 }
787 }
788 else if (strcmp(key, "httpsport") == 0)
789 {
|
790 krisbash 1.5 if ( ParseHttpPortSpecification(&s_opts.httpsport, &s_opts.httpsport_size, value, CONFIG_HTTPSPORT) )
|
791 mike 1.1 {
|
792 krisbash 1.4 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
793 Conf_Line(conf), scs(key), scs(value));
|
794 mike 1.1 }
795 }
796 else if (strcmp(key, "idletimeout") == 0)
797 {
798 char* end;
799 MI_Uint64 x = Strtoull(value, &end, 10);
800
801 if (*end != '\0')
802 {
|
803 krisbash 1.4 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
804 Conf_Line(conf), scs(key), scs(value));
|
805 mike 1.1 }
806
807 s_opts.idletimeout = x;
808 }
809 else if (strcmp(key, "livetime") == 0)
810 {
811 char* end;
812 MI_Uint64 x = Strtoull(value, &end, 10);
813
814 if (*end != '\0')
815 {
|
816 krisbash 1.4 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
817 Conf_Line(conf), scs(key), scs(value));
|
818 mike 1.1 }
819
820 s_opts.livetime = x;
821 }
822 else if (strcmp(key, "trace") == 0)
823 {
824 if (Strcasecmp(value, "true") == 0)
825 {
|
826 krisbash 1.4 #if !defined(CONFIG_FAVORSIZE)
|
827 mike 1.1 s_opts.trace = MI_TRUE;
|
828 krisbash 1.4 #endif
|
829 mike 1.1 }
830 else if (Strcasecmp(value, "false") == 0)
831 {
|
832 krisbash 1.4 #if !defined(CONFIG_FAVORSIZE)
|
833 mike 1.1 s_opts.trace = MI_FALSE;
|
834 krisbash 1.4 #endif
|
835 mike 1.1 }
836 else
837 {
|
838 krisbash 1.4 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
839 Conf_Line(conf), scs(key), scs(value));
|
840 mike 1.1 }
841 }
|
842 mike 1.2 else if (strcmp(key, "httptrace") == 0)
843 {
844 if (Strcasecmp(value, "true") == 0)
845 {
846 s_opts.httptrace = MI_TRUE;
847 }
848 else if (Strcasecmp(value, "false") == 0)
849 {
850 s_opts.httptrace = MI_FALSE;
851 }
852 else
853 {
|
854 krisbash 1.4 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
855 Conf_Line(conf), scs(key), scs(value));
856 }
857 }
858 else if (strcmp(key, "loglevel") == 0)
859 {
860 if (Log_SetLevelFromString(value) != 0)
861 {
862 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
863 Conf_Line(conf), scs(key), scs(value));
864 }
865 }
866 else if (strcmp(key, "sslciphersuite") == 0)
867 {
868 size_t valueLength = strlen(value);
869 s_opts.sslCipherSuite = PAL_Malloc(valueLength + 1);
870 if (s_opts.sslCipherSuite == NULL)
871 err(ZT("Out of memory"));
872 Strlcpy(s_opts.sslCipherSuite, value, valueLength+1);
873 s_opts.sslCipherSuite[valueLength] = '\0';
874 }
|
875 krisbash 1.5 else if (strcmp(key, "NoSSLv2") == 0)
|
876 krisbash 1.4 {
877 if (Strcasecmp(value, "true") == 0)
878 {
879 s_opts.sslOptions |= DISABLE_SSL_V2;
880 }
|
881 krisbash 1.5 else if (Strcasecmp(value, "false") == 0)
882 {
883 s_opts.sslOptions &= ~DISABLE_SSL_V2;
884 }
885 else
|
886 krisbash 1.4 {
887 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
888 Conf_Line(conf), scs(key), scs(value));
889 }
890 }
|
891 krisbash 1.5 else if (strcmp(key, "NoSSLv3") == 0)
|
892 krisbash 1.4 {
893 if (Strcasecmp(value, "true") == 0)
894 {
895 s_opts.sslOptions |= DISABLE_SSL_V3;
896 }
|
897 krisbash 1.5 else if (Strcasecmp(value, "false") == 0)
898 {
899 s_opts.sslOptions &= ~DISABLE_SSL_V3;
900 }
901 else
|
902 krisbash 1.4 {
903 err(ZT("%s(%u): invalid value for '%s': %s"), scs(path),
904 Conf_Line(conf), scs(key), scs(value));
|
905 mike 1.2 }
906 }
|
907 mike 1.1 else if (IsNickname(key))
908 {
909 if (SetPathFromNickname(key, value) != 0)
|
910 krisbash 1.4 err(ZT("SetPathFromNickname() failed"));
|
911 mike 1.1 }
912 else
913 {
|
914 krisbash 1.4 err(ZT("%s(%u): unknown key: %s"), scs(path), Conf_Line(conf),
915 scs(key));
|
916 mike 1.1 }
917 }
918
919 /* Close configuration file */
920 Conf_Close(conf);
921
922 return;
923 }
924
925 int servermain(int argc, const char* argv[])
926 {
927 MI_Result r;
928 #if defined(CONFIG_POSIX)
929 int pidfile = -1;
930 #endif
931
932 arg0 = argv[0];
933
934 memset(&s_data, 0, sizeof(s_data));
935
936 /* Set default options */
|
937 krisbash 1.5 s_opts.httpport = PAL_Malloc(sizeof(unsigned short));
938 s_opts.httpport[0] = CONFIG_HTTPPORT;
939 s_opts.httpport_size = 1;
940
941 s_opts.httpsport = PAL_Malloc(sizeof(unsigned short));
942 s_opts.httpsport[0] = CONFIG_HTTPSPORT;
943 s_opts.httpsport_size = 1;
944
945 s_opts.sslOptions = DISABLE_SSL_V2;
|
946 mike 1.1 s_opts.idletimeout = 0;
947 s_opts.livetime = 0;
948
949 /* Get --destdir command-line option */
950 GetCommandLineDestDirOption(&argc, argv);
951
952 /* Extract configuration file options */
953 GetConfigFileOptions();
954
955 /* Extract command-line options a second time (to override) */
956 GetCommandLineOptions(&argc, argv);
957
958 /* Open the log file */
959 OpenLogFile();
960
961 /* Print help */
962 if (s_opts.help)
963 {
|
964 krisbash 1.4 Ftprintf(stderr, HELP, scs(arg0));
|
965 mike 1.1 exit(1);
966 }
967
968 /* Print locations of files and directories */
969 if (s_opts.locations)
970 {
971 _PrintPaths();
|
972 krisbash 1.4 Tprintf(ZT("\n"));
|
973 mike 1.1 exit(0);
974 }
975
976 #if defined(CONFIG_POSIX)
977 if (s_opts.stop || s_opts.reloadConfig)
978 {
979 if (PIDFile_IsRunning() != 0)
|
980 krisbash 1.4 info_exit(ZT("server is not running\n"));
|
981 mike 1.1
982 if (PIDFile_Signal(s_opts.stop ? SIGTERM : SIGHUP) != 0)
|
983 krisbash 1.4 err(ZT("failed to stop server\n"));
|
984 mike 1.1
985 if (s_opts.stop)
|
986 krisbash 1.4 Tprintf(ZT("%s: stopped server\n"), scs(arg0));
|
987 mike 1.1 else
|
988 krisbash 1.4 Tprintf(ZT("%s: refreshed server\n"), scs(arg0));
|
989 mike 1.1
990 exit(0);
991 }
|
992 krisbash 1.5 if (s_opts.reloadDispatcher)
993 {
994 if (PIDFile_IsRunning() != 0)
995 info_exit(ZT("server is not running\n"));
996
997 if (PIDFile_Signal(SIGUSR1) != 0)
998 err(ZT("failed to reload dispatcher on the server\n"));
999
1000 Tprintf(ZT("%s: server has reloaded its dispatcher\n"), scs(arg0));
1001
1002 exit(0);
1003 }
|
1004 mike 1.1 #endif
1005
1006 #if defined(CONFIG_POSIX)
1007
1008 if (PIDFile_IsRunning() == 0)
|
1009 krisbash 1.4 err(ZT("server is already running\n"));
|
1010 mike 1.1
1011 /* Verify that server is started as root */
1012 if (0 != IsRoot() && !s_opts.ignoreAuthentication)
1013 {
|
1014 krisbash 1.4 err(ZT("expected to run as root"));
|
1015 mike 1.1 }
1016
1017 /* ATTN: unit-test support; should be removed/ifdefed later */
1018 if (s_opts.ignoreAuthentication)
1019 {
1020 IgnoreAuthCalls(1);
1021 }
1022
1023 /* Watch for SIGTERM signals */
1024 if (0 != SetSignalHandler(SIGTERM, _HandleSIGTERM) ||
|
1025 krisbash 1.5 0 != SetSignalHandler(SIGHUP, _HandleSIGHUP) ||
1026 0 != SetSignalHandler(SIGUSR1, _HandleSIGUSR1))
1027 err(ZT("cannot set sighandler, errno %d"), errno);
|
1028 mike 1.1
1029
1030 /* Watch for SIGCHLD signals */
1031 SetSignalHandler(SIGCHLD, _HandleSIGCHLD);
1032
1033 #endif
1034
1035 /* Change directory to 'rundir' */
|
1036 krisbash 1.4 if (Chdir(OMI_GetPath(ID_RUNDIR)) != 0)
1037 {
1038 err(ZT("failed to change directory to: %s"),
1039 scs(OMI_GetPath(ID_RUNDIR)));
1040 }
|
1041 mike 1.1
1042 #if defined(CONFIG_POSIX)
1043 /* Daemonize */
1044 if (s_opts.daemonize && Process_Daemonize() != 0)
|
1045 krisbash 1.4 err(ZT("failed to daemonize server process"));
|
1046 mike 1.1 #endif
1047
1048 #if defined(CONFIG_POSIX)
1049
1050 /* Create PID file */
1051 if ((pidfile = PIDFile_OpenWrite()) == -1)
1052 {
|
1053 krisbash 1.4 trace_CreatePIDFileFailed( scs(OMI_GetPath(ID_PIDFILE)) );
|
1054 mike 1.1 exit(1);
1055 }
|
1056 krisbash 1.4
|
1057 mike 1.1 #endif
1058
1059 /* Initialize calback parameters */
1060 s_data.protocolData.data = &s_data;
1061 s_data.protocolData.type = SRV_PROTOCOL;
1062 s_data.wsmanData.data = &s_data;
1063 s_data.wsmanData.type = SRV_WSMAN;
1064
1065 while (!s_data.terminated)
1066 {
1067 /* selector */
1068 {
1069 /* Initialize the network */
1070 Sock_Start();
1071
1072 if(Selector_Init(&s_data.selector) != MI_RESULT_OK)
|
1073 krisbash 1.4 err(ZT("Selector_Init() failed"));
|
1074 mike 1.1
1075 s_data.selectorInitialized = MI_TRUE;
|
1076 krisbash 1.4
1077 Timer_SetSelector(&s_data.selector);
|
1078 mike 1.1 }
1079
1080 /* Create the dispatcher object. */
1081 {
1082 r = Disp_Init(&s_data.disp, &s_data.selector);
1083
1084 if (r != MI_RESULT_OK)
1085 {
|
1086 krisbash 1.4 trace_DispatchInitFailed(r);
1087 err(ZT("failed to initialize the dispatcher: %u"), r);
|
1088 mike 1.1 }
1089 }
1090
1091 if (s_opts.idletimeout)
1092 {
1093 /* convert it to usec */
1094 s_data.disp.agentmgr.provmgr.idleTimeoutUsec = s_opts.idletimeout * 1000000;
1095 }
1096
|
1097 krisbash 1.4 /* Set WSMAN options and create WSMAN server */
|
1098 krisbash 1.5 s_data.wsman_size = s_opts.httpport_size + s_opts.httpsport_size;
1099 if ( s_data.wsman_size > 0 )
1100 {
1101 s_data.wsman = PAL_Calloc(s_data.wsman_size, sizeof(WSMAN*));
1102 if ( s_data.wsman == NULL )
1103 {
1104 err(ZT("memory allocation failure allocating %d bytes"), s_data.wsman_size * sizeof(WSMAN*));
1105 }
1106 }
1107
|
1108 mike 1.1 {
|
1109 krisbash 1.5 int wsman_count = 0;
|
1110 krisbash 1.4 WSMAN_Options options = DEFAULT_WSMAN_OPTIONS;
1111 #if !defined(CONFIG_FAVORSIZE)
1112 options.enableTracing = s_opts.trace;
1113 #endif
1114 options.enableHTTPTracing = s_opts.httptrace;
1115
|
1116 krisbash 1.5 /* Start up the non-encrypted listeners */
1117 int count;
1118 for ( count = 0; count < s_opts.httpport_size; ++count )
1119 {
1120 r = WSMAN_New_Listener(
1121 &s_data.wsman[wsman_count++],
1122 &s_data.selector,
1123 s_opts.httpport[count],
1124 0,
1125 s_opts.sslCipherSuite,
1126 s_opts.sslOptions,
1127 _RequestCallback,
1128 &s_data.wsmanData,
1129 &options);
1130
1131 if (r != MI_RESULT_OK)
1132 {
1133 err(ZT("WSMAN_New_Listener() failed for port %u"), s_opts.httpport[count]);
1134 }
1135
1136 /* Log start up message */
1137 krisbash 1.5 trace_ListeningOnPort(s_opts.httpport[count]);
1138 }
1139
1140 /* Start up the encrypted listeners */
1141 for ( count = 0; count < s_opts.httpsport_size; ++count )
1142 {
1143 r = WSMAN_New_Listener(
1144 &s_data.wsman[wsman_count++],
1145 &s_data.selector,
1146 0,
1147 s_opts.httpsport[count],
1148 s_opts.sslCipherSuite,
1149 s_opts.sslOptions,
1150 _RequestCallback,
1151 &s_data.wsmanData,
1152 &options);
1153
1154 if (r != MI_RESULT_OK)
1155 {
1156 err(ZT("WSMAN_New_Listener() failed for encrypted port %u"), s_opts.httpsport[count]);
1157 }
|
1158 mike 1.1
|
1159 krisbash 1.5 /* Log start up message */
1160 trace_ListeningOnEncryptedPort(s_opts.httpsport[count]);
1161 }
|
1162 mike 1.1 }
1163
|
1164 krisbash 1.4 /* mux */
|
1165 mike 1.1 {
|
1166 krisbash 1.4 if(MuxIn_Init(&s_data.mux, _RequestCallback, &s_data.protocolData, NULL, PostResultMsg_NewAndSerialize) != MI_RESULT_OK)
1167 err(ZT("MuxIn_Init() failed"));
|
1168 mike 1.1 }
|
1169 krisbash 1.4
|
1170 mike 1.1 /* Create new protocol object */
1171 {
|
1172 krisbash 1.4 r = ProtocolBase_New_Listener(
1173 &s_data.protocol,
1174 &s_data.selector,
1175 OMI_GetPath(ID_SOCKETFILE),
1176 MuxIn_Open,
1177 &s_data.mux);
|
1178 mike 1.1
1179 if (r != MI_RESULT_OK)
|
1180 krisbash 1.4 err(ZT("Protocol_New_Listener() failed"));
|
1181 mike 1.1 }
1182
1183 /* Run the protocol object (waiting for new messages) */
|
1184 krisbash 1.4 {
1185 const PAL_Uint64 ONE_SECOND_USEC = 1000 * 1000;
1186 PAL_Uint64 start;
1187 PAL_Uint64 finish;
|
1188 mike 1.1
|
1189 krisbash 1.4 PAL_Time(&start);
1190
1191 if (s_opts.livetime)
1192 finish = start + (s_opts.livetime * ONE_SECOND_USEC);
1193 else
1194 finish = 0;
1195
1196 for (;;)
1197 {
1198 PAL_Uint64 now;
|
1199 krisbash 1.5
1200 if (s_data.reloadDispFlag)
1201 {
1202 Lock_Acquire(&s_disp_mutex);
1203 Disp_Reload(&s_data.disp);
1204 s_data.reloadDispFlag = MI_FALSE;
1205 Lock_Release(&s_disp_mutex);
1206 }
|
1207 krisbash 1.4
1208 r = Protocol_Run(s_data.protocol, ONE_SECOND_USEC);
1209
1210 if (r != MI_RESULT_TIME_OUT)
1211 break;
1212
1213 PAL_Time(&now);
1214
1215 /* Log abnormally terminated terminated process */
1216 {
1217 size_t i;
1218
1219 for (i = 0; i < _npids; i++)
1220 trace_ChildProcessTerminatedAbnormally(_pids[i]);
1221
1222 _npids = 0;
1223 }
1224
1225 if (finish && now > finish)
1226 break;
1227 }
1228 krisbash 1.4 }
1229
1230 trace_Server_ProtocolRun(r);
|
1231 mike 1.1
1232 s_data.selectorInitialized = MI_FALSE;
1233
1234 if (MI_RESULT_TIME_OUT == r)
1235 {
|
1236 krisbash 1.4 trace_Server_LiveTimeExpired();
|
1237 mike 1.1 s_data.terminated = MI_TRUE;
1238 }
1239
1240 #if defined(CONFIG_POSIX)
1241 if (r == MI_RESULT_OK)
1242 {
1243 if (s_data.terminated)
|
1244 krisbash 1.4 trace_ServerTerminated();
|
1245 mike 1.1 else
|
1246 krisbash 1.4 trace_ServerReReadingConfig();
|
1247 mike 1.1 }
1248 #endif
1249
1250 // Destroy the dispatcher.
1251 Selector_RemoveAllHandlers(&s_data.selector);
1252 Disp_Destroy(&s_data.disp);
|
1253 krisbash 1.5
1254 {
1255 int i;
1256 for (i = 0; i < s_data.wsman_size; ++i)
1257 {
1258 WSMAN_Delete(s_data.wsman[i]);
1259 }
1260 }
1261
|
1262 krisbash 1.4 ProtocolBase_Delete(s_data.protocol);
|
1263 mike 1.1 Selector_Destroy(&s_data.selector);
1264
1265 /* Shutdown the network */
1266 Sock_Stop();
1267 }
1268
|
1269 krisbash 1.5 /* Done with WSMAN* array; free it */
1270 PAL_Free(s_data.wsman);
1271 s_data.wsman_size = 0;
1272
1273 /* Done with pointers to ports; free them now */
1274 PAL_Free(s_opts.httpport);
1275 PAL_Free(s_opts.httpsport);
1276 s_opts.httpport_size = s_opts.httpsport_size = 0;
1277
|
1278 mike 1.1 #if defined(CONFIG_POSIX)
1279 /* Close PID file */
1280 close(pidfile);
1281
1282 /* Remove PID file */
1283 if (PIDFile_Delete() != 0)
|
1284 krisbash 1.4 {
1285 trace_FailedRemovePIDFile(scs(OMI_GetPath(ID_PIDFILE)));
1286 }
|
1287 mike 1.1 #endif
1288
1289 /* Log that we are exiting */
|
1290 krisbash 1.4 trace_ServerExiting();
|
1291 mike 1.1
1292 Log_Close();
|
1293 krisbash 1.4
1294 #if defined(USE_ALLOCATOR)
1295
1296 # if defined(USE_PAL_ATEXIT)
1297 PAL_AtexitCall();
1298 # endif
1299
1300 PAL_DumpAllocStats();
1301
1302 if (PAL_GetBlocksAllocated())
1303 {
1304 printf("WARNING: %s: server has unfreed blocks on exit\n", arg0);
1305 PAL_DumpAllocList();
1306 }
1307 #endif
1308
|
1309 mike 1.1 return 0;
1310 }
|