version 1.2, 2015/04/20 18:10:09
|
version 1.3, 2015/04/20 18:19:49
|
|
|
*/ | */ |
| |
#include <protocol/protocol.h> | #include <protocol/protocol.h> |
#include <base/time.h> |
#include <pal/sleep.h> |
#include <provmgr/provmgr.h> | #include <provmgr/provmgr.h> |
#include <base/strings.h> |
#include <pal/strings.h> |
#include <base/args.h> |
|
#include <base/log.h> | #include <base/log.h> |
#include <base/env.h> | #include <base/env.h> |
#include <base/paths.h> | #include <base/paths.h> |
#include <base/getopt.h> |
#include <base/omigetopt.h> |
|
#include <base/multiplex.h> |
|
#include <base/Strand.h> |
|
#include <pal/format.h> |
#include <sys/types.h> | #include <sys/types.h> |
|
#include <sys/resource.h> |
#include <pwd.h> | #include <pwd.h> |
#include <grp.h> | #include <grp.h> |
| |
#define T MI_T |
STRAND_DEBUGNAME( IdleNotification ); |
| |
typedef struct _AgentData AgentData; | typedef struct _AgentData AgentData; |
| |
struct _AgentData | struct _AgentData |
{ | { |
Protocol* protocol; |
MuxIn mux; |
|
ProtocolSocketAndBase* protocol; |
ProvMgr provmgr; | ProvMgr provmgr; |
Selector selector; | Selector selector; |
|
Strand idleNotificationStrand; |
} ; | } ; |
| |
typedef struct _Options | typedef struct _Options |
|
|
| |
static Options s_opts; | static Options s_opts; |
static const char* arg0 = 0; | static const char* arg0 = 0; |
static const char HELP[] = "\ |
static const ZChar HELP[] = ZT("\ |
Usage: %s [OPTIONS]\n\ | Usage: %s [OPTIONS]\n\ |
\n\ | \n\ |
This program starts the OMI agent.\n\ | This program starts the OMI agent.\n\ |
|
|
OPTIONS:\n\ | OPTIONS:\n\ |
--version Print version information.\n\ | --version Print version information.\n\ |
--providerdir Find providers in this directory.\n\ | --providerdir Find providers in this directory.\n\ |
--loglevel LEVEL Set the log level (0-4).\n\ |
--loglevel LEVEL Set the log level (0-5).\n\ |
\n"; |
\n"); |
| |
PRINTF_FORMAT(1, 2) | PRINTF_FORMAT(1, 2) |
void FUNCTION_NEVER_RETURNS err(const char* fmt, ...) |
static void FUNCTION_NEVER_RETURNS err(const ZChar* fmt, ...) |
{ | { |
|
ZChar* buf = NULL; |
|
ZChar* buf2 = NULL; |
va_list ap; | va_list ap; |
memset(&ap, 0, sizeof(ap)); |
size_t buflen = PAL_MAX_PATH_SIZE; |
|
buf = (ZChar*) PAL_Malloc( sizeof(ZChar) * buflen * 2 ); |
fprintf(stderr, "%s: ", arg0); |
if (buf) |
|
{ |
|
buf2 = buf + buflen; |
| |
|
memset(&ap, 0, sizeof(ap)); |
va_start(ap, fmt); | va_start(ap, fmt); |
vfprintf(stderr, fmt, ap); |
Vstprintf(buf, buflen, fmt, ap); |
va_end(ap); | va_end(ap); |
|
Stprintf(buf2, buflen, ZT("%s: %T"), scs(arg0), buf); |
|
|
|
Ftprintf(stderr, ZT("%T\n"), buf2); |
|
trace_CriticalError(buf2); |
| |
fputc('\n', stderr); |
PAL_Free(buf); |
|
} |
exit(1); | exit(1); |
} | } |
| |
static void _ProviderCallback(Message* msg, void* callbackData) |
/* enable core dump for current process */ |
|
static void _EnableCoreDump() |
{ | { |
|
struct rlimit core_limits; |
|
core_limits.rlim_cur = RLIM_INFINITY; |
|
core_limits.rlim_max = RLIM_INFINITY; |
|
setrlimit(RLIMIT_CORE, &core_limits); |
|
} |
| |
/* forward message to the other side */ |
void _IdleNotification_Post( _In_ Strand* self_, _In_ Message* msg) |
/*if (msg->request) |
{ |
msg->clientID = msg->request->clientID;*/ |
DEBUG_ASSERT( MI_FALSE ); // not used |
|
} |
| |
Protocol_Send(s_data.protocol, msg); |
void _IdleNotification_PostControl( _In_ Strand* self_, _In_ Message* msg) |
|
{ |
|
DEBUG_ASSERT( MI_FALSE ); // not used |
} | } |
| |
/* Called by protocol stack to dispatch an incoming request message */ |
void _IdleNotification_Ack( _In_ Strand* self_ ) |
static MI_Boolean _RequestCallback( |
|
Protocol* protocol_, |
|
Message* msg, |
|
void* data) |
|
{ | { |
//ServerCallbackData* self = (ServerCallbackData*)data; |
// Nothing to do |
MI_Result r; |
} |
| |
MI_UNUSED(protocol_); |
void _IdleNotification_Finish( _In_ Strand* self_ ) |
|
{ |
|
// Nothing to do |
|
} |
| |
msg->callback = _ProviderCallback; |
/* |
//msg->callbackData = self; |
Object that is just used to send to agent manager BinProtocolNotification |
| |
r = ProvMgr_PostMessage(&s_data.provmgr, msg->libraryName, msg); |
Behavior: |
|
- It is created when the initial BinProtocolNotification is sent by the server |
|
then kept alive as long as the connection is alive. |
|
- Post, PostControl and Ack are not actually used |
|
- Shutdown: |
|
The objects are deleted thru the normal Strand logic once the connection is closed. |
| |
if (MI_RESULT_OK != r) |
Unique features and special Behavior: |
{ |
- If the agent is idle it will be use to post a BinProtocolNotification |
PostResultMsg* resp; |
thru the many-to-one interface so there are no problem or races with |
|
a request being received or a response to a normal request going out |
|
at the same time |
|
*/ |
|
static StrandFT _IdleNotification_FT = { |
|
_IdleNotification_Post, |
|
_IdleNotification_PostControl, |
|
_IdleNotification_Ack, |
|
NULL, |
|
NULL, |
|
_IdleNotification_Finish, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL }; |
| |
resp = PostResultMsg_New( msg->msgID ); |
/* Called by mux to dispatch an incoming request message */ |
|
static void _RequestCallback( |
|
_Inout_ InteractionOpenParams* interactionParams ) |
|
{ |
|
DEBUG_ASSERT( NULL != interactionParams ); |
|
DEBUG_ASSERT( NULL != interactionParams->msg ); |
|
DEBUG_ASSERT( NULL == interactionParams->callbackData ); |
| |
if (!resp) |
if (BinProtocolNotificationTag == interactionParams->msg->tag) |
return MI_FALSE; |
{ |
|
BinProtocolNotification* notification = (BinProtocolNotification*)interactionParams->msg; |
|
(void) notification; /* In case DEBUG_ASSERT is compiled out, avoid compiler warnings */ |
| |
resp->result = r; |
DEBUG_ASSERT(BinNotificationAgentIdle == notification->type); |
Message_SetRequest(&resp->base,msg); |
|
(*msg->callback)(&resp->base, msg->callbackData); |
|
| |
PostResultMsg_Release(resp); |
Strand_Init( STRAND_DEBUG(IdleNotification) &s_data.idleNotificationStrand, &_IdleNotification_FT, 0, interactionParams ); |
} | } |
|
else |
|
{ |
|
MI_Result result; |
|
ProvRegEntry regentry; |
|
RequestMsg* request = (RequestMsg*)interactionParams->msg; |
|
|
|
DEBUG_ASSERT( Message_IsRequest(interactionParams->msg) ); |
| |
return MI_TRUE; |
memset(®entry, 0, sizeof(regentry)); |
|
regentry.libraryName = request->libraryName; |
|
regentry.instanceLifetimeContext = request->instanceLifetimeContext; |
|
|
|
result = ProvMgr_NewRequest(&s_data.provmgr, ®entry, interactionParams ); |
|
|
|
if (MI_RESULT_OK != result) |
|
{ |
|
trace_Agent_ProvMgrNewRequest_Failed( result ); |
|
Strand_FailOpenWithResult(interactionParams, result, PostResultMsg_NewAndSerialize); |
|
} |
|
} |
} | } |
| |
static void GetCommandLineDestDirOption( | static void GetCommandLineDestDirOption( |
|
|
if (strcmp(argv[i], "--destdir") == 0) | if (strcmp(argv[i], "--destdir") == 0) |
{ | { |
if (i + 1 == argc) | if (i + 1 == argc) |
err("missing argument for --destdir option"); |
err(ZT("missing argument for --destdir option")); |
| |
destdir = argv[i+1]; | destdir = argv[i+1]; |
memmove((char*)&argv[i], (char*)&argv[i+2], | memmove((char*)&argv[i], (char*)&argv[i+2], |
|
|
if (destdir) | if (destdir) |
{ | { |
if (SetPath(ID_DESTDIR, destdir) != 0) | if (SetPath(ID_DESTDIR, destdir) != 0) |
err("failed to set destdir"); |
err(ZT("failed to set destdir")); |
} | } |
| |
*argc_ = argc; | *argc_ = argc; |
|
|
break; | break; |
| |
if (r == -1) | if (r == -1) |
err("%s", state.err); |
err(ZT("%s"), scs(state.err)); |
| |
/* Check for -h option */ | /* Check for -h option */ |
if (strcmp(state.opt, "-h") == 0 || strcmp(state.opt, "--help") == 0) | if (strcmp(state.opt, "-h") == 0 || strcmp(state.opt, "--help") == 0) |
|
|
} | } |
else if (strcmp(state.opt, "--version") == 0) | else if (strcmp(state.opt, "--version") == 0) |
{ | { |
printf("%s: %s\n", arg0, |
Tprintf(ZT("%s: %s\n"), scs(arg0), |
CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE); |
scs(CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE)); |
exit(0); | exit(0); |
} | } |
else if (strcmp(state.opt, "--providerdir") == 0) | else if (strcmp(state.opt, "--providerdir") == 0) |
|
|
MI_Uint64 x = Strtoull(state.arg, &end, 10); | MI_Uint64 x = Strtoull(state.arg, &end, 10); |
| |
if (*end != '\0') | if (*end != '\0') |
err("bad option argument for --idletimeout: %s", state.arg); |
{ |
|
err(ZT("bad option argument for --idletimeout: %s"), |
|
scs(state.arg)); |
|
} |
| |
s_opts.idletimeout = x; | s_opts.idletimeout = x; |
} | } |
|
|
{ | { |
if (Log_SetLevelFromString(state.arg) != 0) | if (Log_SetLevelFromString(state.arg) != 0) |
{ | { |
err("bad option argument for %s: %s", state.opt, state.arg); |
err(ZT("bad option argument for %s: %s"), |
|
scs(state.opt), scs(state.arg)); |
} | } |
} | } |
} | } |
} | } |
| |
static void _EventCallback( |
static void _OnCloseCallback( |
Protocol* protocol, |
_In_ void* object) |
ProtocolEvent event, |
|
void* data) |
|
{ | { |
MI_UNUSED(protocol); |
MI_UNUSED(object); |
MI_UNUSED(event); |
|
MI_UNUSED(data); |
|
| |
LOGI_CHAR(("disconnected form server; exiting")); |
trace_Agent_DisconnectedFromServer(); |
exit(0); |
Selector_StopRunning(&s_data.selector); |
} | } |
| |
static void _ProvMgrCallbackOnIdle( | static void _ProvMgrCallbackOnIdle( |
|
|
MI_UNUSED(mgr); | MI_UNUSED(mgr); |
MI_UNUSED(callbackData); | MI_UNUSED(callbackData); |
| |
LOGI_CHAR(("sending 'agent-idle' notification to the server")); |
DEBUG_ASSERT( s_data.idleNotificationStrand.info.opened ); |
|
|
|
trace_Agent_SendingIdleNotification(); |
| |
notification = BinProtocolNotification_New( BinNotificationAgentIdle ); | notification = BinProtocolNotification_New( BinNotificationAgentIdle ); |
| |
if (!notification) | if (!notification) |
|
{ |
|
// Nothing we can do here |
|
DEBUG_ASSERT( MI_FALSE ); |
return; | return; |
|
} |
| |
Protocol_Send(s_data.protocol, ¬ification->base); |
// Call on the always opened idle notification strand |
|
Strand_SchedulePost( &s_data.idleNotificationStrand, ¬ification->base); |
| |
BinProtocolNotification_Release(notification); | BinProtocolNotification_Release(notification); |
} | } |
|
|
| |
memset(&s_data, 0, sizeof(s_data)); | memset(&s_data, 0, sizeof(s_data)); |
| |
|
/* Enable core dump */ |
|
_EnableCoreDump(); |
|
|
/* Get --destdir option first (other options may depend on it) */ | /* Get --destdir option first (other options may depend on it) */ |
GetCommandLineDestDirOption(&argc, argv); | GetCommandLineDestDirOption(&argc, argv); |
| |
|
|
/* Print help */ | /* Print help */ |
if (s_opts.help) | if (s_opts.help) |
{ | { |
fprintf(stderr, HELP, arg0); |
Ftprintf(stderr, HELP, scs(arg0)); |
exit(1); | exit(1); |
} | } |
| |
/* extract socket number */ | /* extract socket number */ |
if (argc < 3) | if (argc < 3) |
{ | { |
LOGE_CHAR(("parameter is missing (fd)")); |
trace_Agent_FDParameterIsMissing(); |
exit(1); | exit(1); |
} | } |
| |
|
|
/* Open the log file */ | /* Open the log file */ |
if (Log_OpenFD(logfd) != MI_RESULT_OK) | if (Log_OpenFD(logfd) != MI_RESULT_OK) |
{ | { |
err("failed to attach log file to fd: %d; errno %d", logfd, |
err(ZT("failed to attach log file to fd: %d; errno %d"), logfd, |
(int)errno); | (int)errno); |
} | } |
} | } |
|
|
Sock_Start(); | Sock_Start(); |
| |
if(Selector_Init(&s_data.selector) != MI_RESULT_OK) | if(Selector_Init(&s_data.selector) != MI_RESULT_OK) |
err("Selector_Init() failed"); |
err(ZT("Selector_Init() failed")); |
|
|
|
Timer_SetSelector(&s_data.selector); |
|
} |
|
|
|
/* mux */ |
|
{ |
|
if(MuxIn_Init(&s_data.mux, _RequestCallback, NULL, _OnCloseCallback, PostResultMsg_NewAndSerialize) != MI_RESULT_OK) |
|
err(ZT("MuxIn_Init() failed")); |
} | } |
| |
/* Create new protocol object */ | /* Create new protocol object */ |
{ | { |
r = Protocol_New_From_Socket( |
r = ProtocolSocketAndBase_New_Agent( |
&s_data.protocol, | &s_data.protocol, |
&s_data.selector, | &s_data.selector, |
fd, | fd, |
MI_FALSE, |
MuxIn_Open, |
_RequestCallback, |
&s_data.mux); |
0, |
|
_EventCallback, |
|
0); |
|
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
err("Protocol_New_Listener() failed"); |
err(ZT("ProtocolSocketAndBase_New_Agent() failed")); |
} | } |
| |
/* Provider manager */ | /* Provider manager */ |
|
|
r = ProvMgr_Init(&s_data.provmgr, &s_data.selector, _ProvMgrCallbackOnIdle, &s_data, s_opts.provDir); | r = ProvMgr_Init(&s_data.provmgr, &s_data.selector, _ProvMgrCallbackOnIdle, &s_data, s_opts.provDir); |
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
err("ProvMgr_Init() failed"); |
err(ZT("ProvMgr_Init() failed")); |
} | } |
| |
/* idle timeout */ | /* idle timeout */ |
|
|
{ | { |
/* convert it to usec */ | /* convert it to usec */ |
s_data.provmgr.idleTimeoutUsec = s_opts.idletimeout * 1000000; | s_data.provmgr.idleTimeoutUsec = s_opts.idletimeout * 1000000; |
LOGI((T("changing idle timeout to %d sec"), (int)s_opts.idletimeout)); |
trace_Agent_ChangingIdleTimeout(s_opts.idletimeout); |
| |
} | } |
| |
/* Log start up message */ | /* Log start up message */ |
LOGI((T("agent started; fd %d"), (int)fd)); |
trace_Agent_Started((int)fd); |
| |
/* Run the protocol object (waiting for new messages) */ | /* Run the protocol object (waiting for new messages) */ |
r = Protocol_Run(s_data.protocol, TIME_NEVER); |
r = Protocol_Run( &s_data.protocol->internalProtocolBase, TIME_NEVER); |
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
err("Protocol_Run() failed (%d)", (int)r); |
err(ZT("Protocol_Run() failed (%d)"), (int)r); |
| |
// Destroy all global objects | // Destroy all global objects |
Selector_RemoveAllHandlers(&s_data.selector); | Selector_RemoveAllHandlers(&s_data.selector); |
Protocol_Delete(s_data.protocol); |
|
Selector_Destroy(&s_data.selector); | Selector_Destroy(&s_data.selector); |
|
ProvMgr_Destroy(&s_data.provmgr); |
|
ProtocolSocketAndBase_ReadyToFinish(s_data.protocol); |
| |
return 0; | return 0; |
} | } |