Exemple #1
0
/// 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;
}
Exemple #2
0
/// 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);
}