Configuration API Guide - C++
Reference code
Classes used to provide ConfigData
Server class | Description |
---|---|
ConfigService | Class that implements the interface org.alljoyn.Config as a service framework. |
PropertyStore | Interface that supplies the list of properties required for ReadAll() and enables user manipulation of their values via Update(), Delete() and Reset(). |
Classes used to remotely manipulate ConfigData
Client class | Description |
---|---|
ConfigClient | Class that implements the interface org.alljoyn.Config as a client. |
Obtain the Configuration service framework
See the Building Linux section for instructions on compiling the Configuration service framework.
Build an application that uses ConfigServer
The following steps provide the high-level process to build an application that will maintain ConfigData.
- Create the base for the AllJoyn™ application.
- Implement the ProperyStore to produce a ConfigStore.
- Initialize the AboutService in service mode.
- Instantiate a ConfigStore.
- Implement the callbacks required by the Config Server.
- Initialize the ConfigService in server mode, providing it with the ConfigStore and callbacks.
Setting up the AllJoyn framework and About feature
The steps required for this service framework are universal to all applications that use the AllJoyn framework and for any application using one or more AllJoyn service frameworks. Prior to use of the Configuration service framework as a Config Server or Config Client, the About feature must be implemented and the AllJoyn framework set up.
Complete the procedures in the following documents to guide you in this process:
Implementing an App: Config Server
Implementing a Config Server requires creating and registering an instance of the ConfigService class. Any application using Config Server also requires an About Server to facilitate the discovery via Announcements.
NOTE: Verify the BusAttachment has been created, started and
connected before implementing the ConfigService. See the
About API Guide for the code snippets.
Code in this chapter references a variable mBus
(the BusAttachment variable name).
Initialize the AllJoyn framework
See the Building Linux section for instructions to set up the AllJoyn framework.
Create bus attachment
bus->Start();
bus->Connect();
Enable peer security
Config Server uses peer security.
Create a KeyListener class that inherits from ajn::AuthListener. It needs to implement two functions: RequestCredentials and AuthenticationComplete.
class SrpKeyXListener : public ajn::AuthListener {
public:
bool RequestCredentials(const char* authMechanism,
const char* authPeer,
uint16_t authCount, const char* userId,
uint16_t credMask, Credentials& creds);
void AuthenticationComplete(const char* authMechanism, const char* authPeer,
bool success);
};
RequestCredentials()
needs to set the password using Creds
and return true.
creds.SetPassword(Password);
return true;
Instantiate the keylistener class and enable peer security.
SrpKeyXListener* keyListener = new SrpKeyXListener();
bus->EnablePeerSecurity("ALLJOYN_PIN_KEYX ALLJOYN_SRP_KEYX ALLJOYN_ECDHE_PSK", keyListener);
Implement PropertyStore to produce a ConfigStore
The PropertyStore interface is required by the AboutService to store the provisioned values for the About interface data fields. See the About Interface Definition for more information.
The ProperyStore interface is also required by the ConfigService to store and facilitate manipulation of some updateable fields (listed in Config interface data fields). See the [Configuration Interface Definition] for more information.
Config interface data fields
Field name | Required | Type |
---|---|---|
DefaultLanguage |
yes | s |
DeviceName |
yes | s |
An example PropertyStore implementation (ConfigStore) is provided below that specifies the following dictionary of metadata fields:
- Keys are the field names.
- Values are a Map of String to Object entries where the String is the language tag associated with the Object value.
This implementation extends the example AboutStore implementation in the About API Guide and is passed to the AboutService instead of AboutStore.
PropertyStoreImpl::PropertyStoreImpl(const char* factoryConfigFile, const char*
configFile) : m_IsInitialized(false)
{
m_configFileName.assign(configFile);
m_factoryConfigFileName.assign(factoryConfigFile);
}
void PropertyStoreImpl::Initialize()
{
m_IsInitialized = true; m_factoryProperties.clear();
m_factoryProperties.insert(m_Properties.begin(), m_Properties.end());
//m_factoryProperties - overwrite the values that are found in
FactoryConfigService file
UpdateFactorySettings();
}
void PropertyStoreImpl::FactoryReset()
{
std::ifstream factoryConfigFile(m_factoryConfigFileName.c_str(), std::ios::binary);
std::ofstream configFile(m_configFileName.c_str(), std::ios::binary);
if (factoryConfigFile && configFile) {
configFile << factoryConfigFile.rdbuf();
configFile.close();
factoryConfigFile.close();
} else {
std::cout << "Factory reset failed" << std::endl;
}
m_Properties.clear();
m_Properties.insert(m_factoryProperties.begin(), m_factoryProperties.end());
}
const qcc::String& PropertyStoreImpl::GetConfigFileName()
{
return m_configFileName;
}
PropertyStoreImpl::~PropertyStoreImpl()
{
}
QStatus PropertyStoreImpl::ReadAll(const char* languageTag, Filter filter, ajn::MsgArg& all)
{
if (!m_IsInitialized) {
return ER_FAIL;
}
if (filter == ANNOUNCE || filter == READ) {
return AboutPropertyStoreImpl::ReadAll(languageTag, filter, all);
}
if (filter != WRITE) {
return ER_FAIL;
}
QStatus status = ER_OK;
if (languageTag != NULL && languageTag[0] != 0) { // check that the language is in the supported languages;
CHECK_RETURN(isLanguageSupported(languageTag))
} else {
PropertyMap::iterator it = m_Properties.find(DEFAULT_LANG);
if (it == m_Properties.end()) {
return ER_LANGUAGE_NOT_SUPPORTED;
}
CHECK_RETURN(it->second.getPropertyValue().Get("s", &languageTag))
}
MsgArg* argsWriteData = new MsgArg[m_Properties.size()];
uint32_t writeArgCount = 0;
do {
for (PropertyMap::const_iterator it = m_Properties.begin(); it !=
m_Properties.end(); ++it) {
const PropertyStoreProperty& property = it->second;
if (!property.getIsWritable()) {
continue;
}
// check that it is from the defaultLanguage or empty. if (!(property.getLanguage().empty() ||
property.getLanguage().compare(languageTag) == 0)) {
continue;
}
CHECK(argsWriteData[writeArgCount].Set("{sv}", property.getPropertyName().c_str(),
new
MsgArg(property.getPropertyValue())))
argsWriteData[writeArgCount].SetOwnershipFlags(MsgArg::OwnsArgs,true;
writeArgCount++;
}
CHECK(all.Set("a{sv}", writeArgCount, argsWriteData))
all.SetOwnershipFlags(MsgArg::OwnsArgs, true);
} while (0);
if (status != ER_OK) {
delete[] argsWriteData;
}
return status;
}
QStatus PropertyStoreImpl::Update(const char* name, const char* languageTag, const ajn::MsgArg* value)
{
if (!m_IsInitialized) {
return ER_FAIL;
}
PropertyStoreKey propertyKey = getPropertyStoreKeyFromName(name);
if (propertyKey >= NUMBER_OF_KEYS) {
return ER_FEATURE_NOT_AVAILABLE;
}
// check the languageTag
// case languageTag == NULL: is not a valid value for the languageTag
// case languageTag == "": use the default language
// case languageTag == string: check value, must be one of the supported languages
QStatus status = ER_OK;
if (languageTag == NULL) {
return ER_INVALID_VALUE;
} else if (languageTag[0] == 0) {
PropertyMap::iterator it = m_Properties.find(DEFAULT_LANG);
if (it == m_Properties.end()) {
return ER_LANGUAGE_NOT_SUPPORTED;
}
status = it->second.getPropertyValue().Get("s", &languageTag);
} else {
status = isLanguageSupported(languageTag);
if (status != ER_OK) {
return status;
}
}
// Special case DEFAULT_LANG is not associated with a language in the PropertyMap and
// its only valid languageTag = NULL
// By setting it here, we to let the user follow the same language rules as any other property
if (propertyKey == DEFAULT_LANG) {
languageTag = NULL;
}
//validate that the value is acceptable
qcc::String languageString = languageTag ? languageTag : ""; status = validateValue(propertyKey, *value, languageString); if (status != ER_OK) {
std::cout << "New Value failed validation. Will not update" << std::endl;
return status;
}
PropertyStoreProperty* temp = NULL;
std::pair<PropertyMap::iterator, PropertyMap::iterator> propertiesIter =
m_Properties.equal_range(propertyKey);
for (PropertyMap::iterator it = propertiesIter.first; it !=
propertiesIter.second; it++) {
const PropertyStoreProperty& property = it->second;
if (property.getIsWritable()) {
if ((languageTag == NULL && property.getLanguage().empty()) || (languageTag != NULL && property.getLanguage().compare(languageTag)
== 0)) {
temp = new PropertyStoreProperty(property.getPropertyName(),
*value, property.getIsPublic(),
property.getIsAnnouncable());
if (languageTag) {
property.getIsWritable(),
temp->setLanguage(languageTag);
}
m_Properties.erase(it);
break;
}
}
}
if (temp == NULL) {
return ER_INVALID_VALUE;
}
m_Properties.insert(PropertyPair(propertyKey, *temp));
if (persistUpdate(temp->getPropertyName().c_str(), value->v_string.str, languageTag)) {
AboutService* aboutService = AboutServiceApi::getInstance();
if (aboutService) {
aboutService->Announce();
std::cout << "Calling Announce after UpdateConfiguration" << std::endl;
}
delete temp;
return ER_OK;
} else {
delete temp;
return ER_INVALID_VALUE;
}
}
QStatus PropertyStoreImpl::Delete(const char* name, const char* languageTag)
{
if (!m_IsInitialized) {
return ER_FAIL;
}
PropertyStoreKey propertyKey = getPropertyStoreKeyFromName(name);
if (propertyKey >= NUMBER_OF_KEYS) {
return ER_FEATURE_NOT_AVAILABLE;
}
QStatus status = ER_OK;
if (languageTag == NULL) {
return ER_INVALID_VALUE;
} else if (languageTag[0] == 0) {
PropertyMap::iterator it = m_Properties.find(DEFAULT_LANG);
if (it == m_Properties.end()) {
return ER_LANGUAGE_NOT_SUPPORTED;
}
status = it->second.getPropertyValue().Get("s", &languageTag);
} else {
status = isLanguageSupported(languageTag);
if (status != ER_OK) {
return status;
}
}
if (propertyKey == DEFAULT_LANG) {
languageTag = NULL;
}
bool deleted = false;
std::pair<PropertyMap::iterator, PropertyMap::iterator> propertiesIter =
m_Properties.equal_range(propertyKey);
for (PropertyMap::iterator it = propertiesIter.first; it !=
propertiesIter.second; it++) {
const PropertyStoreProperty& property = it->second;
if (property.getIsWritable()) {
if ((languageTag == NULL && property.getLanguage().empty()) || (languageTag != NULL && property.getLanguage().compare(languageTag)
== 0)) {
m_Properties.erase(it);
// insert from backup. deleted = true;
break;
}
}
}
if (!deleted) {
if (languageTag != NULL) {
return ER_LANGUAGE_NOT_SUPPORTED;
} else {
return ER_INVALID_VALUE;
}
}
propertiesIter = m_factoryProperties.equal_range(propertyKey);
for (PropertyMap::iterator it = propertiesIter.first; it !=
propertiesIter.second; it++) {
const PropertyStoreProperty& property = it->second;
if (property.getIsWritable()) {
if ((languageTag == NULL && property.getLanguage().empty()) || (languageTag != NULL && property.getLanguage().compare(languageTag)
== 0)) {
m_Properties.insert(PropertyPair(it->first, it->second));
char* value;
it->second.getPropertyValue().Get("s", &value);
if (persistUpdate(it->second.getPropertyName().c_str(), value,
languageTag)) {
AboutService* aboutService = AboutServiceApi::getInstance();
if (aboutService) {
aboutService->Announce();
std::cout << "Calling Announce after ResetConfiguration"
<< std::endl;
}
return ER_OK;
}
}
}
}
return ER_INVALID_VALUE;
}
bool PropertyStoreImpl::persistUpdate(const char* key, const char* value, const char* languageTag)
{
std::map<std::string, std::string> data;
std::string skey(key);
if (languageTag && languageTag[0]) { skey.append("."); skey.append(languageTag);
}
data[skey] = value;
return IniParser::UpdateFile(m_configFileName.c_str(), data);
}
PropertyStoreKey PropertyStoreImpl::getPropertyStoreKeyFromName(qcc::String const&
propertyStoreName)
{
for (int indx = 0; indx < NUMBER_OF_KEYS; indx++) {
if (PropertyStoreName[indx].compare(propertyStoreName) == 0) {
return (PropertyStoreKey)indx;
}
}
return NUMBER_OF_KEYS;
}
bool PropertyStoreImpl::FillDeviceNames()
{
std::map<std::string, std::string> data;
if (!IniParser::ParseFile(m_factoryConfigFileName.c_str(), data)) {
std::cerr << "Could not parse configFile" << std::endl;
return false;
}
typedef std::map<std::string, std::string>::iterator it_data;
for (it_data iterator = data.begin(); iterator != data.end(); iterator++) {
if
(iterator->first.find(AboutPropertyStoreImpl::getPropertyStoreName(DEVICE_NAME).c_str())
== 0) {
size_t lastDotLocation = iterator->first.find(".");
if ((lastDotLocation == std::string::npos) || (lastDotLocation + 1
>= iterator->first.length())) {
continue;
}
std::string language = iterator->first.substr(lastDotLocation + 1);
std::string value = iterator->second;
UpdateFactoryProperty(DEVICE_NAME, language.c_str(), MsgArg("s", value.c_str()));
}
}
return true;
}
bool PropertyStoreImpl::UpdateFactorySettings()
{
std::map<std::string, std::string> data;
if (!IniParser::ParseFile(m_factoryConfigFileName.c_str(), data)) {
std::cerr << "Could not parse configFile" << std::endl;
return false;
}
std::map<std::string, std::string>::iterator iter;
iter =
data.find(AboutPropertyStoreImpl::getPropertyStoreName(DEVICE_ID).c_str());
if (iter != data.end()) {
qcc::String deviceId = iter->second.c_str(); UpdateFactoryProperty(DEVICE_ID, NULL, MsgArg("s", deviceId.c_str()));
}
if (!FillDeviceNames()) {
return false;
}
iter = data.find(AboutPropertyStoreImpl::getPropertyStoreName(APP_ID).c_str());
if (iter != data.end()) {
qcc::String appGUID = iter->second.c_str();
UpdateFactoryProperty(APP_ID, NULL, MsgArg("s", appGUID.c_str()));
}
iter =
data.find(AboutPropertyStoreImpl::getPropertyStoreName(APP_NAME).c_str());
if (iter != data.end()) {
qcc::String appName = iter->second.c_str(); UpdateFactoryProperty(APP_NAME, NULL, MsgArg("s", appName.c_str()));
}
iter =
data.find(AboutPropertyStoreImpl::getPropertyStoreName(DEFAULT_LANG).c_str());
if (iter != data.end()) {
qcc::String defaultLanguage = iter->second.c_str(); UpdateFactoryProperty(DEFAULT_LANG, NULL, MsgArg("s",
defaultLanguage.c_str()));
}
return true;
}
void PropertyStoreImpl::UpdateFactoryProperty(PropertyStoreKey propertyKey, const char* languageTag,
const ajn::MsgArg& value)
{
PropertyStoreProperty* temp = NULL;
std::pair<PropertyMap::iterator, PropertyMap::iterator> propertiesIter =
m_factoryProperties.equal_range(propertyKey);
for (PropertyMap::iterator it = propertiesIter.first; it !=
propertiesIter.second; it++) {
const PropertyStoreProperty& property = it->second;
if ((languageTag == NULL && property.getLanguage().empty()) || (languageTag != NULL && property.getLanguage().compare(languageTag)
== 0)) {
temp = new PropertyStoreProperty(property.getPropertyName(), value,
property.getIsPublic(),
property.getIsWritable(),
property.getIsAnnouncable());
if (languageTag) {
temp->setLanguage(languageTag);
}
m_factoryProperties.erase(it);
break;
}
}
if (temp == NULL) {
return;
}
m_factoryProperties.insert(PropertyPair(propertyKey, *temp));
delete temp;
}
Instantiate a ConfigStore
propertyStore = new PropertyStoreImpl(FACTORYCONFIGFILENAME, CONFIGFILENAME);
propertyStore->setDeviceName(deviceName);
propertyStore->setAppId(appIdHex);
propertyStore->setAppName(appName);
propertyStore->setDefaultLang(defaultLanguage);
propertyStore->setModelNumber("Wxfy388i");
propertyStore->setDateOfManufacture("10/1/2199");
propertyStore->setSoftwareVersion("12.20.44 build 44454");
propertyStore->setAjSoftwareVersion(ajn::GetVersion());
propertyStore->setHardwareVersion("355.499. b");
std::vector<qcc::String> languages(3);
languages.push_back("en");
languages.push_back("sp");
languages.push_back("fr");
propertyStore->setSupportedLangs(languages);
DeviceNamesType::const_iterator iter = deviceNames.find(languages[0]);
if (iter != deviceNames.end()) {
CHECK_RETURN(propertyStore->setDeviceName(iter->second.c_str(), languages[0]));
} else {
CHECK_RETURN(propertyStore->setDeviceName("My device name", "en"));
}
iter = deviceNames.find(languages[1]);
if (iter != deviceNames.end()) {
CHECK_RETURN(propertyStore->setDeviceName(iter->second.c_str(), languages[1]));
} else {
CHECK_RETURN(propertyStore->setDeviceName("Mi nombre de dispositivo",
"sp"));
}
iter = deviceNames.find(languages[2]);
if (iter != deviceNames.end()) {
CHECK_RETURN(propertyStore->setDeviceName(iter->second.c_str(), languages[2]));
} else {
CHECK_RETURN(propertyStore->setDeviceName("Mon nom de l'appareil", "fr"));
}
propertyStore->setDescription("This is an AllJoyn application", "en");
propertyStore->setDescription("Esta es una AllJoyn aplicacion", "sp");
propertyStore->setDescription("C'est une Alljoyn application", "fr");
propertyStore->setManufacturer("Company", "en");
propertyStore->setManufacturer("Empresa", "sp");
propertyStore->setManufacturer("Entreprise", "fr");
propertyStore->setSupportUrl("http://www.allseenalliance.org");
propertyStore->Initialize();
Implement a BusListener and SessionPortListener
In order to bind a SessionPort and accept sessions, a new class must be created that inherits from the AllJoyn BusListener and SessionPortListener classes.
The class must contain the following function:
bool AcceptSessionJoiner(SessionPort sessionPort, const char* joiner, const
SessionOpts& opts)
The AcceptSessionJoiner function will be called any time a joinsession request is received; the Listener class needs to dictate whether the joinsession request should be accepted or rejected by returning true or false, respectively. These considerations are application-specific and can include any of the following:
- The SessionPort the request was made on
- Specific SessionOpts limitations
- The number of sessions already joined
Here is an example of a full class declaration for the listener class.
class CommonBusListener : public ajn::BusListener, public ajn::SessionPortListener {
public:
CommonBusListener();
~CommonBusListener();
bool AcceptSessionJoiner(ajn::SessionPort sessionPort,
const char* joiner, const ajn::SessionOpts& opts);
void setSessionPort(ajn::SessionPort sessionPort);
ajn::SessionPort getSessionPort();
private:
ajn::SessionPort m_SessionPort;
};
Initialize the AboutService in server mode
busListener = new CommonBusListener();
AboutServiceApi::Init(*bus, *propertyStore);
AboutServiceApi* aboutService = AboutServiceApi::getInstance();
busListener->setSessionPort(port);
bus->RegisterBusListener(*busListener);
TransportMask transportMask = TRANSPORT_ANY;
SessionPort sp = port;
SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, false,
SessionOpts::PROXIMITY_ANY, transportMask);
bus->BindSessionPort(sp, opts, *busListener);
aboutService->Register(port);
bus->RegisterBusObject(*aboutService);
For more information about the About feature, see the About API Guide.
Implement the callbacks required by the Config Server
ConfigServiceListenerImpl::ConfigServiceListenerImpl(PropertyStoreImpl& store, BusAttachment& bus) :
ConfigService::Listener(), m_PropertyStore(&store), m_Bus(&bus)
{
}
QStatus ConfigServiceListenerImpl::Restart()
{
printf("Restart has been called !!!\n");
return ER_OK;
}
QStatus ConfigServiceListenerImpl::FactoryReset()
{
QStatus status = ER_OK;
printf("FactoryReset has been called!!!\n"); m_PropertyStore->FactoryReset(); printf("Clearing Key Store\n");
m_Bus->ClearKeyStore();
AboutServiceApi* aboutService = AboutServiceApi::getInstance();
if (aboutService) {
status = aboutService->Announce();
printf("Announce for %s =%d\n", m_Bus->GetUniqueName().c_str(), status);
}
return status;
}
QStatus ConfigServiceListenerImpl::SetPassphrase(const char* daemonRealm, size_t passcodeSize, const char* passcode)
{
qcc::String passCodeString(passcode, passcodeSize);
printf("SetPassphrase has been called daemonRealm=%s passcode=%s passcodeLength=%lu\n", daemonRealm,
passCodeString.c_str(), passcodeSize); PersistPassword(daemonRealm, passCodeString.c_str());
printf("Clearing Key Store\n");
m_Bus->ClearKeyStore();
return ER_OK;
}
ConfigServiceListenerImpl::~ConfigServiceListenerImpl()
{
}
void ConfigServiceListenerImpl::PersistPassword(const char* daemonRealm, const char* passcode)
{
std::map<std::string, std::string> data;
data["daemonrealm"] = daemonRealm;
data["passcode"] = passcode;
IniParser::UpdateFile(m_PropertyStore->GetConfigFile().c_str(), data);
}
Initialize the ConfigService in server mode, providing it with the ConfigStore and callbacks
configServiceListenerImpl = new ConfigServiceListenerImpl(*propertyStoreImpl,
*msgBus);
configService = new ConfigService(*msgBus, *propertyStoreImpl,
*configServiceListenerImpl);
std::vector<qcc::String> interfaces;
interfaces.push_back("org.alljoyn.Config");
aboutService->AddObjectDescription("/Config", interfaces);
configService->Register();
msgBus->RegisterBusObject(*configService);
Advertise name and announce
AdvertiseName(SERVICE_TRANSPORT_TYPE);
aboutService->Announce();
Unregister and delete ConfigService and BusAttachment
When your process is done with the ConfigService delete variables used:
if (configService) {
delete configService;
configService = NULL;
}
if (configServiceListenerImpl) {
delete configServiceListenerImpl;
configServiceListenerImpl = NULL;
}
if (keyListener) {
delete keyListener;
keyListener = NULL;
}
if (propertyStoreImpl) {
delete propertyStoreImpl;
propertyStoreImpl = NULL;
}
delete msgBus;
msgBus = NULL;
Implementing an App: Config Client
To implement an application to receive and modify ConfigData, use the ConfigClient class. The AboutClient class must be used so that your application is notified when applications with About Server and possibly Config Server instances can send announcements.
NOTE: Verify the BusAttachment has been created, started and
connected before implementing a Config Client. See the About
API Guide for the code snippets.
Code in this chapter references a variable mBus
(the BusAttachment variable name).
Initialize the AllJoyn framework
See the Building Linux section for instructions to set up the AllJoyn framework.
Create bus attachment
busAttachment ->Start();
busAttachment ->Connect();
Enable peer security
Config Client uses peer security.
Create a KeyListener class that inherits from ajn::AuthListener. It needs to implement two functions: RequestCredentials and AuthenticationComplete.
class SrpKeyXListener : public ajn::AuthListener {
public:
bool RequestCredentials(const char* authMechanism, const char* authPeer, uint16_t authCount, const char* userId,
uint16_t credMask, Credentials& creds);
void AuthenticationComplete(const char* authMechanism, const char*
authPeer, bool success);
};
RequestCredentials needs to set the password using Creds and return true.
creds.SetPassword(Password);
return true;
Instantiate the keylistener class and enable peer security.
SrpKeyXListener* keyListener = new SrpKeyXListener();
bus->EnablePeerSecurity("ALLJOYN_PIN_KEYX ALLJOYN_SRP_KEYX ALLJOYN_ECDHE_PSK", keyListener);
Initialize the AboutService in client mode
Complete the following steps.
- Implement the announce handler.
- Implement the announce method.
- Register the announce handler, if there is a Config interface.
- Join a session.
For more information about the About feature, see the About API Guide.
Create the ConfigService client object
configClient = new ConfigClient(*busAttachment);
Request the ConfigData
The Configurations data structure is filled by the GetConfigurations()
method call. Configurations can be iterated through to determine
the contents. The content definition is found in the Configuration
Interface Definition.
ConfigClient::Configurations configurations;
if ((status = configClient->GetConfigurations(busname.c_str(),
"en", configurations, id)) == ER_OK) {
for (ConfigClient::Configurations::iterator it = configurations.begin();
it != configurations.end(); ++it) { qcc::String key = it->first; ajn::MsgArg value = it->second;
if (value.typeId == ALLJOYN_STRING) {
printf("Key name=%s value=%s\n", key.c_str(), value.v_string.str);
} else if (value.typeId == ALLJOYN_ARRAY &&
value.Signature().compare("as") == 0) {
printf("Key name=%s values: ", key.c_str());
const MsgArg*stringArray;
size_t fieldListNumElements;
status = value.Get("as", &fieldListNumElements, &stringArray);
for (unsigned int i = 0; i < fieldListNumElements; i++) {
char* tempString; stringArray[i].Get("s", &tempString);
printf("%s ", tempString);
}
printf("\n");
}
}
Update the ConfigData
The received data can be updated through the ConfigClient
using the UpdateConfigurations()
method call.
configurations.insert(std::pair<qcc::String, ajn::MsgArg>("DeviceName", MsgArg("s", "New Device Name")));
configClient->UpdateConfigurations(busname.c_str(), NULL, configurations, id);
Get the interface version
The peer device/application configuration can query for the interface version.
int version;
configClient->GetVersion(busname.c_str(), version, id);
Reset the ConfigData
The ConfigData can be reset to default through the ConfigClient
using the ResetConfigurations()
method call.
std::vector<qcc::String> configNames;
configNames.push_back("DeviceName");
configClient->ResetConfigurations(busname.c_str(), "en", configNames, id);
Reset the peer device application to factory defaults
The peer device/application configuration can be reset to
factory defaults through the ConfigClient using the
FactoryReset()
method call.
NOTE: This is a no-reply call, so its success cannot be determined directly.
configClient->FactoryReset(busname.c_str(), id);
Restart the peer
The peer application can be restarted though the ConfigClient using the Restart() method call.
NOTE: This is a no-reply call, so its success cannot be determined directly.
configClient->Restart(busname.c_str(), id);
Setting a passcode on the peer
The peer application can be set to have a different passcode
though the ConfigClient using the SetPasscode()
method call.
This revokes the current encryption keys and regenerates new
ones based on the new shared secret, namely the passcode.
NOTE: The realm name is currently ignored.
configClient->SetPasscode(busname.c_str(), "MyDeamonRealm", 8, (const uint8_t*) NEW_PASSCODE, id);
srpKeyXListener->setPassCode(NEW_PASSCODE);
qcc::String guid;
busAttachment->GetPeerGUID(busname.c_str(), guid);
busAttachment->ClearKeys(guid);
Delete variables and unregister listeners
Once you are done using the Config Service, Configuration service framework, and the AllJoyn framework, free the variables used in the application.
if (configClient) {
delete configClient;
configClient = NULL;
}
busAttachment->Stop();
delete busAttachment;