Пример #1
0
void PersistCommand::Validate(bool checkTokenValid) const
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	if (!m_activity->IsPersistTokenSet()) {
		LOG_AM_ERROR(MSGID_PERSIST_TOKEN_NOT_SET,2,
			PMLOGKFV("activity","%llu",m_activity->GetId()),
 		    PMLOGKS("persist_command",GetString().c_str()),
            "Persist token for Activity is not set");

		throw std::runtime_error("Persist token for Activity is not set");
	}

	if (checkTokenValid) {
		boost::shared_ptr<PersistToken> pt = m_activity->GetPersistToken();
		if (!pt->IsValid()) {
			LOG_AM_ERROR(MSGID_PERSIST_TOKEN_INVALID, 2,
				PMLOGKFV("activity","%llu",m_activity->GetId()),
 		        PMLOGKS("persist_command",GetString().c_str()),
			    "Persist token for Activity is set but not valid" );

			throw std::runtime_error("Persist token for Activity is set "
				"but not valid");
		}
	}
}
Пример #2
0
ConversionResultFlags jdouble_to_i32(double value, int32_t *result)
{
	CHECK_POINTER_RETURN_VALUE(result, CONV_BAD_ARGS);
	
	if (isnan(value) != 0) {
		PJ_LOG_WARN("PBNJSON_NAN_TO_INT_WARN", 0, "attempting to convert nan to int");
		*result = 0;
		return CONV_NOT_A_NUM;
	}

	switch (isinf(value)) {
		case 0:
			break;
		case 1:
			PJ_LOG_WARN("PBNJSON_+INF_TO_INT_WARN", 0, "attempting to convert +infinity to int");
			*result = PJSON_MAX_INT;
			return CONV_POSITIVE_INFINITY;
		case -1:
			PJ_LOG_WARN("PBNJSON_-INF_TO_INT_WARN", 0, "attempting to convert -infinity to int");
			*result = PJSON_MIN_INT;
			return CONV_NEGATIVE_INFINITY;
		default:
			PJ_LOG_ERR("PBNJSON_ISINF_ERR", 1, PMLOGKFV("VALUE", "%lf", value), "unknown result from isinf for %lf", value);
			return CONV_GENERIC_ERROR;
	}

	if (value > PJSON_MAX_INT) {
		PJ_LOG_WARN("PBNJSON_DBL_OO_INT_RANGE", 1, PMLOGKFV("VALUE", "%lf", value), "attempting to convert double %lf outside of int range", value);
		*result = PJSON_MAX_INT;
		return CONV_POSITIVE_OVERFLOW;
	}

	if (value < PJSON_MIN_INT) {
		PJ_LOG_WARN("PBNJSON_DBL_OO_INT_RANGE", 1, PMLOGKFV("VALUE", "%lf", value), "attempting to convert double %lf outside of int range", value);
		*result = PJSON_MIN_INT;
		return CONV_NEGATIVE_OVERFLOW;
	}

#if 0
	// unnecessary for 32-bits because they will always fit in a double
	// with no precision loss
	if (value > PJSON_MAX_INT_IN_DBL || value < PJSON_MIN_INT_IN_DBL) {
		PJ_LOG_WARN("PBNJSON_DBL_TO_INT_CONV_WARN", 1, PMLOGKFV("VALUE", "%lf", value), "conversion of double %lf to integer potentially has precision loss", value);
		*result = (int64_t)value;
		return CONV_PRECISION_LOSS;
	}
#endif

	*result = (int32_t) value;
	if (*result != value) {
		PJ_LOG_WARN("PBNJSON_DBL_TO_INT_CONV_LOSS", 1, PMLOGKFV("VALUE", "%lf", value), "conversion of double %lf results in integer with different value", value);
		return CONV_PRECISION_LOSS;
	}

	return CONV_OK;
}
Пример #3
0
void PersistCommand::Complete(bool success)
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	/* All steps of Complete must execute, including launching the next
	 * command in the chain.  All exceptions must be handled locally. */
	try {
		m_completion->Complete(success);
	} catch (const std::exception& except) {
		LOG_AM_WARNING(MSGID_CMD_COMPLETE_EXCEPTION,3,
			PMLOGKFV("activity","%llu",m_activity->GetId()),
		    PMLOGKS("persist_command",GetString().c_str()),
			PMLOGKS("exception",except.what()),"Unexpected exception while trying to complete");
	} catch (...) {
		LOG_AM_WARNING(MSGID_CMD_COMPLETE_EXCEPTION,2,
			PMLOGKFV("activity","%llu",m_activity->GetId()),
		    PMLOGKS("persist_command",GetString().c_str()),"exception while trying to complete");

	}

	/* Tricky order here.  Unhooking this command will probably destroy it,
	 * so we have to pick up a local reference to the next command in the
	 * chain because we won't be able to access the object property.
	 *
	 * The whole chain shouldn't collapse, though, as the next executing
	 * command should be referenced by the same Activity or some other one.
	 * It's just the reference that's bad... but since something like:
	 * Complete "foo"/Create(and replace) "foo"/Cancel old "foo".  If the
	 * Complete is still in process, the Cancel will chain (and ultimately
	 * will succeed as the Activity is already cancelled).
	 */
	boost::shared_ptr<PersistCommand> next = m_next;

	try {
		m_activity->UnhookPersistCommand(shared_from_this());
	} catch (const std::exception& except) {
		LOG_AM_WARNING( MSGID_CMD_UNHOOK_EXCEPTION,3,
			PMLOGKFV("activity","%llu",m_activity->GetId()),
            PMLOGKS("persist_command",GetString().c_str()),
			PMLOGKS("exception",except.what()),"Unexpected exception unhooking command" );
	} catch (...) {
		LOG_AM_WARNING(MSGID_CMD_UNHOOK_EXCEPTION,2,
			PMLOGKFV("activity","%llu",m_activity->GetId()),
            PMLOGKS("persist_command",GetString().c_str()),"exception unhooking command");
	}

	if (next) {
		next->Persist();
	}
}
void PowerdPowerActivity::PowerUnlockedNotification(MojServiceMessage *msg,
	const MojObject& response, MojErr err, bool debounce)
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	if (err == MojErrNone) {
		LOG_AM_DEBUG("[Activity %llu] Power lock successfully %s",
			m_activity.lock()->GetId(), debounce ? "debounced" : "removed");

		// reset the call *before* the unlocked notification; if
		// we end up requeuing the activity due to a transient, we may end
		// up sending a new call.
		m_call.reset();

		m_currentState = PowerUnlocked;
		m_activity.lock()->PowerUnlockedNotification();
	} else {
		LOG_AM_WARNING(MSGID_PWRULK_NOTI_ERR,1,
			PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
			"Attempt to %s power lock failed, retrying. Error: %s",
			debounce ? "debounce" : "remove",
			MojoObjectJson(response).c_str());

		m_call.reset();

		/* Retry. XXX but if error is "Activity doesn't exist", it's done. */
		MojErr err2;
		if (debounce) {
			err2 = CreateRemotePowerActivity(true);
		} else {
			err2 = RemoveRemotePowerActivity();
		}

		if (err2) {
			LOG_AM_WARNING(MSGID_PWR_UNLOCK_CREATE_ERR,1,
				PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
				"Failed to issue command to %s power lock",
				debounce ? "debounce" : "remove");

			/* Not much to do at this point, let the Activity move on
			 * so it doesn't hang. */
			LOG_AM_WARNING(MSGID_PWR_UNLOCK_FAKE_NOTI,1,
				PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
				"Faking power unlocked notification in Noti");

			m_currentState = PowerUnlocked;
			m_activity.lock()->PowerUnlockedNotification();
		}
	}
}
Пример #5
0
ConversionResultFlags ji64_to_i32(int64_t value, int32_t *result)
{
	if (value > PJSON_MAX_INT) {
		PJ_LOG_WARN("PBNJSON_INT64_OO_INT32_RANGE", 1, PMLOGKFV("VALUE", "%"PRId64, value), "overflow converting %"PRId64 " to int32", value);
		*result = PJSON_MAX_INT;
		return CONV_POSITIVE_OVERFLOW;
	}
	if (value < PJSON_MIN_INT) {
		PJ_LOG_WARN("PBNJSON_INT64_OO_INT32_RANGE", 1, PMLOGKFV("VALUE", "%"PRId64, value), "overflow converting %"PRId64 " to int32", value);
		*result = PJSON_MIN_INT;
		return CONV_NEGATIVE_OVERFLOW;
	}
	*result = (int32_t) value;
	return CONV_OK;
}
Пример #6
0
boost::shared_ptr<Requirement> TelephonyProxy::InstantiateRequirement(
	boost::shared_ptr<Activity> activity, const std::string& name,
	const MojObject& value)
{
	LOG_TRACE("Entering function %s", __FUNCTION__);
	LOG_DEBUG("Instantiating [Requirement %s] for [Activity %llu]",
		name.c_str(), activity->GetId());

	if (name == "telephony") {
		if ((value.type() == MojObject::TypeBool) && value.boolValue()) {
			boost::shared_ptr<ListedRequirement> req =
				boost::make_shared<BasicCoreListedRequirement>(
					activity, m_telephonyRequirementCore,
					m_telephonyRequirementCore->IsMet());
			m_telephonyRequirements.push_back(*req);
			return req;
		} else {
			throw std::runtime_error("If a 'telephony' requirement is "
				"specified, the only legal value is 'true'");
		}
	} else {
		LOG_ERROR(MSGID_TIL_UNKNOWN_REQ, 3, PMLOGKS("MANAGER", GetName().c_str()),
			PMLOGKS("REQ",name.c_str()),
			PMLOGKFV("ACTIVITY_ID","%llu",activity->GetId()),
			"does not know how to instantiate Requirement" );
		throw std::runtime_error("Attempt to instantiate unknown requirement");
	}
}
Пример #7
0
inline void
_lshandle_validate(LSHandle *sh)
{
    if (sh && sh->history.magic_state_num != LSHANDLE_MAGIC_STATE_VALID)
    {
        Dl_info create_info;
        Dl_info destroy_info;
        bool create_info_valid = false;
        bool destroy_info_valid = false;

        if (sh->history.creator_ret_addr)
        {
            create_info_valid = dladdr(sh->history.creator_ret_addr, &create_info);
        }

        if (sh->history.destroyer_ret_addr)
        {
            destroy_info_valid = dladdr(sh->history.destroyer_ret_addr, &destroy_info);
        }

        LOG_LS_ERROR(MSGID_LS_INVALID_HANDLE, 5,
                     PMLOGKFV("HANDLER", "%p", sh),
                     PMLOGKS("CREATE_DLI_FNAME", create_info_valid ? create_info.dli_fname : "(unknown)"),
                     PMLOGKS("CREATE_DLI_SNAME", create_info_valid ? create_info.dli_sname : "(unknown)"),
                     PMLOGKS("DESTR_DLI_FNAME", destroy_info_valid ? destroy_info.dli_fname : "(unknown)"),
                     PMLOGKS("DESTR_DLI_SNAME", destroy_info_valid ? destroy_info.dli_sname : "(unknown)"),
                     "%s: Invalid handle", __func__);
        LS_ASSERT(!"Invalid LSHandle");
    }
}
boost::shared_ptr<Requirement> ConnectionManagerProxy::InstantiateRequirement(
	boost::shared_ptr<Activity> activity, const std::string& name,
	const MojObject& value)
{
	LOG_TRACE("Entering function %s", __FUNCTION__);
	LOG_DEBUG("Instantiating [Requirement %s] for [Activity %llu]",
		name.c_str(), activity->GetId());

	if (name == "internet") {
		if ((value.type() == MojObject::TypeBool) && value.boolValue()) {
			boost::shared_ptr<ListedRequirement> req =
				boost::make_shared<BasicCoreListedRequirement>(
					activity, m_internetRequirementCore,
					m_internetRequirementCore->IsMet());
			m_internetRequirements.push_back(*req);
			return req;
		} else {
			throw std::runtime_error("If an 'internet' requirement is "
				"specified, the only legal value is 'true'");
		}
	} else if (name == "internetConfidence") {
		return InstantiateConfidenceRequirement(activity,
			m_internetConfidenceCores, m_internetConfidenceRequirements,
			value);
	} else if (name == "wan") {
		if ((value.type() == MojObject::TypeBool) && value.boolValue()) {
			boost::shared_ptr<ListedRequirement> req =
				boost::make_shared<BasicCoreListedRequirement>(
					activity, m_wanRequirementCore,
					m_wanRequirementCore->IsMet());
			m_wanRequirements.push_back(*req);
			return req;
		} else {
			throw std::runtime_error("If an 'wan' requirement is "
				"specified, the only legal value is 'true'");
		}
	} else if (name == "wanConfidence") {
		return InstantiateConfidenceRequirement(activity, m_wanConfidenceCores,
			m_wanConfidenceRequirements, value);
	} else if (name == "wifi") {
		if ((value.type() == MojObject::TypeBool) && value.boolValue()) {
			boost::shared_ptr<ListedRequirement> req =
				boost::make_shared<BasicCoreListedRequirement>(
					activity, m_wifiRequirementCore,
					m_wifiRequirementCore->IsMet());
			m_wifiRequirements.push_back(*req);
			return req;
		} else {
			throw std::runtime_error("If an 'wifi' requirement is "
				"specified, the only legal value is 'true'");
		}
	} else if (name == "wifiConfidence") {
		return InstantiateConfidenceRequirement(activity, m_wifiConfidenceCores,
			m_wifiConfidenceRequirements, value);
	} else {
		LOG_ERROR(MSGID_REQUIREMENT_INSTANTIATE_FAIL , 3, PMLOGKS("Manager",GetName().c_str()),
			  PMLOGKFV("Activity","%llu",activity->GetId()), PMLOGKS("Requirement",name.c_str()), "");
		throw std::runtime_error("Attempt to instantiate unknown requirement");
	}
}
void PowerdPowerActivity::End()
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);
	LOG_AM_DEBUG("[Activity %llu] Unlocking power",
		m_activity.lock()->GetId());

	if ((m_currentState == PowerUnlocked) || (m_targetState == PowerUnlocked)) {
		return;
	}

	if (m_timeout) {
		m_timeout.reset();
	}

	/* If there's a command in flight, cancel it. */
	if (m_call) {
		m_call.reset();
	}

	m_targetState = PowerUnlocked;
	m_currentState = PowerUnknown;

	bool debounce = m_activity.lock()->IsPowerDebounce();

	MojErr err;
	if (debounce) {
		err = CreateRemotePowerActivity(true);
	} else {
		err = RemoveRemotePowerActivity();
	}

	if (err) {
		LOG_AM_ERROR(MSGID_PWR_UNLOCK_CREATE_FAIL,1,
			PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
			"Failed to issue command to %s power unlock", debounce ? "debounce" : "remove");

		/* Fake it so the Activity doesn't stall - the lock will fall off
		 * on its own... not that that's a good thing, but better than
		 * nothing. */
		LOG_AM_WARNING(MSGID_PWR_UNLOCK_FAKE_NOTI,1,
			PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
			"Faking power unlocked notification");

		m_currentState = PowerUnlocked;
		m_activity.lock()->PowerUnlockedNotification();
	}
}
Пример #10
0
boost::shared_ptr<Requirement> PowerdProxy::InstantiateRequirement(
	boost::shared_ptr<Activity> activity, const std::string& name,
	const MojObject& value)
{
	LOG_TRACE("Entering function %s", __FUNCTION__);
	LOG_DEBUG("Instantiating [Requirement %s] for [Activity %llu]",
		name.c_str(), activity->GetId());

	if (name == "charging") {
		if ((value.type() != MojObject::TypeBool) || !value.boolValue()) {
			throw std::runtime_error("A \"charging\" requirement must specify "
				"'true' if present");
		}

		boost::shared_ptr<ListedRequirement> req =
			boost::make_shared<BasicCoreListedRequirement>(
				activity, m_chargingRequirementCore,
				m_chargingRequirementCore->IsMet());

		m_chargingRequirements.push_back(*req);
		return req;
	} else if (name == "docked") {
		if ((value.type() != MojObject::TypeBool) || !value.boolValue()) {
			throw std::runtime_error("A \"docked\" requirement must specify "
				"'true' if present");
		}

		boost::shared_ptr<ListedRequirement> req =
			boost::make_shared<BasicCoreListedRequirement>(
				activity, m_dockedRequirementCore,
				m_dockedRequirementCore->IsMet());

		m_dockedRequirements.push_back(*req);
		return req;
	} else if (name == "battery") {
		if ((value.type() != MojObject::TypeInt) ||
			(value.intValue() < 0) || (value.intValue() > 100)) {
			throw std::runtime_error("A \"battery\" requirement must specify "
				"a value between 0 and 100");
		}

		MojInt64 percent = value.intValue();

		boost::shared_ptr<BatteryRequirement> req =
			boost::make_shared<BatteryRequirement>(activity, percent,
				boost::dynamic_pointer_cast<PowerdProxy,
					RequirementManager>(shared_from_this()),
				(m_batteryPercent >= percent));
		m_batteryRequirements.insert(*req);
		return req;
	} else {
		LOG_ERROR(MSGID_UNKNOW_REQUIREMENT,3,
			PMLOGKS("MANAGER",GetName().c_str()),
			PMLOGKS("REQUIREMENT",name.c_str()),
			PMLOGKFV("Activity","%llu",activity->GetId()),
			"does not know how to instantiate ");
		throw std::runtime_error("Attempt to instantiate unknown requirement");
	}
}
Пример #11
0
ConversionResultFlags ji64_to_double(int64_t value, double *result)
{
	CHECK_POINTER_RETURN_VALUE(result, CONV_BAD_ARGS);
	if (value > PJSON_MAX_INT_IN_DBL || value < PJSON_MIN_INT_IN_DBL) {
		PJ_LOG_WARN("PBNJSON_INT_TO_DBL_CONV_WARN", 1, PMLOGKFV("VALUE", "%"PRId64, value), "conversion of integer %"PRId64 " to a double will result in precision loss when doing reverse", value);
		*result = (double)value;
		return CONV_PRECISION_LOSS;
	}
	*result = (double)value;
	return CONV_OK;
}
void PowerdPowerActivity::TimeoutNotification()
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);
	LOG_AM_DEBUG("[Activity %llu] Attempting to update power lock",
		m_activity.lock()->GetId());

