/// Create a new RscQElem object FSTATIC RscQElem* _resource_queue_qelem_new(ResourceCmd* cmd, ResourceQueue* parent , ResourceCmdCallback callback, gpointer user_data, GQueue* Q) { RscQElem* self = MALLOCCLASS(RscQElem, sizeof(RscQElem)); gint64 repeat; gint64 initdelay; self->queuetime = g_get_monotonic_time(); self->cmd = cmd; REF(cmd); self->parent = parent; self->callback = callback; self->user_data = user_data; self->ourQ = Q; self->cancelme = FALSE; repeat = cmd->request->getint(cmd->request, REQREPEATNAMEFIELD); self->repeatinterval = (repeat > 0 ? repeat : 0); if (cmd->request->gettype(cmd->request, REQCANCELONFAILFIELD) != CFG_BOOL) { self->cancelonfail = FALSE; }else{ self->cancelonfail = cmd->request->getbool(cmd->request, REQCANCELONFAILFIELD); } initdelay = cmd->request->getint(cmd->request, CONFIGNAME_INITDELAY); initdelay = (initdelay > 0 ? initdelay : 0); cmd->starttime = self->queuetime + (initdelay*uSPERSEC); DEBUGMSG2("%s.%d: %s:%s (initdelay %ld)", __FUNCTION__, __LINE__ , self->cmd->resourcename, self->cmd->operation, (long)initdelay); return self; }
/// Construct a new CryptCurve25519 object (frame). CryptCurve25519* cryptcurve25519_new(guint16 frame_type, ///<[in] TLV type of CryptCurve25519 const char * sender_key_id, ///<[in] name of sender's key const char * receiver_key_id, ///<[in] name of receiver's key gboolean forsending, ///<[in] TRUE if this is for sending gsize objsize) ///<[in] sizeof(this object) - or zero for default { CryptFrame* baseframe; CryptCurve25519* ret; BINDDEBUG(CryptCurve25519); if (objsize < sizeof(CryptCurve25519)) { objsize = sizeof(CryptCurve25519); } if (NULL == sender_key_id) { sender_key_id = cryptframe_get_signing_key_id(); } DEBUGMSG2("%s.%d:(%s, %s, %d)", __FUNCTION__, __LINE__, sender_key_id, receiver_key_id , (int)objsize); g_return_val_if_fail(sender_key_id != NULL && receiver_key_id != NULL, NULL); if (!_is_valid_curve25519_key_id(receiver_key_id, PUBLICKEY)) { g_critical("%s.%d: public key name [%s] is invalid", __FUNCTION__, __LINE__, receiver_key_id); return NULL; } if (!_is_valid_curve25519_key_id(sender_key_id, PUBLICKEY)) { g_critical("%s.%d: public key name [%s] is invalid", __FUNCTION__, __LINE__, sender_key_id); return NULL; } baseframe = cryptframe_new(frame_type, sender_key_id, receiver_key_id, objsize); if (!_parentclass_finalize) { _parentclass_finalize = baseframe->baseclass.baseclass._finalize; } baseframe->baseclass.isvalid = _cryptcurve25519_default_isvalid; baseframe->baseclass.updatedata = _cryptcurve25519_updatedata; baseframe->baseclass.length = TLVLEN(receiver_key_id, sender_key_id); baseframe->baseclass.baseclass._finalize = _cryptcurve25519_finalize; ret = NEWSUBCLASS(CryptCurve25519, baseframe); ret->forsending = forsending; ret->private_key = cryptframe_private_key_by_id(forsending ? sender_key_id : receiver_key_id); ret->public_key = cryptframe_public_key_by_id(forsending ? receiver_key_id : sender_key_id); if (ret->private_key && ret->public_key) { DEBUGCKSUM3("private_key:", ret->private_key->private_key, crypto_box_SECRETKEYBYTES); DEBUGCKSUM3("public_key:", ret->public_key->public_key, crypto_box_PUBLICKEYBYTES); DUMP3(__FUNCTION__, &ret->baseclass.baseclass.baseclass, " is return value"); REF(ret->private_key); REF(ret->public_key); }else{ if (!ret->private_key) { g_warning("%s.%d: Sender private key is NULL for key id %s", __FUNCTION__, __LINE__ , sender_key_id); abort(); } if (!ret->public_key) { g_warning("%s.%d: Receiver public key is NULL for key id %s", __FUNCTION__, __LINE__ , receiver_key_id); } UNREF3(ret); return NULL; } return ret; }
/** * @ref ChildProcess constructor. * Here's what we're going to do: * 1) Create child process using g_spawn_async_with_pipes() * 2) ...In child process become our own process group * 3) Create LogSourceFd object for stderr * 4) Create LogSourceFd or GMainFd object for stdout * 5) Set timer (if any) * 6) Initialize the child state to running * 7) Return. */ WINEXPORT ChildProcess* childprocess_new(gsize cpsize ///< Size of created ChildProcess object , char** argv ///< NULL-terminated argv for the ChildProcess , const char** envp ///< Environment for the ChildProcess , ConfigContext* envmod ///< Modifications to the ChildProcess environment , const char* curdir ///< Current directory to start the child in , void (*notify)(ChildProcess*, enum HowDied, int rc, int signal, gboolean core_dumped) ///< Function to call if/when the child terminates , gboolean save_stdout ///< TRUE to save stdout, FALSE to log it , const char*logdomain ///< Glib log domain , const char*logprefix ///< Prefix to prepend to log entries , GLogLevelFlags loglevel ///< Glib Log level , guint32 timeout_seconds ///< How long to wait before killing it - zero for no timeout , gpointer user_data ///< Data our user wants us to keep , enum ChildErrLogMode logmode ///< How to log child exits , const char* logname) ///< Name to use when logging child exits as requested { AssimObj* aself; ChildProcess* self; gint stdoutfd; gint stderrfd; GError* failcode = NULL; gchar** childenv = NULL; BINDDEBUG(ChildProcess); g_return_val_if_fail(logprefix != NULL, NULL); if (cpsize < sizeof(ChildProcess)) { cpsize = sizeof(ChildProcess); } aself = assimobj_new(cpsize); g_return_val_if_fail(aself != NULL, NULL); self = NEWSUBCLASS(ChildProcess, aself); childenv = assim_merge_environ(envp, envmod); if (!g_spawn_async_with_pipes( curdir, // Current directory argv, // Arguments childenv, // environment G_SPAWN_DO_NOT_REAP_CHILD, // GSpawnFlags flags, _childprocess_setup_child, // GSpawnChildSetupFunc child_setup, self, // gpointer user_data, &self->child_pid, // GPid *child_pid, NULL, // gint *standard_input, &stdoutfd, // gint *standard_output, &stderrfd, // gint *standard_error, &failcode)) { // GError **error // OOPS! Failed! const char * msg = "unknown exec error"; if (failcode && failcode->message) { msg = failcode->message; } g_critical("%s.%d: %s", __FUNCTION__, __LINE__, msg); if (failcode) { g_clear_error(&failcode); // sets failcode back to NULL } assim_free_environ(childenv); childenv = NULL; UNREF(self); aself = NULL; return NULL; } DEBUGMSG2("%s.%d: Spawned process with user_data = %p", __FUNCTION__, __LINE__, self); aself->_finalize = _childprocess_finalize; aself->toString = _childprocess_toString; self->stderr_src = logsourcefd_new(0, stderrfd, G_PRIORITY_HIGH, g_main_context_default() , logdomain, loglevel, logprefix); self->user_data = user_data; self->logmode = logmode; if (NULL == logname) { logname = argv[0]; } self->loggingname = g_strdup(logname); assim_free_environ(childenv); childenv = NULL; if (!save_stdout) { LogSourceFd* logsrc; logsrc = logsourcefd_new(0, stdoutfd, G_PRIORITY_HIGH , g_main_context_default(), logdomain, loglevel, logprefix); self->stdout_src = &logsrc->baseclass; }else{ self->stdout_src = gmainfd_new(0, stdoutfd, G_PRIORITY_HIGH, g_main_context_default()); } self->childsrc_id = g_child_watch_add(self->child_pid, _childprocess_childexit, self); self->notify = notify; if (0 == timeout_seconds) { DEBUGMSG2("No timeout for process with user_data = %p", self); self->timeoutsrc_id = 0; }else{ self->timeoutsrc_id = g_timeout_add_seconds(timeout_seconds , _childprocess_timeout, self); DEBUGMSG3("%s.%d: Set %d second timeout %d for process with user_data = %p" , __FUNCTION__, __LINE__, timeout_seconds, self->timeoutsrc_id, self); } self->child_state = CHILDSTATE_RUNNING; DEBUGMSG5("%s.%d: REF child: %p", __FUNCTION__,__LINE__, self); REF(self); // We do this because we need to still be here when the process exits return self; }
/// Function called when the child (finally) exits... FSTATIC void _childprocess_childexit(GPid pid, gint status, gpointer childprocess_object) { ChildProcess* self = CASTTOCLASS(ChildProcess, childprocess_object); gboolean signalled = WIFSIGNALED(status); int exitrc = 0; int signal = 0; gboolean logexit = FALSE; enum HowDied howwedied = NOT_EXITED; (void)pid; if (self->timeoutsrc_id > 0) { g_source_remove(self->timeoutsrc_id); DEBUGMSG3("%s.%d: Removed timeout %d for process with user_data = %p" , __FUNCTION__, __LINE__, self->timeoutsrc_id, self); self->timeoutsrc_id = 0; } // If it refused to die, then the status is invalid if ((guint)(self->child_state) >= DIMOF(signalmap)) { howwedied = EXITED_HUNG; }else if ((guint)self->child_state != CHILDSTATE_RUNNING) { // Then we tried to kill it... howwedied = EXITED_TIMEOUT; signal = signalled ? WTERMSIG(status) : 0; }else{ if (signalled) { signal = WTERMSIG(status); howwedied = EXITED_SIGNAL; }else{ exitrc = WEXITSTATUS(status); howwedied = (exitrc == 0 ? EXITED_ZERO : EXITED_NONZERO); } } switch (howwedied) { case EXITED_SIGNAL: /*FALLTHROUGH*/ case EXITED_TIMEOUT: /*FALLTHROUGH*/ case EXITED_HUNG: logexit = self->logmode > CHILD_NOLOG; break; case EXITED_NONZERO: logexit = self->logmode >= CHILD_LOGERRS; break; case EXITED_ZERO: logexit = self->logmode >= CHILD_LOGALL; break; default: // We'll never produce any other values above /*NOTREACHED*/ logexit = TRUE; break; } if (logexit) { switch (howwedied) { case EXITED_SIGNAL: g_warning("Child process [%s] died from signal %d%s." , self->loggingname, signal, WCOREDUMP(status) ? " (core dumped)" : ""); break; case EXITED_TIMEOUT: if (signalled) { g_warning("Child process [%s] timed out after %d seconds [signal %d%s]." , self->loggingname, self->timeout, signal , WCOREDUMP(status) ? " (core dumped)" : ""); }else{ g_warning("Child process [%s] timed out after %d seconds." , self->loggingname, self->timeout); } break; case EXITED_HUNG: g_warning("Child process [%s] timed out after %d seconds and could not be killed." , self->loggingname, self->timeout); break; case EXITED_NONZERO: g_message("Child process [%s] exited with return code %d." , self->loggingname, exitrc); break; case EXITED_ZERO: g_message("Child process [%s] exited normally.", self->loggingname); break; default:/*NOTREACHED*/ break; } } DEBUGMSG2("%s.%d: Exit happened howwedied:%d", __FUNCTION__, __LINE__ , howwedied); if (!self->stdout_src->atEOF) { //DEBUGMSG3("Child %d [%s] EXITED but output is not at EOF [fd%d]", pid //, self->loggingname, self->stdout_src->gfd.fd); self->stdout_src->readmore(self->stdout_src); } if (!self->stderr_src->baseclass.atEOF) { self->stderr_src->baseclass.readmore(&self->stderr_src->baseclass); } self->notify(self, howwedied, exitrc, signal, WCOREDUMP(status)); self->child_state = -1; DEBUGMSG5("%s.%d: UNREF child: %p", __FUNCTION__,__LINE__, self); UNREF(self); // Undo the REF(self) in our constructor }
/// Send JSON that we discovered to the CMA - with some caching going on FSTATIC void _discovery_sendjson(Discovery* self, ///< Our discovery object char * jsonout, ///< malloced JSON output - which we free (!) gsize jsonlen) ///< length of jsonout { FrameSet* fs; CstringFrame* jsf; IntFrame* intf; Frame* fsf; ConfigContext* cfg = self->_config; NetGSource* io = self->_iosource; NetAddr* cma; const char * basename = self->instancename(self); ConfigContext* jsonobject; g_return_if_fail(cfg != NULL && io != NULL); if (NULL == (jsonobject = configcontext_new_JSON_string(jsonout))) { g_warning("%s.%d: JSON Discovery is not legal JSON [%s]" , __FUNCTION__, __LINE__, jsonout); return; } g_free(jsonout); jsonobject->setstring(jsonobject, CONFIGNAME_INSTANCE, basename); jsonout = jsonobject->baseclass.toString(&jsonobject->baseclass); jsonlen = strlen(jsonout); UNREF(jsonobject); DEBUGMSG2("%s.%d: discovering %s: _sentyet == %d" , __FUNCTION__, __LINE__, basename, self->_sentyet); // Primitive caching - don't send what we've already sent. if (self->_sentyet) { const char * oldvalue = cfg->getstring(cfg, basename); if (oldvalue != NULL && strcmp(jsonout, oldvalue) == 0) { DEBUGMSG2("%s.%d: %s sent this value - don't send again." , __FUNCTION__, __LINE__, basename); g_free(jsonout); return; } DEBUGMSG2("%s.%d: %s this value is different from previous value" , __FUNCTION__, __LINE__, basename); } DEBUGMSG2("%s.%d: Sending %"G_GSIZE_FORMAT" bytes of JSON text" , __FUNCTION__, __LINE__, jsonlen); cfg->setstring(cfg, basename, jsonout); cma = cfg->getaddr(cfg, CONFIGNAME_CMADISCOVER); if (cma == NULL) { DEBUGMSG2("%s.%d: %s address is unknown - skipping send" , __FUNCTION__, __LINE__, CONFIGNAME_CMADISCOVER); g_free(jsonout); return; } self->_sentyet = TRUE; fs = frameset_new(FRAMESETTYPE_JSDISCOVERY); intf = intframe_new(FRAMETYPE_WALLCLOCK, 8); intf->setint(intf, self->starttime); frameset_append_frame(fs, &intf->baseclass); UNREF2(intf); jsf = cstringframe_new(FRAMETYPE_JSDISCOVER, 0); fsf = &jsf->baseclass; // base class object of jsf fsf->setvalue(fsf, jsonout, jsonlen+1, frame_default_valuefinalize); // jsonlen is strlen(jsonout) frameset_append_frame(fs, fsf); DEBUGMSG2("%s.%d: Sending a %"G_GSIZE_FORMAT" bytes JSON frameset" , __FUNCTION__, __LINE__, jsonlen); io->_netio->sendareliablefs(io->_netio, cma, DEFAULT_FSP_QID, fs); ++ self->reportcount; UNREF(fsf); UNREF(fs); }