Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  *  Import and export general routing data using a XML file.
     19  */
     20 
     21 #include <android-base/stringprintf.h>
     22 #include <base/logging.h>
     23 #include <errno.h>
     24 #include <sys/stat.h>
     25 
     26 /* NOTE:
     27  * This has to be included AFTER the android-base includes since
     28  * android-base/macros.h defines ATTRIBUTE_UNUSED, also used in the
     29  * tiny XML library.
     30  */
     31 #include "RouteDataSet.h"
     32 
     33 #include "libxml/xmlmemory.h"
     34 
     35 using android::base::StringPrintf;
     36 
     37 extern std::string nfc_storage_path;
     38 extern bool nfc_debug_enabled;
     39 
     40 /*******************************************************************************
     41 **
     42 ** Function:        AidBuffer
     43 **
     44 ** Description:     Parse a string of hex numbers.  Store result in an array of
     45 **                  bytes.
     46 **                  aid: string of hex numbers.
     47 **
     48 ** Returns:         None.
     49 **
     50 *******************************************************************************/
     51 AidBuffer::AidBuffer(std::string& aid) : mBuffer(NULL), mBufferLen(0) {
     52   unsigned int num = 0;
     53   const char delimiter = ':';
     54   std::string::size_type pos1 = 0;
     55   std::string::size_type pos2 = aid.find_first_of(delimiter);
     56 
     57   // parse the AID string; each hex number is separated by a colon;
     58   mBuffer = new uint8_t[aid.length()];
     59   while (true) {
     60     num = 0;
     61     if (pos2 == std::string::npos) {
     62       sscanf(aid.substr(pos1).c_str(), "%x", &num);
     63       mBuffer[mBufferLen] = (uint8_t)num;
     64       mBufferLen++;
     65       break;
     66     } else {
     67       sscanf(aid.substr(pos1, pos2 - pos1 + 1).c_str(), "%x", &num);
     68       mBuffer[mBufferLen] = (uint8_t)num;
     69       mBufferLen++;
     70       pos1 = pos2 + 1;
     71       pos2 = aid.find_first_of(delimiter, pos1);
     72     }
     73   }
     74 }
     75 
     76 /*******************************************************************************
     77 **
     78 ** Function:        ~AidBuffer
     79 **
     80 ** Description:     Release all resources.
     81 **
     82 ** Returns:         None.
     83 **
     84 *******************************************************************************/
     85 AidBuffer::~AidBuffer() { delete[] mBuffer; }
     86 
     87 /*******************************************************************************/
     88 /*******************************************************************************/
     89 
     90 const char* RouteDataSet::sConfigFile = "/param/route.xml";
     91 
     92 /*******************************************************************************
     93 **
     94 ** Function:        ~RouteDataSet
     95 **
     96 ** Description:     Release all resources.
     97 **
     98 ** Returns:         None.
     99 **
    100 *******************************************************************************/
    101 RouteDataSet::~RouteDataSet() { deleteDatabase(); }
    102 
    103 /*******************************************************************************
    104 **
    105 ** Function:        initialize
    106 **
    107 ** Description:     Initialize resources.
    108 **
    109 ** Returns:         True if ok.
    110 **
    111 *******************************************************************************/
    112 bool RouteDataSet::initialize() {
    113   DLOG_IF(INFO, nfc_debug_enabled)
    114       << StringPrintf("%s: enter", "RouteDataSet::initialize");
    115   // check that the libxml2 version in use is compatible
    116   // with the version the software has been compiled with
    117   LIBXML_TEST_VERSION
    118   DLOG_IF(INFO, nfc_debug_enabled)
    119       << StringPrintf("%s: exit; return=true", "RouteDataSet::initialize");
    120   return true;
    121 }
    122 
    123 /*******************************************************************************
    124 **
    125 ** Function:        deleteDatabase
    126 **
    127 ** Description:     Delete all routes stored in all databases.
    128 **
    129 ** Returns:         None.
    130 **
    131 *******************************************************************************/
    132 void RouteDataSet::deleteDatabase() {
    133   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
    134       "%s: default db size=%zu; sec elem db size=%zu",
    135       "RouteDataSet::deleteDatabase", mDefaultRouteDatabase.size(),
    136       mSecElemRouteDatabase.size());
    137   Database::iterator it;
    138 
    139   for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end();
    140        it++)
    141     delete (*it);
    142   mDefaultRouteDatabase.clear();
    143 
    144   for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end();
    145        it++)
    146     delete (*it);
    147   mSecElemRouteDatabase.clear();
    148 }
    149 
    150 /*******************************************************************************
    151 **
    152 ** Function:        import
    153 **
    154 ** Description:     Import data from an XML file.  Fill the databases.
    155 **
    156 ** Returns:         True if ok.
    157 **
    158 *******************************************************************************/
    159 bool RouteDataSet::import() {
    160   static const char fn[] = "RouteDataSet::import";
    161   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", fn);
    162   bool retval = false;
    163   xmlDocPtr doc;
    164   xmlNodePtr node1;
    165   std::string strFilename(nfc_storage_path);
    166   strFilename += sConfigFile;
    167 
    168   deleteDatabase();
    169 
    170   doc = xmlParseFile(strFilename.c_str());
    171   if (doc == NULL) {
    172     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: fail parse", fn);
    173     goto TheEnd;
    174   }
    175 
    176   node1 = xmlDocGetRootElement(doc);
    177   if (node1 == NULL) {
    178     LOG(ERROR) << StringPrintf("%s: fail root element", fn);
    179     goto TheEnd;
    180   }
    181   DLOG_IF(INFO, nfc_debug_enabled)
    182       << StringPrintf("%s: root=%s", fn, node1->name);
    183 
    184   node1 = node1->xmlChildrenNode;
    185   while (node1)  // loop through all elements in <Routes ...
    186   {
    187     if (xmlStrcmp(node1->name, (const xmlChar*)"Route") == 0) {
    188       xmlChar* value = xmlGetProp(node1, (const xmlChar*)"Type");
    189       if (value &&
    190           (xmlStrcmp(value, (const xmlChar*)"SecElemSelectedRoutes") == 0)) {
    191         DLOG_IF(INFO, nfc_debug_enabled)
    192             << StringPrintf("%s: found SecElemSelectedRoutes", fn);
    193         xmlNodePtr node2 = node1->xmlChildrenNode;
    194         while (node2)  // loop all elements in <Route
    195                        // Type="SecElemSelectedRoutes" ...
    196         {
    197           if (xmlStrcmp(node2->name, (const xmlChar*)"Proto") == 0)
    198             importProtocolRoute(node2, mSecElemRouteDatabase);
    199           else if (xmlStrcmp(node2->name, (const xmlChar*)"Tech") == 0)
    200             importTechnologyRoute(node2, mSecElemRouteDatabase);
    201           node2 = node2->next;
    202         }  // loop all elements in <Route Type="SecElemSelectedRoutes" ...
    203       } else if (value &&
    204                  (xmlStrcmp(value, (const xmlChar*)"DefaultRoutes") == 0)) {
    205         DLOG_IF(INFO, nfc_debug_enabled)
    206             << StringPrintf("%s: found DefaultRoutes", fn);
    207         xmlNodePtr node2 = node1->xmlChildrenNode;
    208         while (node2)  // loop all elements in <Route Type="DefaultRoutes" ...
    209         {
    210           if (xmlStrcmp(node2->name, (const xmlChar*)"Proto") == 0)
    211             importProtocolRoute(node2, mDefaultRouteDatabase);
    212           else if (xmlStrcmp(node2->name, (const xmlChar*)"Tech") == 0)
    213             importTechnologyRoute(node2, mDefaultRouteDatabase);
    214           node2 = node2->next;
    215         }  // loop all elements in <Route Type="DefaultRoutes" ...
    216       }
    217       if (value) xmlFree(value);
    218     }  // check <Route ...
    219     node1 = node1->next;
    220   }  // loop through all elements in <Routes ...
    221   retval = true;
    222 
    223 TheEnd:
    224   xmlFreeDoc(doc);
    225   xmlCleanupParser();
    226   DLOG_IF(INFO, nfc_debug_enabled)
    227       << StringPrintf("%s: exit; return=%u", fn, retval);
    228   return retval;
    229 }
    230 
    231 /*******************************************************************************
    232 **
    233 ** Function:        saveToFile
    234 **
    235 ** Description:     Save XML data from a string into a file.
    236 **                  routesXml: XML that represents routes.
    237 **
    238 ** Returns:         True if ok.
    239 **
    240 *******************************************************************************/
    241 bool RouteDataSet::saveToFile(const char* routesXml) {
    242   static const char fn[] = "RouteDataSet::saveToFile";
    243   FILE* fh = NULL;
    244   size_t actualWritten = 0;
    245   bool retval = false;
    246   std::string filename(nfc_storage_path);
    247   int stat = 0;
    248 
    249   filename.append(sConfigFile);
    250   fh = fopen(filename.c_str(), "w");
    251   if (fh == NULL) {
    252     LOG(ERROR) << StringPrintf("%s: fail to open file", fn);
    253     return false;
    254   }
    255 
    256   actualWritten = fwrite(routesXml, sizeof(char), strlen(routesXml), fh);
    257   retval = actualWritten == strlen(routesXml);
    258   fclose(fh);
    259   DLOG_IF(INFO, nfc_debug_enabled)
    260       << StringPrintf("%s: wrote %zu bytes", fn, actualWritten);
    261   if (retval == false) LOG(ERROR) << StringPrintf("%s: error during write", fn);
    262 
    263   // set file permission to
    264   // owner read, write; group read; other read
    265   stat = chmod(filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    266   if (stat == -1) LOG(ERROR) << StringPrintf("%s: error during chmod", fn);
    267   return retval;
    268 }
    269 
    270 /*******************************************************************************
    271 **
    272 ** Function:        loadFromFile
    273 **
    274 ** Description:     Load XML data from file into a string.
    275 **                  routesXml: string to receive XML data.
    276 **
    277 ** Returns:         True if ok.
    278 **
    279 *******************************************************************************/
    280 bool RouteDataSet::loadFromFile(std::string& routesXml) {
    281   FILE* fh = NULL;
    282   size_t actual = 0;
    283   char buffer[1024];
    284   std::string filename(nfc_storage_path);
    285 
    286   filename.append(sConfigFile);
    287   fh = fopen(filename.c_str(), "r");
    288   if (fh == NULL) {
    289     DLOG_IF(INFO, nfc_debug_enabled)
    290         << StringPrintf("%s: fail to open file", "RouteDataSet::loadFromFile");
    291     return false;
    292   }
    293 
    294   while (true) {
    295     actual = fread(buffer, sizeof(char), sizeof(buffer), fh);
    296     if (actual == 0) break;
    297     routesXml.append(buffer, actual);
    298   }
    299   fclose(fh);
    300   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
    301       "%s: read %zu bytes", "RouteDataSet::loadFromFile", routesXml.length());
    302   return true;
    303 }
    304 
    305 /*******************************************************************************
    306 **
    307 ** Function:        importProtocolRoute
    308 **
    309 ** Description:     Parse data for protocol routes.
    310 **                  element: XML node for one protocol route.
    311 **                  database: store data in this database.
    312 **
    313 ** Returns:         None.
    314 **
    315 *******************************************************************************/
    316 void RouteDataSet::importProtocolRoute(xmlNodePtr& element,
    317                                        Database& database) {
    318   const xmlChar* id = (const xmlChar*)"Id";
    319   const xmlChar* secElem = (const xmlChar*)"SecElem";
    320   const xmlChar* trueString = (const xmlChar*)"true";
    321   const xmlChar* switchOn = (const xmlChar*)"SwitchOn";
    322   const xmlChar* switchOff = (const xmlChar*)"SwitchOff";
    323   const xmlChar* batteryOff = (const xmlChar*)"BatteryOff";
    324   RouteDataForProtocol* data = new RouteDataForProtocol;
    325   xmlChar* value = NULL;
    326 
    327   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
    328       "%s: element=%s", "RouteDataSet::importProtocolRoute", element->name);
    329   value = xmlGetProp(element, id);
    330   if (value) {
    331     if (xmlStrcmp(value, (const xmlChar*)"T1T") == 0)
    332       data->mProtocol = NFA_PROTOCOL_MASK_T1T;
    333     else if (xmlStrcmp(value, (const xmlChar*)"T2T") == 0)
    334       data->mProtocol = NFA_PROTOCOL_MASK_T2T;
    335     else if (xmlStrcmp(value, (const xmlChar*)"T3T") == 0)
    336       data->mProtocol = NFA_PROTOCOL_MASK_T3T;
    337     else if (xmlStrcmp(value, (const xmlChar*)"IsoDep") == 0)
    338       data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP;
    339     xmlFree(value);
    340     DLOG_IF(INFO, nfc_debug_enabled)
    341         << StringPrintf("%s: %s=0x%X", "RouteDataSet::importProtocolRoute", id,
    342                         data->mProtocol);
    343   }
    344 
    345   value = xmlGetProp(element, secElem);
    346   if (value) {
    347     data->mNfaEeHandle = strtol((char*)value, NULL, 16);
    348     xmlFree(value);
    349     data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
    350     DLOG_IF(INFO, nfc_debug_enabled)
    351         << StringPrintf("%s: %s=0x%X", "RouteDataSet::importProtocolRoute",
    352                         secElem, data->mNfaEeHandle);
    353   }
    354 
    355   value = xmlGetProp(element, switchOn);
    356   if (value) {
    357     data->mSwitchOn = (xmlStrcmp(value, trueString) == 0);
    358     xmlFree(value);
    359   }
    360 
    361   value = xmlGetProp(element, switchOff);
    362   if (value) {
    363     data->mSwitchOff = (xmlStrcmp(value, trueString) == 0);
    364     xmlFree(value);
    365   }
    366 
    367   value = xmlGetProp(element, batteryOff);
    368   if (value) {
    369     data->mBatteryOff = (xmlStrcmp(value, trueString) == 0);
    370     xmlFree(value);
    371   }
    372   database.push_back(data);
    373 }
    374 
    375 /*******************************************************************************
    376 **
    377 ** Function:        importTechnologyRoute
    378 **
    379 ** Description:     Parse data for technology routes.
    380 **                  element: XML node for one technology route.
    381 **                  database: store data in this database.
    382 **
    383 ** Returns:         None.
    384 **
    385 *******************************************************************************/
    386 void RouteDataSet::importTechnologyRoute(xmlNodePtr& element,
    387                                          Database& database) {
    388   const xmlChar* id = (const xmlChar*)"Id";
    389   const xmlChar* secElem = (const xmlChar*)"SecElem";
    390   const xmlChar* trueString = (const xmlChar*)"true";
    391   const xmlChar* switchOn = (const xmlChar*)"SwitchOn";
    392   const xmlChar* switchOff = (const xmlChar*)"SwitchOff";
    393   const xmlChar* batteryOff = (const xmlChar*)"BatteryOff";
    394   RouteDataForTechnology* data = new RouteDataForTechnology;
    395   xmlChar* value = NULL;
    396 
    397   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
    398       "%s: element=%s", "RouteDataSet::importTechnologyRoute", element->name);
    399   value = xmlGetProp(element, id);
    400   if (value) {
    401     if (xmlStrcmp(value, (const xmlChar*)"NfcA") == 0)
    402       data->mTechnology = NFA_TECHNOLOGY_MASK_A;
    403     else if (xmlStrcmp(value, (const xmlChar*)"NfcB") == 0)
    404       data->mTechnology = NFA_TECHNOLOGY_MASK_B;
    405     else if (xmlStrcmp(value, (const xmlChar*)"NfcF") == 0)
    406       data->mTechnology = NFA_TECHNOLOGY_MASK_F;
    407     xmlFree(value);
    408     DLOG_IF(INFO, nfc_debug_enabled)
    409         << StringPrintf("%s: %s=0x%X", "RouteDataSet::importTechnologyRoute",
    410                         id, data->mTechnology);
    411   }
    412 
    413   value = xmlGetProp(element, secElem);
    414   if (value) {
    415     data->mNfaEeHandle = strtol((char*)value, NULL, 16);
    416     xmlFree(value);
    417     data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
    418     DLOG_IF(INFO, nfc_debug_enabled)
    419         << StringPrintf("%s: %s=0x%X", "RouteDataSet::importTechnologyRoute",
    420                         secElem, data->mNfaEeHandle);
    421   }
    422 
    423   value = xmlGetProp(element, switchOn);
    424   if (value) {
    425     data->mSwitchOn = (xmlStrcmp(value, trueString) == 0);
    426     xmlFree(value);
    427   }
    428 
    429   value = xmlGetProp(element, switchOff);
    430   if (value) {
    431     data->mSwitchOff = (xmlStrcmp(value, trueString) == 0);
    432     xmlFree(value);
    433   }
    434 
    435   value = xmlGetProp(element, batteryOff);
    436   if (value) {
    437     data->mBatteryOff = (xmlStrcmp(value, trueString) == 0);
    438     xmlFree(value);
    439   }
    440   database.push_back(data);
    441 }
    442 
    443 /*******************************************************************************
    444 **
    445 ** Function:        deleteFile
    446 **
    447 ** Description:     Delete route data XML file.
    448 **
    449 ** Returns:         True if ok.
    450 **
    451 *******************************************************************************/
    452 bool RouteDataSet::deleteFile() {
    453   static const char fn[] = "RouteDataSet::deleteFile";
    454   std::string filename(nfc_storage_path);
    455   filename.append(sConfigFile);
    456   int stat = remove(filename.c_str());
    457   DLOG_IF(INFO, nfc_debug_enabled)
    458       << StringPrintf("%s: exit %u", fn, stat == 0);
    459   return stat == 0;
    460 }
    461 
    462 /*******************************************************************************
    463 **
    464 ** Function:        getDatabase
    465 **
    466 ** Description:     Obtain a database of routing data.
    467 **                  selection: which database.
    468 **
    469 ** Returns:         Pointer to database.
    470 **
    471 *******************************************************************************/
    472 RouteDataSet::Database* RouteDataSet::getDatabase(DatabaseSelection selection) {
    473   switch (selection) {
    474     case DefaultRouteDatabase:
    475       return &mDefaultRouteDatabase;
    476     case SecElemRouteDatabase:
    477       return &mSecElemRouteDatabase;
    478   }
    479   return NULL;
    480 }
    481 
    482 /*******************************************************************************
    483 **
    484 ** Function:        printDiagnostic
    485 **
    486 ** Description:     Print some diagnostic output.
    487 **
    488 ** Returns:         None.
    489 **
    490 *******************************************************************************/
    491 void RouteDataSet::printDiagnostic() {
    492   static const char fn[] = "RouteDataSet::printDiagnostic";
    493   Database* db = getDatabase(DefaultRouteDatabase);
    494 
    495   DLOG_IF(INFO, nfc_debug_enabled)
    496       << StringPrintf("%s: default route database", fn);
    497   for (Database::iterator iter = db->begin(); iter != db->end(); iter++) {
    498     RouteData* routeData = *iter;
    499     switch (routeData->mRouteType) {
    500       case RouteData::ProtocolRoute: {
    501         RouteDataForProtocol* proto = (RouteDataForProtocol*)routeData;
    502         DLOG_IF(INFO, nfc_debug_enabled)
    503             << StringPrintf("%s: ee h=0x%X; protocol=0x%X", fn,
    504                             proto->mNfaEeHandle, proto->mProtocol);
    505       } break;
    506       case RouteData::TechnologyRoute: {
    507         RouteDataForTechnology* tech = (RouteDataForTechnology*)routeData;
    508         DLOG_IF(INFO, nfc_debug_enabled)
    509             << StringPrintf("%s: ee h=0x%X; technology=0x%X", fn,
    510                             tech->mNfaEeHandle, tech->mTechnology);
    511       } break;
    512     }
    513   }
    514 
    515   DLOG_IF(INFO, nfc_debug_enabled)
    516       << StringPrintf("%s: sec elem route database", fn);
    517   db = getDatabase(SecElemRouteDatabase);
    518   for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++) {
    519     RouteData* routeData = *iter2;
    520     switch (routeData->mRouteType) {
    521       case RouteData::ProtocolRoute: {
    522         RouteDataForProtocol* proto = (RouteDataForProtocol*)routeData;
    523         DLOG_IF(INFO, nfc_debug_enabled)
    524             << StringPrintf("%s: ee h=0x%X; protocol=0x%X", fn,
    525                             proto->mNfaEeHandle, proto->mProtocol);
    526       } break;
    527       case RouteData::TechnologyRoute: {
    528         RouteDataForTechnology* tech = (RouteDataForTechnology*)routeData;
    529         DLOG_IF(INFO, nfc_debug_enabled)
    530             << StringPrintf("%s: ee h=0x%X; technology=0x%X", fn,
    531                             tech->mNfaEeHandle, tech->mTechnology);
    532       } break;
    533     }
    534   }
    535 }
    536