#ifdef ACTIVITYMANAGER_RENEW_POWER_ACTIVITIES
	MojErr err = CreateRemotePowerActivity();
	if (err) {
		LOG_AM_ERROR(MSGID_PWR_ACTIVITY_CREATE_ERR,1,
			PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
			"Failed to issue command to update power lock");
		m_timeout->Arm();
	}
#else
	LOG_AM_WARNING(MSGID_PWR_TIMEOUT_NOTI,2,
	    PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
	    PMLOGKFV("LOCKDURATION","%d",PowerActivityLockDuration),
	    "Power Activity exceeded maximum length of seconds, not being renewed");
#endif
}
Пример #13
0
/*
 * networkStatusQuery
 *
 * {
 *    "extended" : {
 *    ...
 *        "state" : "noservice" | "limited" | "service"
 *    ...
 *    }
 * }
 *
 */
void TelephonyProxy::NetworkStatusUpdate(MojServiceMessage *msg,
	const MojObject& response, MojErr err)
{
	LOG_TRACE("Entering function %s", __FUNCTION__);
	LOG_DEBUG("Network status update message: %s",
		MojoObjectJson(response).c_str());

	if (err != MojErrNone) {
		if (MojoCall::IsPermanentFailure(msg, response, err)) {
			LOG_WARNING(MSGID_TIL_NWSTATUS_QUERY_ERR,0,
				"TIL experienced an uncorrectable failure : %s", MojoObjectJson(response).c_str());
			m_networkStatusQuery.reset();
		} else {
			LOG_WARNING(MSGID_TIL_NWSTATUS_QUERY_RETRY, 0,
				"Subscription to TIL failed, retrying - %s", MojoObjectJson(response).c_str() );
			m_networkStatusQuery->Call();
		}
		return;
	}

	MojObject extended;

	bool found;
	found = response.get(_T("extended"), extended);
	if (!found) {
		/* Way to have 2 different formats for the same thing!  First
		 * response names the property "extended".  All subsequent ones
		 * name it "eventNetwork". */
		found = response.get(_T("eventNetwork"), extended);
	}

	if (found) {
		MojString status;
		MojErr err2;

		err2 = extended.get(_T("state"), status, found);
		if (err2) {
			LOG_WARNING(MSGID_TIL_NWSTATE_ERR, 1 ,
				PMLOGKFV("NWSTATE","%d",err2),
				"Error attempting to retrieve network state");
		} else if (found) {
			if (status == "service") {
			    m_haveTelephonyService = true;
			} else {
			    m_haveTelephonyService = false;
			}
			UpdateTelephonyState();
		} else {
			LOG_WARNING(MSGID_TIL_NO_NWSTATE, 0 ,
				"Network status update message did not include network state: %s", MojoObjectJson(response).c_str());
		}
	}
}
Пример #14
0
MojErr MojDbLunaServiceDb::recoverDb(MojDbEnv* env, const MojChar* dir, const MojObject& conf)
{
    MojErr err;

    if (m_recoveryScriptPath.empty()) {
        LOG_ERROR(MSGID_LUNA_SERVICE_DB_OPEN,0, "No recovery script, close database");
        return MojErrDbFatal;
    }

    int recoveryResult = system(m_recoveryScriptPath.data());
    if (recoveryResult != 0) {
        LOG_ERROR(MSGID_LUNA_SERVICE_DB_OPEN,
                  3,
                  PMLOGKS("recoveryScript", m_recoveryScriptPath.data()),
                  PMLOGKFV("scriptExecResult", "%i", recoveryResult),
                  PMLOGKS("dbdir", dir),
                  "Can't recovery database with help of recovery script");

        return MojErrDbFatal;   // close database and stop process
    }

    LOG_INFO(MSGID_LUNA_SERVICE_DB_OPEN, 0, "Recovery database success, reopen database" );
    err = openDb(env, dir, conf);

    if (err != MojErrNone) {
        MojString msg;
        MojErrToString(err, msg);
        LOG_ERROR(MSGID_LUNA_SERVICE_DB_OPEN, 3,
                  PMLOGKS("dbdir", dir),
                  PMLOGKS("dbdata", msg.data()),
                  PMLOGKFV("dberror", "%d", err),
                  "Error re-opening database after recovery");

        return err;
    }

    return MojErrNone;
}
void PowerdPowerActivity::Begin()
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);
	LOG_AM_DEBUG("[Activity %llu] Locking power on",
		m_activity.lock()->GetId());

	if ((m_currentState == PowerLocked) || (m_targetState == PowerLocked)) {
		return;
	}

	if (m_timeout) {
		m_timeout.reset();
	}

	/* If there's a command in flight, cancel it. */
	if (m_call) {
		m_call.reset();
	}

	m_targetState = PowerLocked;
	m_currentState = PowerUnknown;

	MojErr err = CreateRemotePowerActivity();
	if (err) {
		LOG_AM_ERROR(MSGID_PWR_LOCK_CREATE_FAIL,1,
			PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
			"Failed to issue command to create power lock");

		/* Fake it so the Activity doesn't stall */
		LOG_AM_WARNING(MSGID_PWR_LOCK_FAKE_NOTI,1,
			PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
			"Faking power locked notification");

		m_currentState = PowerLocked;
		m_activity.lock()->PowerLockedNotification();
	}
}
void ConnectionManagerProxy::UpdateConfidenceRequirements(
	boost::shared_ptr<RequirementCore> *confidenceCores,
	RequirementList *confidenceLists, int confidence)
{
	if (((confidence < 0) || (confidence >= ConnectionConfidenceMax)) &&
		(confidence != ConnectionConfidenceUnknown)) {
		LOG_WARNING(MSGID_UNKNOWN_CONN_CONFIDENCE_LEVEL, 1, PMLOGKFV("conn_confidence_level","%d",confidence),
			    "Unknown connection confidence level seen attempting to update confidence requirements");
		return;
	}

	MojString& confidenceName = (confidence == ConnectionConfidenceUnknown) ?
		ConnectionConfidenceUnknownName :
		ConnectionConfidenceNames[confidence];

	for (int i = 0; i < ConnectionConfidenceMax; ++i) {
		confidenceCores[i]->SetCurrentValue(MojObject(confidenceName));

		if (confidence < i) {
			if (confidenceCores[i]->IsMet()) {
				confidenceCores[i]->Unmet();
				std::for_each(confidenceLists[i].begin(),
					confidenceLists[i].end(),
					boost::mem_fn(&Requirement::Unmet));
			} else {
				std::for_each(confidenceLists[i].begin(),
					confidenceLists[i].end(),
					boost::mem_fn(&Requirement::Updated));
			}
		} else {
			if (!confidenceCores[i]->IsMet()) {
				confidenceCores[i]->Met();
				std::for_each(confidenceLists[i].begin(),
					confidenceLists[i].end(),
					boost::mem_fn(&Requirement::Met));
			} else {
				std::for_each(confidenceLists[i].begin(),
					confidenceLists[i].end(),
					boost::mem_fn(&Requirement::Updated));
			}
		}
	}
}
Пример #17
0
MojErr MojDbIndex::addWatch(const MojDbQueryPlan& plan, MojDbCursor& cursor, MojDbWatcher* watcher, MojDbReq& req)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);
	MojAssert(watcher);

	// TODO: use interval tree instead of vector for watches
	MojThreadWriteGuard guard(m_lock);
	MojErr err = m_watcherVec.push(watcher);
	MojErrCheck(err);
	// update count map
	watcher->domain(req.domain());
	WatcherMap::Iterator iter;
	err = m_watcherMap.find(req.domain(), iter);
	MojErrCheck(err);
	if (iter == m_watcherMap.end()) {
		err = m_watcherMap.put(req.domain(), 1);
		MojErrCheck(err);
	} else {
		iter.value() += 1;
		if (iter.value() > WatchWarningThreshold) {
            LOG_WARNING(MSGID_MOJ_DB_INDEX_WARNING, 4,
            		PMLOGKS("domain", req.domain().data()),
            		PMLOGKFV("iter", "%zd", iter.value()),
            		PMLOGKS("kindId", m_kind->id().data()),
            		PMLOGKS("name", m_name.data()),
            		"db:'domain' has 'iter' watches open on index 'kindId - name'");
		}
	}
	LOG_DEBUG("[db_mojodb] DbIndex_addWatch - '%s' on index '%s - %s'",
		req.domain().data(),  m_kind->id().data(), m_name.data());
	// drop lock before acquiring watcher mutex in init
	guard.unlock();
	watcher->init(this, plan.ranges(), plan.desc(), false);

	return MojErrNone;
}
Пример #18
0
MojErr MojDbLunaServiceDb::open(MojGmainReactor& reactor, MojDbEnv* env,
                                const MojChar* serviceName, const MojChar* dir, const MojObject& conf)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);

    // open service
    MojErr err = m_service.open(serviceName);
    MojErrCheck(err);
    err = m_service.attach(reactor.impl());
    MojErrCheck(err);
    // open handler
    err = m_handler->open();
    MojErrCheck(err);
    err = m_service.addCategory(MojDbServiceDefs::Category, m_handler.get());
    MojErrCheck(err);

    LOG_DEBUG("[MojDb] service name: %s", serviceName);

    // open db
    err = openDb(env, dir, conf);
    if (err != MojErrNone) {
        MojString msg;
        MojErrToString(err, msg);
        LOG_WARNING(MSGID_LUNA_SERVICE_DB_OPEN,
                      3,
                      PMLOGKS("dbdir", dir),
                      PMLOGKS("dbdata", msg.data()),
                      PMLOGKFV("dberror", "%d", err),
                      "Can't open database");

        err = recoverDb(env, dir, conf);
        MojErrCheck(err);
    }

    return err;
}
Пример #19
0
void PowerdProxy::ChargerStatusSignal(MojServiceMessage *msg,
	const MojObject& response, MojErr err)
{
	LOG_TRACE("Entering function %s", __FUNCTION__);
	LOG_DEBUG("Received charger status signal: %s",
		MojoObjectJson(response).c_str());

	if (err != MojErrNone) {
		m_chargerStatusSubscribed = false;

		if (MojoCall::IsPermanentFailure(msg, response, err)) {
			LOG_WARNING(MSGID_CHRGR_STATUS_SIG_FAIL,0,
				"Subscription to charger status signal experienced an uncorrectable failure: %s",
				MojoObjectJson(response).c_str());
			m_chargerStatus.reset();
		} else {
			LOG_WARNING(MSGID_CHRGR_SIG_ENABLE,0,
				"Subscription to charger status signal failed, resubscribing: %s",
				MojoObjectJson(response).c_str());
			EnableChargerSignals();
		}
		return;
	}

	if (!m_chargerStatusSubscribed) {
		m_chargerStatusSubscribed = true;
		TriggerChargerStatus();
	}

	/* Not all responses will contain charger information... for example,
	 * the initial subscription result. */
	MojString chargerType;
	bool found = false;
	MojErr err2 = response.get(_T("type"), chargerType, found);
	if (err2) {
		LOG_ERROR(MSGID_CHRGR_SIG_NO_TYPE, 1,PMLOGKFV("ERROR","%d",err2),
			"Error retrieving charger type from charger status signal response");
		return;
	} else if (found) {
		bool connected;
		found = response.get(_T("connected"), connected);
		if (!found) {
			LOG_WARNING(MSGID_CHRGR_NOT_CONNECTED,1,PMLOGKS("TYPE",chargerType.data()),
				"Charger type found, but not it's connected");
			return;
		}

		if (chargerType == "usb") {
			m_usbChargerConnected = connected;
		} else if (chargerType == "inductive") {
			m_inductiveChargerConnected = connected;
		} else {
			LOG_WARNING(MSGID_CHRGR_TYPE_UNKNOWN, 1, PMLOGKS("TYPE",chargerType.data()),
				"Unknown charger type");
			return;
		}

		found = false;
		MojString name;
		err2 = response.get(_T("name"), name, found);
		if (err2) {
			LOG_ERROR(MSGID_CHRGR_NO_NAME,2, PMLOGKS("TYPE",chargerType.data()),
				PMLOGKFV("ERR", "%d", err2),
				"Error retrieving the specific name of charger");
		} else if (found) {
			if (name == "puck") {
				m_onPuck = connected;
			}
		}

		if (m_onPuck) {
			if (!m_dockedRequirementCore->IsMet()) {
				LOG_DEBUG("Device is now docked");
				m_dockedRequirementCore->Met();
				std::for_each(m_dockedRequirements.begin(),
					m_dockedRequirements.end(),
					boost::mem_fn(&Requirement::Met));
			}
		} else {
			if (m_dockedRequirementCore->IsMet()) {
				LOG_DEBUG("Device is no longer docked");
				m_dockedRequirementCore->Unmet();
				std::for_each(m_dockedRequirements.begin(),
					m_dockedRequirements.end(),
					boost::mem_fn(&Requirement::Unmet));
			}
		}

		if (m_inductiveChargerConnected || m_usbChargerConnected) {
			if (!m_chargingRequirementCore->IsMet()) {
				LOG_DEBUG("Device is now charging");
				m_chargingRequirementCore->Met();
				std::for_each(m_chargingRequirements.begin(),
					m_chargingRequirements.end(),
					boost::mem_fn(&Requirement::Met));
			}
		} else {
			if (m_chargingRequirementCore->IsMet()) {
				LOG_DEBUG("Device is no longer charging");
				m_chargingRequirementCore->Unmet();
				std::for_each(m_chargingRequirements.begin(),
					m_chargingRequirements.end(),
					boost::mem_fn(&Requirement::Unmet));
			}
		}
	}
}
void PowerdPowerActivity::PowerLockedNotification(MojServiceMessage *msg,
	const MojObject& response, MojErr err)
{
	LOG_AM_TRACE("Entering function %s", __FUNCTION__);

	if (err == MojErrNone) {
		if (m_currentState != PowerLocked) {
			LOG_AM_DEBUG("[Activity %llu] Power lock successfully created",
				m_activity.lock()->GetId());

			m_currentState = PowerLocked;
			m_activity.lock()->PowerLockedNotification();
		} else {
			LOG_AM_DEBUG("[Activity %llu] Power lock successfully updated",
				m_activity.lock()->GetId());
		}

		if (!m_timeout) {
			m_timeout = boost::make_shared<Timeout<PowerdPowerActivity> >(
				boost::dynamic_pointer_cast<PowerdPowerActivity, PowerActivity>(
					shared_from_this()), PowerActivityLockUpdateInterval,
					&PowerdPowerActivity::TimeoutNotification);
		}

		m_timeout->Arm();

		m_call.reset();
	} else {
		if (m_currentState != PowerLocked) {
			LOG_AM_WARNING(MSGID_PWRLK_NOTI_CREATE_FAIL,1,
				PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
				"Attempt to create power lock failed, retrying. Error %s",
				 MojoObjectJson(response).c_str());
		} else {
			LOG_AM_WARNING(MSGID_PWRLK_NOTI_UPDATE_FAIL,1,
				PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
				"Attempt to update power lock failed, retrying. Error %s",
				MojoObjectJson(response).c_str());
		}

		m_call.reset();

		/* Retry - powerd may have restarted. */
		MojErr err2 = CreateRemotePowerActivity();
		if (err2) {
			LOG_AM_WARNING(MSGID_PWR_LOCK_CREATE_FAIL,1,
				PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
				"Failed to issue command to create power lock in Noti" );

			/* If power was not currently locked, fake the create so the
			 * Activity doesn't hang */
			if (m_currentState != PowerLocked) {
				LOG_AM_WARNING(MSGID_PWR_LOCK_FAKE_NOTI,1,
					PMLOGKFV("Activity","%llu",m_activity.lock()->GetId()),
					"Faking power locked notification in noti");

				m_currentState = PowerLocked;
				m_activity.lock()->PowerLockedNotification();
			}
		}
	}
}
Пример #21
0
static void
alarm_read_db(void)
{
	bool retVal;

	xmlDocPtr db = xmlReadFile(gAlarmQueue->alarm_db, NULL, 0);

	if (!db)
	{
		return;
	}

	xmlNodePtr cur = xmlDocGetRootElement(db);
	xmlNodePtr sub;

	if (!cur)
	{
		return;
	}

	sub = cur->children;

	while (sub != NULL)
	{
		if (!xmlStrcmp(sub->name, (const xmlChar *)"alarm"))
		{
			xmlChar *id = xmlGetProp(sub, (const xmlChar *)"id");
			xmlChar *key = xmlGetProp(sub, (const xmlChar *)"key");
			xmlChar *expiry = xmlGetProp(sub, (const xmlChar *)"expiry");
			xmlChar *calendar = xmlGetProp(sub, (const xmlChar *)"calendar");
			xmlChar *service = xmlGetProp(sub, (const xmlChar *)"serviceName");
			xmlChar *app = xmlGetProp(sub, (const xmlChar *)"applicationName");

			if (!id || !expiry)
			{
				goto clean_round;
			}

			unsigned long expiry_secs = 0;
			uint32_t alarmId = 0;
			bool isCalendar = false;

			if (expiry)
			{
				expiry_secs = atol((const char *)expiry);
			}

			if (id)
			{
				alarmId = atoi((const char *)id);
			}

			if (calendar)
			{
				isCalendar = atoi((const char *)calendar) > 0;
			}

			retVal = alarm_queue_add(alarmId, (const char *)key,
			                         isCalendar, expiry_secs,
			                         (const char *)service,
			                         (const char *)app, false, NULL);

			if (!retVal)
			{
				SLEEPDLOG_WARNING(MSGID_ALARM_NOT_SET, 3, PMLOGKFV(ALARM_ID, "%d", alarmId),
				                  PMLOGKS(SRVC_NAME, service), PMLOGKS(APP_NAME, app), "could not add alarm");
			}

clean_round:
			xmlFree(expiry);
			xmlFree(service);
			xmlFree(app);
		}

		sub = sub->next;
	}

	xmlFreeDoc(db);
}
Пример #22
0
void MojoDBProxy::ActivityLoadResults(MojServiceMessage *msg,
	const MojObject& response, MojErr err)
{
	LOG_TRACE("Entering function %s", __FUNCTION__);
	LOG_DEBUG("Processing Activities loaded from MojoDB");

	/* Don't allow the Activity Manager to start up if the MojoDB load
	 * fails ... */
	if (err != MojErrNone) {
		if (MojoCall::IsPermanentFailure(msg, response, err)) {
			LOG_ERROR(MSGID_LOAD_ACTIVITIES_FROM_DB_FAIL, 0,
				     "Uncorrectable error loading Activities from MojoDB: %s", MojoObjectJson(response).c_str());
#ifdef ACTIVITYMANAGER_REQUIRE_DB
			m_app->shutdown();
#else
			m_app->ready();
#endif
		} else {
			LOG_WARNING(MSGID_ACTIVITIES_LOAD_ERR, 0, "Error loading Activities from MojoDB, retrying: %s",
                                    MojoObjectJson(response).c_str());
			m_call->Call();
		}
		return;
	}

	/* Clear current call */
	m_call.reset();

	bool found;
	MojErr err2;
	MojObject results;
	found = response.get(_T("results"), results);

	if (found) {
		for (MojObject::ConstArrayIterator iter = results.arrayBegin();
			iter != results.arrayEnd(); ++iter) {
			const MojObject& rep = *iter;
			MojInt64 activityId;

			bool found;
			found = rep.get(_T("activityId"), activityId);
			if (!found) {
				LOG_WARNING(MSGID_ACTIVITYID_NOT_FOUND, 0, "activityId not found loading Activities");
					continue;
			}

			MojString id;
			MojErr err = rep.get(_T("_id"), id, found);
			if (err) {
				LOG_WARNING(MSGID_RETRIEVE_ID_FAIL, 0, "Error retrieving _id from results returned from MojoDB");
				continue;
			}

			if (!found) {
				LOG_WARNING(MSGID_ID_NOT_FOUND, 0, "_id not found loading Activities from MojoDB");
				continue;
			}

			MojInt64 rev;
			found = rep.get(_T("_rev"), rev);
			if (!found) {
				LOG_WARNING(MSGID_REV_NOT_FOUND, 0, "_rev not found loading Activities from MojoDB");
				continue;
			}

			boost::shared_ptr<MojoDBPersistToken> pt =
				boost::make_shared<MojoDBPersistToken>(id, rev);

			boost::shared_ptr<Activity> act;

			try {
				act = m_json->CreateActivity(rep, Activity::PrivateBus, true);
			} catch (const std::exception& except) {
				LOG_WARNING(MSGID_CREATE_ACTIVITY_EXCEPTION, 1, PMLOGKS("Exception",except.what()),
					  "Activity: %s", MojoObjectJson(rep).c_str());
				m_oldTokens.push_back(pt);
				continue;
			} catch (...) {
				LOG_WARNING(MSGID_UNKNOWN_EXCEPTION, 0, "Activity : %s. Unknown exception decoding encoded",
					  MojoObjectJson(rep).c_str());
				m_oldTokens.push_back(pt);
				continue;
			}

			act->SetPersistToken(pt);

			/* Attempt to register this Activity's Id and Name, in order. */

			try {
				m_am->RegisterActivityId(act);
			} catch (...) {
				LOG_ERROR(MSGID_ACTIVITY_ID_REG_FAIL, 1, PMLOGKFV("Activity","%llu", act->GetId()), "");

				/* Another Activity is already registered.  Determine which
				 * is newer, and kill the older one. */

				boost::shared_ptr<Activity> old = m_am->GetActivity(
					act->GetId());
				boost::shared_ptr<MojoDBPersistToken> oldPt =
					boost::dynamic_pointer_cast<MojoDBPersistToken,
						PersistToken>(old->GetPersistToken());

				if (pt->GetRev() > oldPt->GetRev()) {
					LOG_WARNING(MSGID_ACTIVITY_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()),
						    PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()),
						    PMLOGKFV("old_Activity","%llu",old->GetId()),
						    PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), "");

					m_oldTokens.push_back(oldPt);
					m_am->UnregisterActivityName(old);
					m_am->ReleaseActivity(old);

					m_am->RegisterActivityId(act);
				} else {
					LOG_WARNING(MSGID_ACTIVITY_NOT_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()),
						    PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()),
						    PMLOGKFV("old_Activity","%llu",old->GetId()),
						    PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), "");

					m_oldTokens.push_back(pt);
					m_am->ReleaseActivity(act);
					continue;
				}
			}

			try {
				m_am->RegisterActivityName(act);
			} catch (...) {
				LOG_ERROR(MSGID_ACTIVITY_NAME_REG_FAIL, 3, PMLOGKFV("Activity","%llu",act->GetId()),
					  PMLOGKS("Creator_name",act->GetCreator().GetString().c_str()),
					  PMLOGKS("Register_name",act->GetName().c_str()), "");

				/* Another Activity is already registered.  Determine which
				 * is newer, and kill the older one. */

				boost::shared_ptr<Activity> old = m_am->GetActivity(
					act->GetName(), act->GetCreator());
				boost::shared_ptr<MojoDBPersistToken> oldPt =
					boost::dynamic_pointer_cast<MojoDBPersistToken,
						PersistToken>(old->GetPersistToken());

				if (pt->GetRev() > oldPt->GetRev()) {
					LOG_WARNING(MSGID_ACTIVITY_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()),
						    PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()),
						    PMLOGKFV("old_Activity","%llu",old->GetId()),
						    PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), "");

					m_oldTokens.push_back(oldPt);
					m_am->UnregisterActivityName(old);
					m_am->ReleaseActivity(old);

					m_am->RegisterActivityName(act);
				} else {
					LOG_WARNING(MSGID_ACTIVITY_NOT_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()),
						    PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()),
						    PMLOGKFV("old_Activity","%llu",old->GetId()),
						    PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), "");

					m_oldTokens.push_back(pt);
					m_am->ReleaseActivity(act);
					continue;
				}
			}

			LOG_DEBUG("[Activity %llu] (\"%s\"): _id %s, rev %llu loaded",
				act->GetId(), act->GetName().c_str(), id.data(),
				(unsigned long long)rev);

			/* Request Activity be scheduled.  It won't transition to running
			 * until after the MojoDB load finishes (and the Activity Manager
			 * moves to the ready() and start()ed states). */
			m_am->StartActivity(act);
		}
	}

	MojString page;
	err2 = response.get(_T("page"), page, found);
	if (err2) {
		LOG_ERROR(MSGID_GET_PAGE_FAIL, 0, "Error getting page parameter in MojoDB query response");
		return;
	}

	if (found) {
		LOG_DEBUG("Preparing to request next page (\"%s\") of Activities",
			page.data());

		MojObject query;
		query.putString(_T("from"), ActivityKind);

		query.putString(_T("page"), page);

		MojObject params;
		params.put(_T("query"), query);

		m_call = boost::make_shared<MojoWeakPtrCall<MojoDBProxy> >(
			boost::dynamic_pointer_cast<MojoDBProxy, PersistProxy>
				(shared_from_this()),
			&MojoDBProxy::ActivityLoadResults,
			m_service, "palm://com.palm.db/find", params);

		m_call->Call();
	} else {
		LOG_DEBUG("All Activities successfully loaded from MojoDB");

		if (!m_oldTokens.empty()) {
			LOG_DEBUG("Beginning purge of old Activities from database");
			PreparePurgeCall();
			m_call->Call();
		} else {
#ifdef ACTIVITYMANAGER_CALL_CONFIGURATOR
			PrepareConfiguratorCall();
			m_call->Call();
#else
			m_call.reset();
			m_am->Enable(ActivityManager::CONFIGURATION_LOADED);
#endif
		}

		m_app->ready();
	}
}
Пример #23
0
ConversionResultFlags parseJSONNumber(raw_buffer *str, int64_t *integerPortion,
		int64_t *exponentPortion, int64_t *decimalPortion, int64_t *decimalLeadingZeros)
{
	size_t i = 0;
	int integerMultiplier = 1;
	int exponentMultiplier = 1;
	int64_t exponent = 0;
	int64_t fraction = 0;
	int64_t fractionFactor = 0;
	int64_t trailingZeros = 0;
	bool validDecimal;
	int64_t temp;

	ConversionResultFlags result = CONV_OK;

	*integerPortion = 0;

	if (str->m_len == 0) {
		result = CONV_NOT_A_NUM;
		goto fast_stop;
	}

	switch (str->m_str[i]) {
		case '-':
			integerMultiplier = -1;
			i++;
			goto parse_integer_portion;
		case '0':
			i++;
			if (i >= str->m_len)
				goto fast_stop;
			switch(str->m_str[i])
			{
			case '.':
				goto parse_decimal_portion;
			case 'e':
			case 'E':
				goto parse_exponent_portion;
			default:
				result = CONV_NOT_A_NUM;
				goto fast_stop;
			}
		case '1'...'9':
			goto parse_integer_portion;
		default:
			goto not_a_number;
	}

parse_integer_portion:
	assert(integerMultiplier == 1 || integerMultiplier == -1);
	assert(exponent == 0);
	for (; i  < str->m_len; i++) {
		switch (str->m_str[i]) {
			case 'e':
			case 'E':
				goto parse_exponent_portion;
			case '.':
				goto parse_decimal_portion;
			case '0'...'9':
				if (exponent == 0) {
					if (integerMultiplier == 1) {
						if (*integerPortion > (INT64_MAX / 10))
							exponent = 1;
					} else {
						if (*integerPortion < (INT64_MIN) / 10)
							exponent = 1;
					}
					if (exponent == 0) {
						temp = *integerPortion * 10 + integerMultiplier * (str->m_str[i] - '0');
						if (UNLIKELY(temp * integerMultiplier < 0)) {
							// sign flipped - overflow
							exponent = 1;
						} else {
							*integerPortion = temp;
						}
					}
				} else {
					if (exponent++ == INT64_MAX)
						return CONV_PRECISION_LOSS | (integerMultiplier == 1 ? CONV_POSITIVE_INFINITY : CONV_NEGATIVE_INFINITY);
				}
				break;
			default:
				PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR1", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]),
				            "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i);
				goto not_a_number;
		}
	}
	goto finish_parse;

parse_decimal_portion:
	validDecimal = false;
	assert(fraction == 0);
	assert(fractionFactor == 0);
	assert(trailingZeros == 0);

	if (str->m_str[i] != '.') {
		assert(false);
		PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR2", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]),
		            "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int) str->m_len, str->m_str, i);
		goto not_a_number;
	}
	i++;

	for (; i < str->m_len; i++) {
		switch(str->m_str[i]) {
			case 'e':
			case 'E':
				goto parse_exponent_portion;
			case '0'...'9':
				validDecimal = true;
				if (str->m_str[i] == '0') {
					// short-circuit - trailing 0s are ignored if that's what they are.
					trailingZeros ++;
					break;
				}
				if (UNLIKELY(fractionFactor == INT64_MAX)) {
					assert(false);
					// this will only become an issue if 10^INT64_MAX < (2^((sizeof(fraction)*8) - 1) - 1)
					// which will never happen
					PJ_LOG_ERR("PBNJSON_FRACTION_ERR", 1, PMLOGKS("STRING", str->m_str), "Internal error for input: %.*s", (int)str->m_len, str->m_str);
					return CONV_GENERIC_ERROR;
				}

				while (trailingZeros != 0) {
					temp = fraction * 10;
					if (temp < 0)
						goto skip_remaining_decimal;
					trailingZeros--;
					fractionFactor++;
					fraction = temp;
				}
				fractionFactor++;

				if (fraction != INT64_MAX) {
					temp = fraction * 10 + (str->m_str[i] - '0');
					if (UNLIKELY(temp < 0)) {
						fractionFactor--;
						goto skip_remaining_decimal;
					} else {
						fraction = temp;
					}
				}
				break;
			default:
				PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR3", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]),
				            "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i);
				goto not_a_number;
		}
	}
	if (UNLIKELY(!validDecimal)) {
		PJ_LOG_WARN("PBNJSON_UNXPCTD_EOS", 0, "Unexpected end of string at %zu in '%.*s'", i, (int)str->m_len, str->m_str);
		goto not_a_number;
	}
	goto finish_parse;

skip_remaining_decimal:
	assert(str->m_str[i] >= '0');
	assert(str->m_str[i] <= '9');

	result |= CONV_PRECISION_LOSS;

	for (; i < str->m_len; i++) {
		if (str->m_str[i] >= '0' && str->m_str[i] <= '9')
			continue;
		if (str->m_str[i] == 'e' || str->m_str[i] == 'E')
			goto parse_exponent_portion;

		PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR4", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]),
		            "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i);
		goto not_a_number;
	}
	assert(i == str->m_len);
	goto finish_parse;

parse_exponent_portion:
	assert(exponent >= 0);
	if (UNLIKELY(str->m_str[i] != 'e' && str->m_str[i] != 'E')) {
		// problem with the state machine
		assert(false);
		PJ_LOG_ERR("PBNJSON_NO_EXPONENT", 1, PMLOGKS("STRING", str->m_str), "Expecting an exponent but didn't get one at %zu in '%.*s'", i, (int)str->m_len, str->m_str);
		return CONV_GENERIC_ERROR;
	}
	i++;

	switch (str->m_str[i]) {
	case '-':
		i++;
		exponentMultiplier = -1;
		break;
	case '+':
		i++;
	case '0'...'9':
		exponentMultiplier = 1;
		break;
	default:
		PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR5", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]),
		            "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i);
		goto not_a_number;
	}
	assert(exponentMultiplier == 1 || exponentMultiplier == -1);

	for (; i < str->m_len; i++) {
		switch (str->m_str[i]) {
			case '0'...'9':
				if (exponentMultiplier == 1) {
					if (UNLIKELY(exponent > (INT64_MAX / 10)))
						goto exponent_overflow;
				} else if (exponentMultiplier == -1) {
					if (UNLIKELY(exponent < (INT64_MIN / 10)))
						goto exponent_overflow;
				}
				exponent *= 10;
				exponent += exponentMultiplier * (str->m_str[i] - '0');
				if (exponent * exponentMultiplier < 0) {
					goto exponent_overflow;
				}
				break;
			default:
				PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR6", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]),
				            "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i);
				goto not_a_number;
		}
	}
	assert(i == str->m_len);
	goto finish_parse;

exponent_overflow:
	// overflow of a 64-bit exponent - +/- infinity or 0 it is.
	assert(exponent > (INT64_MAX / 10 - 10) || exponent < (INT64_MIN / 10 + 10));

	if (exponentMultiplier == 1) {
		exponent = INT64_MAX;
		if (integerMultiplier == 1) {
			*integerPortion = INT64_MAX;
			result |= CONV_POSITIVE_INFINITY;
		} else {
			*integerPortion = INT64_MIN;
			result |= CONV_NEGATIVE_INFINITY;
		}
	} else {
		result |= CONV_PRECISION_LOSS;
		exponent = INT64_MIN;
		*integerPortion = 0;
	}
	goto finish_parse;

finish_parse:
	if (trailingZeros) {
		PJ_LOG_DBG("%"PRId64 " unnecessary 0s in fraction portion of '%.*s'", trailingZeros, (int)str->m_len, str->m_str);
	}

	if (fraction == 0) {
		assert(fractionFactor == 0);
	}

	if (*integerPortion == 0 && (decimalPortion == NULL || fraction == 0)) {
		// shortcut - exponent is redundant if the number is 0.something but we're
		// ignoring the decimal (or there's no fractional portion)
		exponent = 0;
		if (fraction != 0) {
			result |= CONV_PRECISION_LOSS;
		}
	}

	// can't really do this anyways - it would require us shifting values into or out
	// of the fractional component when we adjust the integerPortion by the exponent.
	// internally, we would never use this case anyways because if we care what the
	// fraction is (i.e. we're converting to a floating point), we'll provide the exponent
	// pointer anyways
	if (exponentPortion == NULL && exponent != 0 && fraction != 0) {
		result |= CONV_PRECISION_LOSS;
		fraction = 0;
		fractionFactor = 0;
	}

	if (!exponentPortion) {
		if (*integerPortion != 0) {
			if (exponent > 0) {
				while (exponent) {
					if (*integerPortion > INT64_MAX / 10) {
						assert(integerMultiplier == 1);
						result |= CONV_POSITIVE_OVERFLOW;
						*integerPortion = INT64_MAX;
						break;
					} else if (*integerPortion < INT64_MIN / 10) {
						assert(integerMultiplier == -1);
						result |= CONV_NEGATIVE_OVERFLOW;
						*integerPortion = INT64_MIN;
						break;
					}
					if (*integerPortion != 0)
						assert(*integerPortion * 10 > 0);
					*integerPortion *= 10;
					exponent--;
				}
			} else if (exponent < 0) {
				if (fraction) {
					result |= CONV_PRECISION_LOSS;
					goto lost_precision;
				}
				while (exponent) {
					if (*integerPortion % 10 != 0) {
						result |= CONV_PRECISION_LOSS;
						goto lost_precision;
					}
					*integerPortion /= 10;
					exponent++;
				}
lost_precision:
				while (exponent++ && *integerPortion > 0)
					*integerPortion /= 10;
			}
		}
	} else {
		*exponentPortion = exponent;
	}

	if (!decimalPortion) {
		if (fraction != 0) {
			result |= CONV_PRECISION_LOSS;
		}
	} else {
		*decimalPortion = fraction;
		*decimalLeadingZeros = fractionFactor;
	}

	return result;

not_a_number:
	return CONV_NOT_A_NUM;

fast_stop:
	if (exponentPortion) *exponentPortion = exponent;
	if (decimalPortion) *decimalPortion = fraction;
	if (decimalLeadingZeros) *decimalLeadingZeros = fractionFactor;
	return result;
}
Пример #24
0
jvalue_ref jdom_parse_file(const char *file, JSchemaInfoRef schemaInfo, JFileOptimizationFlags flags)
{
	CHECK_POINTER_RETURN_NULL(file);
	CHECK_POINTER_RETURN_NULL(schemaInfo);

	int fd;
	off_t fileSize;
	raw_buffer input = { 0 };
	jvalue_ref result;
	char *err_msg;

	fd = open(file, O_RDONLY);
	if (fd == -1) {
		goto errno_parse_failure;
	}

	if (!file_size(fd, &fileSize)) {
		goto errno_parse_failure;
	}

	input.m_len = fileSize;
	if (input.m_len != fileSize) {
		PJ_LOG_ERR("PBNJSON_BIG_FILE", 1, PMLOGKS("FILE", file), "File too big - currently unsupported by this API");
		close(fd);
	}

	if (flags & JFileOptMMap) {
		input.m_str = (char *)mmap(NULL, input.m_len, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0);

		if (input.m_str == NULL || input.m_str == MAP_FAILED) {
			goto errno_parse_failure;
		}
	} else {
		input.m_str = (char *)malloc(input.m_len + 1);
		if (input.m_len != read(fd, (char *)input.m_str, input.m_len)) {
			goto errno_parse_failure;
		}
		((char *)input.m_str)[input.m_len] = 0;
	}

	result = jdom_parse(input, DOMOPT_INPUT_OUTLIVES_WITH_NOCHANGE, schemaInfo);

return_result:
	close(fd);

	if (UNLIKELY(!jis_valid(result))) {
		if (input.m_str) {
			if (flags & JFileOptMMap) {
				munmap((void *)input.m_str, input.m_len);
			} else {
				free((void *)input.m_str);
			}
		}
	} else {
		result->m_backingBuffer = input;
		result->m_backingBufferMMap = flags & JFileOptMMap;
	}

	return result;

errno_parse_failure:
	err_msg = strdup(strerror(errno));
	PJ_LOG_WARN("PBNJSON_PARCE_ERR", 3,
	            PMLOGKS("FILE", file),
	            PMLOGKFV("ERRNO", "%d", errno),
	            PMLOGKS("ERROR", err_msg),
	            "Attempt to parse json document '%s' failed (%d) : %s", file, errno, err_msg);
	free(err_msg);

	result = jinvalid();
	goto return_result;
}