bool CSettings::Load() { //! Reset default path variables to the right device SetDefault(); std::string filepath = configPath; filepath += "/loadiine_gx2.cfg"; CFile file(filepath, CFile::ReadOnly); if (!file.isOpen()) return false; std::string strBuffer; strBuffer.resize(file.size()); file.read((u8 *) &strBuffer[0], strBuffer.size()); file.close(); //! remove all windows crap signs size_t position; while(1) { position = strBuffer.find('\r'); if(position == std::string::npos) break; strBuffer.erase(position, 1); } std::vector<std::string> lines = stringSplit(strBuffer, "\n"); if(lines.empty() || !ValidVersion(lines[0])) return false; for(u32 i = 0; i < lines.size(); ++i) { std::vector<std::string> valueSplit = stringSplit(lines[i], "="); if(valueSplit.size() != 2) continue; while((valueSplit[0].size() > 0) && valueSplit[0][0] == ' ') valueSplit[0].erase(0, 1); while((valueSplit[1].size() > 0) && valueSplit[1][ valueSplit[1].size() - 1 ] == ' ') valueSplit[1].resize(valueSplit[1].size() - 1); for(u32 n = 0; n < settingsNames.size(); n++) { if(!settingsNames[n]) continue; if(valueSplit[0] == settingsNames[n]) { switch(settingsValues[n].dataType) { case TypeBool: settingsValues[n].bValue = atoi(valueSplit[1].c_str()); break; case TypeS8: settingsValues[n].cValue = atoi(valueSplit[1].c_str()); break; case TypeU8: settingsValues[n].ucValue = atoi(valueSplit[1].c_str()); break; case TypeS16: settingsValues[n].sValue = atoi(valueSplit[1].c_str()); break; case TypeU16: settingsValues[n].usValue = atoi(valueSplit[1].c_str()); break; case TypeS32: settingsValues[n].iValue = atoi(valueSplit[1].c_str()); break; case TypeU32: settingsValues[n].uiValue = strtoul(valueSplit[1].c_str(), 0, 10); break; case TypeF32: settingsValues[n].fValue = atof(valueSplit[1].c_str()); break; case TypeString: if(settingsValues[n].strValue == NULL) settingsValues[n].strValue = new std::string(); *settingsValues[n].strValue = valueSplit[1]; break; default: break; } } } } return true; }
bool CSettingsGame::Load() { std::string filepath = configPath; filepath += "/" +this->filename; CFile file(filepath, CFile::ReadOnly); if (!file.isOpen()) return false; std::string strBuffer; strBuffer.resize(file.size()); file.read((u8 *) &strBuffer[0], strBuffer.size()); file.close(); //! remove all windows crap signs size_t position; while(1) { position = strBuffer.find('\r'); if(position == std::string::npos) break; strBuffer.erase(position, 1); } std::vector<std::string> lines_ = stringSplit(strBuffer, "\n"); if(lines_.empty() || !ValidVersion(lines_[0])) return false; for(u32 j = 1; j < lines_.size(); ++j){ std::vector<std::string> lines = stringSplit(lines_[j], ";"); if(lines.empty()) return false; std::string ID6 = lines[0]; std::vector<CSettingsGame::SettingValue> newValues = getSettingValuesFromGameSettings(std::string(COMMON_UPDATE_PATH), false, GAME_SAVES_DEFAULT, LOADIINE_MODE_DEFAULT, SETTING_OFF); for(u32 i = 1; i < lines.size(); ++i) { std::vector<std::string> valueSplit = stringSplit(lines[i], "="); if(valueSplit.size() != 2) continue; while((valueSplit[0].size() > 0) && valueSplit[0][0] == ' ') valueSplit[0].erase(0, 1); while((valueSplit[1].size() > 0) && valueSplit[1][ valueSplit[1].size() - 1 ] == ' ') valueSplit[1].resize(valueSplit[1].size() - 1); for(u32 n = 0; n < settingsNames.size(); n++) { if(!settingsNames[n]) continue; if(valueSplit[0] == settingsNames[n]) { switch(newValues.at(n).dataType) { case TypeBool: newValues.at(n).bValue = atoi(valueSplit[1].c_str()); break; case TypeS8: newValues.at(n).cValue = atoi(valueSplit[1].c_str()); break; case TypeU8: newValues.at(n).ucValue = atoi(valueSplit[1].c_str()); break; case TypeS16: newValues.at(n).sValue = atoi(valueSplit[1].c_str()); break; case TypeU16: newValues.at(n).usValue = atoi(valueSplit[1].c_str()); break; case TypeS32: newValues.at(n).iValue = atoi(valueSplit[1].c_str()); break; case TypeU32: newValues.at(n).uiValue = strtoul(valueSplit[1].c_str(), 0, 10); break; case TypeF32: newValues.at(n).fValue = atof(valueSplit[1].c_str()); break; case TypeString: if(newValues.at(n).strValue == NULL) newValues.at(n).strValue = new std::string(); *newValues.at(n).strValue = valueSplit[1]; break; default: break; } } } } GameSettings * set = GetGameSettingsBySettingGameValue(ID6,newValues); //Clean pointer for(u32 j = 0; j < newValues.size(); j++){ if(newValues.at(j).dataType == TypeString) delete newValues.at(j).strValue; } settingsGames[ID6] = *set; delete set; } return true; }
/* **************************************************************************** * * restService - */ std::string restService(ConnectionInfo* ciP, RestService* serviceV) { std::vector<std::string> compV; int components; XmlRequest* reqP = NULL; JsonRequest* jsonReqP = NULL; ParseData parseData; if ((ciP->url.length() == 0) || ((ciP->url.length() == 1) && (ciP->url.c_str()[0] == '/'))) { OrionError error(SccBadRequest, "The Orion Context Broker is a REST service, not a 'web page'"); std::string response = error.render(ciP->outFormat, ""); LM_W(("Bad Input (The Orion Context Broker is a REST service, not a 'web page')")); restReply(ciP, response); return std::string("Empty URL"); } ciP->httpStatusCode = SccOk; components = stringSplit(ciP->url, '/', compV); for (unsigned int ix = 0; serviceV[ix].treat != NULL; ++ix) { if ((serviceV[ix].components != 0) && (serviceV[ix].components != components)) { continue; } if ((ciP->method != serviceV[ix].verb) && (serviceV[ix].verb != "*")) { continue; } strncpy(ciP->payloadWord, serviceV[ix].payloadWord.c_str(), sizeof(ciP->payloadWord)); bool match = true; for (int compNo = 0; compNo < components; ++compNo) { if (serviceV[ix].compV[compNo] == "*") { continue; } if (strcasecmp(serviceV[ix].compV[compNo].c_str(), compV[compNo].c_str()) != 0) { match = false; break; } } if (match == false) { continue; } if ((ciP->payload != NULL) && (ciP->payloadSize != 0) && (ciP->payload[0] != 0) && (serviceV[ix].verb != "*")) { std::string response; LM_T(LmtParsedPayload, ("Parsing payload for URL '%s', method '%s', service vector index: %d", ciP->url.c_str(), ciP->method.c_str(), ix)); ciP->parseDataP = &parseData; response = payloadParse(ciP, &parseData, &serviceV[ix], &reqP, &jsonReqP); LM_T(LmtParsedPayload, ("payloadParse returns '%s'", response.c_str())); if (response != "OK") { restReply(ciP, response); if (reqP != NULL) { reqP->release(&parseData); } if (jsonReqP != NULL) { jsonReqP->release(&parseData); } compV.clear(); return response; } } LM_T(LmtService, ("Treating service %s %s", serviceV[ix].verb.c_str(), ciP->url.c_str())); // Sacred - used in 'heavyTest' statisticsUpdate(serviceV[ix].request, ciP->inFormat); // Tenant to connectionInfo ciP->tenant = ciP->tenantFromHttpHeader; // // A tenant string must not be longer than 50 characters and may only contain // underscores and alphanumeric characters. // std::string result; if ((ciP->tenant != "") && ((result = tenantCheck(ciP->tenant)) != "OK")) { OrionError error(SccBadRequest, "tenant name not accepted - a tenant string must not be longer than " MAX_TENANT_NAME_LEN_STRING " characters" " and may only contain underscores and alphanumeric characters"); std::string response = error.render(ciP->outFormat, ""); LM_W(("Bad Input (%s)", error.details.c_str())); restReply(ciP, response); if (reqP != NULL) { reqP->release(&parseData); } if (jsonReqP != NULL) { jsonReqP->release(&parseData); } compV.clear(); return response; } LM_T(LmtTenant, ("tenant: '%s'", ciP->tenant.c_str())); commonFilters(ciP, &parseData, &serviceV[ix]); scopeFilter(ciP, &parseData, &serviceV[ix]); std::string response = serviceV[ix].treat(ciP, components, compV, &parseData); filterRelease(&parseData, serviceV[ix].request); if (reqP != NULL) { reqP->release(&parseData); } if (jsonReqP != NULL) { jsonReqP->release(&parseData); } compV.clear(); if (response == "DIE") { orionExitFunction(0, "Received a 'DIE' request on REST interface"); } restReply(ciP, response); return response; } LM_W(("Bad Input (service '%s' not recognized)", ciP->url.c_str())); ciP->httpStatusCode = SccBadRequest; std::string answer = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->payloadWord, SccBadRequest, std::string("unrecognized request")); restReply(ciP, answer); compV.clear(); return answer; }
/* **************************************************************************** * * servicePathCheck - check vector of service paths * * This function is called for ALL requests, when a service-path URI-parameter is found. * So, '#' is considered a valid character at it is valid for discoveries and queries. * Later on, if the request is a registration or notification, another function is called * to make sure there is only ONE service path and that there is no '#' present. * * FIXME P5: updates should also call the other servicePathCheck (in common lib) * * [ Not static just to let unit tests call this function ] */ int servicePathCheck(ConnectionInfo* ciP, const char* servicePath) { // // 1. Max 10 paths - ONLY ONE path allowed at this moment // 2. Max 10 levels in each path // 3. Max 50 characters in each path component // 4. Only alphanum and underscore allowed (just like in tenants) // OR: Last component is EXACTLY '#' // std::vector<std::string> compV; int components; if (ciP->httpHeaders.servicePathReceived == false) return 0; if (servicePath[0] != '/') { OrionError e(SccBadRequest, "Only /absolute/ Service Paths allowed [a service path must begin with /]"); ciP->answer = e.render(ciP->outFormat, ""); return 1; } components = stringSplit(servicePath, '/', compV); if (components > 10) { OrionError e(SccBadRequest, "too many components in ServicePath"); ciP->answer = e.render(ciP->outFormat, ""); return 2; } for (int ix = 0; ix < components; ++ix) { if (strlen(compV[ix].c_str()) > 50) { OrionError e(SccBadRequest, "component-name too long in ServicePath"); ciP->answer = e.render(ciP->outFormat, ""); return 3; } // Last token in the path is allowed to be *exactly* "#", as in /Madrid/Gardens/#. Note that // /Madrid/Gardens/North# is not allowed if ((ix == components - 1) && (compV[ix] == "#")) { continue; } const char* comp = compV[ix].c_str(); for (unsigned int cIx = 0; cIx < strlen(comp); ++cIx) { if (!isalnum(comp[cIx]) && (comp[cIx] != '_')) { OrionError e(SccBadRequest, "a component of ServicePath contains an illegal character"); ciP->answer = e.render(ciP->outFormat, ""); return 4; } } } return 0; }
/* **************************************************************************** * * getEntity - * * GET /v2/entities/:id:[?attrs=:list:] * * Payload In: None * Payload Out: Entity * * * Fill in QueryContextRequest * Call standard op postQueryContext * Render Entity response * Cleanup and return result */ std::string getEntity ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string attrs = ciP->uriParam["attrs"]; std::string type = ciP->uriParam["type"]; if (forbiddenIdChars(ciP->apiVersion, compV[2].c_str() , NULL)) { OrionError oe(SccBadRequest, INVAL_CHAR_URI); return oe.render(ciP, ""); } // Fill in QueryContextRequest parseDataP->qcr.res.fill(compV[2], type, "false", EntityTypeEmptyOrNotEmpty, ""); if (attrs != "") { std::vector<std::string> attrsV; stringSplit(attrs, ',', attrsV); for (std::vector<std::string>::const_iterator it = attrsV.begin(); it != attrsV.end(); ++it) { parseDataP->qcr.res.attributeList.push_back_if_absent(*it); } } // Call standard op postQueryContext postQueryContext(ciP, components, compV, parseDataP); // Render entity response Entity entity; // If request was for /entities/<<id>>/attrs, type and id should not be shown if (compV.size() == 4 && compV[3] == "attrs") { entity.hideIdAndType(); } entity.fill(&parseDataP->qcrs.res); std::string answer; TIMED_RENDER(answer = entity.render(ciP, EntityResponse)); if (parseDataP->qcrs.res.errorCode.code == SccOk && parseDataP->qcrs.res.contextElementResponseVector.size() > 1) { // No problem found, but we expect only one entity ciP->httpStatusCode = SccConflict; } else { // the same of the wrapped operation ciP->httpStatusCode = parseDataP->qcrs.res.errorCode.code; } // 04. Cleanup and return result entity.release(); parseDataP->qcr.res.release(); return answer; }
SettingsMenu::SettingsMenu(int w, int h) : GuiFrame(w, h) , categorySelectionFrame(w, h) , particleBgImage(w, h, 50) , buttonClickSound(Resources::GetSound("settings_click_2.mp3")) , quitImageData(Resources::GetImageData("quitButton.png")) , categoryImageData(Resources::GetImageData("settingsCategoryButton.png")) , categoryBgImageData(Resources::GetImageData("settingsCategoryBg.png")) , quitImage(quitImageData) , quitButton(quitImage.getWidth(), quitImage.getHeight()) , touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH) , wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) , buttonATrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_A, true) , buttonBTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_B, true) , buttonLTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_L, true) , buttonRTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_R, true) , buttonLeftTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_LEFT | GuiTrigger::STICK_L_LEFT, true) , buttonRightTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_RIGHT | GuiTrigger::STICK_L_RIGHT, true) , leftArrowImageData(Resources::GetImageData("leftArrow.png")) , rightArrowImageData(Resources::GetImageData("rightArrow.png")) , leftArrowImage(leftArrowImageData) , rightArrowImage(rightArrowImageData) , leftArrowButton(leftArrowImage.getWidth(), leftArrowImage.getHeight()) , rightArrowButton(rightArrowImage.getWidth(), rightArrowImage.getHeight()) , DPADButtons(w,h) { currentPosition = 0; targetPosition = 0; selectedCategory = 0; animationSpeed = 25; bUpdatePositions = true; quitButton.setImage(&quitImage); quitButton.setAlignment(ALIGN_BOTTOM | ALIGN_LEFT); quitButton.clicked.connect(this, &SettingsMenu::OnQuitButtonClick); quitButton.setTrigger(&touchTrigger); quitButton.setTrigger(&wpadTouchTrigger); quitButton.setEffectGrow(); quitButton.setSoundClick(buttonClickSound); categorySelectionFrame.append(&quitButton); versionText.setColor(glm::vec4(0.6f, 0.6f, 0.6f, 1.0f)); versionText.setFontSize(42); versionText.setAlignment(ALIGN_TOP | ALIGN_RIGHT); versionText.setPosition(-50, -80); versionText.setText("Loadiine GX2 " LOADIINE_VERSION); categorySelectionFrame.append(&versionText); const u32 cuCategoriesCount = sizeof(stSettingsCategories) / sizeof(stSettingsCategories[0]); if(cuCategoriesCount > 0) selectedCategory = 0; for(u32 idx = 0; idx < cuCategoriesCount; idx++) { settingsCategories.resize(idx + 1); GuiSettingsCategory & category = settingsCategories[idx]; std::vector<std::string> splitDescriptions = stringSplit(stSettingsCategories[idx].descriptions, "\n"); category.categoryIconData = Resources::GetImageData(stSettingsCategories[idx].icon); category.categoryIconGlowData = Resources::GetImageData(stSettingsCategories[idx].iconGlow); category.categoryLabel = new GuiText(tr(stSettingsCategories[idx].name), 46, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)); category.categoryLabel->setPosition(0, -120); category.categoryBgImage = new GuiImage(categoryBgImageData); category.categoryImages = new GuiImage(categoryImageData); category.categoryIcon = new GuiImage(category.categoryIconData); category.categoryIconGlow = new GuiImage(category.categoryIconGlowData); category.categoryButton = new GuiButton(category.categoryImages->getWidth(), category.categoryImages->getHeight()); category.categoryIcon->setPosition(0, 40); category.categoryIconGlow->setPosition(0, 40); category.categoryButton->setLabel(category.categoryLabel); category.categoryButton->setImage(category.categoryImages); category.categoryButton->setPosition(-300, 0); category.categoryButton->setIcon(category.categoryIcon); category.categoryButton->setIconOver(category.categoryIconGlow); category.categoryButton->setTrigger(&touchTrigger); category.categoryButton->setTrigger(&wpadTouchTrigger); category.categoryButton->setSoundClick(buttonClickSound); category.categoryButton->setEffectGrow(); category.categoryButton->clicked.connect(this, &SettingsMenu::OnCategoryClick); categorySelectionFrame.append(category.categoryBgImage); categorySelectionFrame.append(category.categoryButton); category.categoryButton->setParent(category.categoryBgImage); category.categoryBgImage->setPosition(currentPosition + (category.categoryBgImage->getWidth() + 40) * idx, 0); for(u32 n = 0; n < splitDescriptions.size(); n++) { GuiText * descr = new GuiText(tr(splitDescriptions[n].c_str()), 46, glm::vec4(0.8f, 0.8f, 0.8f, 1.0f)); descr->setAlignment(ALIGN_MIDDLE | ALIGN_LEFT); descr->setPosition(category.categoryBgImage->getWidth() * 0.5f - 50.0f, category.categoryBgImage->getHeight() * 0.5f - 100.0f - n * 60.0f); categorySelectionFrame.append(descr); descr->setParent(category.categoryBgImage); category.descriptions.push_back(descr); } GuiImage *smallIconOver = new GuiImage(category.categoryIconGlowData); GuiImage *smallIcon = new GuiImage(category.categoryIconData); GuiButton *smallIconButton = new GuiButton(smallIcon->getWidth() * smallIconScale, smallIcon->getHeight() * smallIconScale); smallIcon->setScale(smallIconScale); smallIconOver->setScale(smallIconScale); smallIconButton->setImage(smallIcon); smallIconButton->setEffectGrow(); smallIconButton->setTrigger(&touchTrigger); smallIconButton->setTrigger(&wpadTouchTrigger); smallIconButton->setSoundClick(buttonClickSound); smallIconButton->clicked.connect(this, &SettingsMenu::OnSmallIconClick); categorySelectionFrame.append(smallIconButton); categorySmallImages.push_back(smallIcon); categorySmallImagesOver.push_back(smallIconOver); categorySmallButtons.push_back(smallIconButton); } leftArrowButton.setImage(&leftArrowImage); leftArrowButton.setEffectGrow(); leftArrowButton.setPosition(40, 0); leftArrowButton.setAlignment(ALIGN_LEFT | ALIGN_MIDDLE); leftArrowButton.setTrigger(&touchTrigger); leftArrowButton.setTrigger(&wpadTouchTrigger); leftArrowButton.setSoundClick(buttonClickSound); leftArrowButton.clicked.connect(this, &SettingsMenu::OnCategoryLeftClick); categorySelectionFrame.append(&leftArrowButton); rightArrowButton.setImage(&rightArrowImage); rightArrowButton.setEffectGrow(); rightArrowButton.setPosition(-40, 0); rightArrowButton.setAlignment(ALIGN_RIGHT | ALIGN_MIDDLE); rightArrowButton.setTrigger(&touchTrigger); rightArrowButton.setTrigger(&wpadTouchTrigger); rightArrowButton.setSoundClick(buttonClickSound); rightArrowButton.clicked.connect(this, &SettingsMenu::OnCategoryRightClick); categorySelectionFrame.append(&rightArrowButton); DPADButtons.setTrigger(&buttonATrigger); DPADButtons.setTrigger(&buttonBTrigger); DPADButtons.setTrigger(&buttonLTrigger); DPADButtons.setTrigger(&buttonRTrigger); DPADButtons.setTrigger(&buttonLeftTrigger); DPADButtons.setTrigger(&buttonRightTrigger); DPADButtons.clicked.connect(this, &SettingsMenu::OnDPADClick); append(&DPADButtons); categorySelectionFrame.append(&DPADButtons); setTargetPosition(0); moving = false; //! the particle BG is always appended in all sub menus append(&particleBgImage); append(&categorySelectionFrame); }
call_stack::call_stack(const size_t /*num_discard = 0*/) { // getting a stack trace on Windows / MinGW is loads of fun (not) std::vector<void*> traceVector; HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); void* fakeStackPtr = stacktrace::getFakeCallStackPointer(); if (fakeStackPtr) { // set up fake stack for partial trace LPEXCEPTION_POINTERS exceptionInfo = (LPEXCEPTION_POINTERS) fakeStackPtr; if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { // can't do stack walking in Windows when a stack overflow happens :-/ traceVector.push_back((void*) exceptionInfo->ContextRecord->Eip); } else { SymInitialize(GetCurrentProcess(), 0, TRUE); STACKFRAME frame = {0}; frame.AddrPC.Offset = exceptionInfo->ContextRecord->Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = exceptionInfo->ContextRecord->Esp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Offset = exceptionInfo->ContextRecord->Ebp; frame.AddrFrame.Mode = AddrModeFlat; while ((int) traceVector.size() < WIN_STACK_FRAMES_MAX && StackWalk(IMAGE_FILE_MACHINE_I386, process, thread, &frame, exceptionInfo->ContextRecord, 0, SymFunctionTableAccess, SymGetModuleBase, 0)) { traceVector.push_back((void*) frame.AddrPC.Offset); } } } else { if (!::SymSetOptions( // ::SymGetOptions() SYMOPT_DEBUG | SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES // | SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_LOAD_LINES)) { // std::cout << "SymSetOptions failed!" << std::endl; // return; } if (!::SymInitialize( /* process */ process, /* user-defined search path */ NULL, /* include current process */ TRUE)) { // std::cout << "SymInitialize failed!" << std::endl; // return; } void* trace[WIN_STACK_FRAMES_MAX]; USHORT frameCount = ::CaptureStackBackTrace( /* framesToSkip */ WIN_STACK_FRAMES_TO_SKIP, /* framesToCapture; must be < 63 */ WIN_STACK_FRAMES_MAX, trace, /* hash */ NULL ); for (int i = 0; i < frameCount; i++) { traceVector.push_back(trace[i]); } // try to load module symbol information; this always fails for me :-/ DWORD64 BaseAddr = 0; DWORD FileSize = 0; const char* progFileC = exceptions::getProgramNameForStackTrace().c_str(); char* progFile = (char*) progFileC; if (!::SymLoadModule( process, // Process handle of the current process NULL, // Handle to the module's image file (not needed) progFile, // Path/name of the file NULL, // User-defined short name of the module (it can be NULL) BaseAddr, // Base address of the module (cannot be NULL if .PDB file is used, otherwise it can be NULL) FileSize)) { // Size of the file (cannot be NULL if .PDB file is used, otherwise it can be NULL) // std::cout << "Error: SymLoadModule() failed: " << pp->os_getLastError() << std::endl; // return; } } // let's also try to get the line numbers via an external command-line process 'addr2line' // (ought to be able to get this information through C function 'backtrace', but for some // reason, Qt Creator's shipped version of MinGW does not include this functionality, argh) std::string addr2lineOutput; std::vector<std::string> addr2lineLines; if (!traceVector.empty()) { int result = addr2line_all(traceVector, addr2lineOutput); if (result == 0) { addr2lineLines = stringSplit(addr2lineOutput, "\n"); } } SYMBOL_INFO* symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 1024 * sizeof(char), 1); symbol->MaxNameLen = 1020; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); for (int i = 0; i < (int) traceVector.size(); ++i) { entry ent; ent.address = traceVector[i]; if (process && ::SymFromAddr(process, (DWORD64) traceVector[i], 0, symbol)) { ent.function = symbol->Name; } // internal stuff failed, so load from external process if (i < addr2lineLines.size()) { injectAddr2lineInfo(ent, addr2line_clean(addr2lineLines[i])); } else { injectAddr2lineInfo(ent, ""); } if (!ent.function.empty() || ent.line > 0) { stack.push_back(ent); } } free(symbol); }
/* **************************************************************************** * * mongoConnect - * * Default value for writeConcern == 1 (0: unacknowledged, 1: acknowledged) */ static DBClientBase* mongoConnect ( const char* host, const char* db, const char* rplSet, const char* username, const char* passwd, bool multitenant, int writeConcern, double timeout ) { std::string err; DBClientBase* connection = NULL; LM_T(LmtMongo, ("Connection info: dbName='%s', rplSet='%s', timeout=%f", db, rplSet, timeout)); bool connected = false; int retries = RECONNECT_RETRIES; if (strlen(rplSet) == 0) { /* Setting the first argument to true is to use autoreconnect */ connection = new DBClientConnection(true); /* Not sure of how to generalize the following code, given that DBClientBase class doesn't have a common connect() method (surprisingly) */ for (int tryNo = 0; tryNo < retries; ++tryNo) { if ( ((DBClientConnection*)connection)->connect(host, err)) { connected = true; break; } if (tryNo == 0) { LM_E(("Database Startup Error (cannot connect to mongo - doing %d retries with a %d microsecond interval)", retries, RECONNECT_DELAY)); } else { LM_T(LmtMongo, ("Try %d connecting to mongo failed", tryNo)); } usleep(RECONNECT_DELAY * 1000); // usleep accepts microseconds } } else { LM_T(LmtMongo, ("Using replica set %s", rplSet)); // autoReconnect is always on for DBClientReplicaSet connections. std::vector<std::string> hostTokens; int components = stringSplit(host, ',', hostTokens); std::vector<HostAndPort> rplSetHosts; for (int ix = 0; ix < components; ix++) { LM_T(LmtMongo, ("rplSet host <%s>", hostTokens[ix].c_str())); rplSetHosts.push_back(HostAndPort(hostTokens[ix])); } connection = new DBClientReplicaSet(rplSet, rplSetHosts, timeout); /* Not sure of to generalize the following code, given that DBClientBase class hasn't a common connect() method (surprisingly) */ for (int tryNo = 0; tryNo < retries; ++tryNo) { if ( ((DBClientReplicaSet*)connection)->connect()) { connected = true; break; } if (tryNo == 0) { LM_E(("Database Startup Error (cannot connect to mongo - doing %d retries with a %d microsecond interval)", retries, RECONNECT_DELAY)); } else { LM_T(LmtMongo, ("Try %d connecting to mongo failed", tryNo)); } usleep(RECONNECT_DELAY * 1000); // usleep accepts microseconds } } if (connected == false) { LM_E(("Database Error (connection failed, after %d retries: '%s')", retries, err.c_str())); return NULL; } LM_I(("Successful connection to database")); // // WriteConcern // mongo::WriteConcern writeConcernCheck; // In legacy driver writeConcern is no longer an int, but a class. We need a small // conversion step here mongo::WriteConcern wc = writeConcern == 1 ? mongo::WriteConcern::acknowledged : mongo::WriteConcern::unacknowledged; connection->setWriteConcern((mongo::WriteConcern) wc); writeConcernCheck = (mongo::WriteConcern) connection->getWriteConcern(); if (writeConcernCheck.nodes() != wc.nodes()) { LM_E(("Database Error (Write Concern not set as desired)")); return NULL; } LM_T(LmtMongo, ("Active DB Write Concern mode: %d", writeConcern)); /* Authentication is different depending if multiservice is used or not. In the case of not * using multiservice, we authenticate in the single-service database. In the case of using * multiservice, it isn't a default database that we know at contextBroker start time (when * this connection function is invoked) so we authenticate on the admin database, which provides * access to any database */ if (multitenant) { if (strlen(username) != 0 && strlen(passwd) != 0) { if (!connection->auth("admin", std::string(username), std::string(passwd), err)) { LM_E(("Database Startup Error (authentication: db='admin', username='******', password='******': %s)", username, err.c_str())); return NULL; } } } else { if (strlen(db) != 0 && strlen(username) != 0 && strlen(passwd) != 0) { if (!connection->auth(std::string(db), std::string(username), std::string(passwd), err)) { LM_E(("Database Startup Error (authentication: db='%s', username='******', password='******': %s)", db, username, err.c_str())); return NULL; } } } /* Get mongo version with the 'buildinfo' command */ BSONObj result; std::string extra; connection->runCommand("admin", BSON("buildinfo" << 1), result); std::string versionString = std::string(result.getStringField("version")); if (!versionParse(versionString, mongoVersionMayor, mongoVersionMinor, extra)) { LM_E(("Database Startup Error (invalid version format: %s)", versionString.c_str())); return NULL; } LM_T(LmtMongo, ("mongo version server: %s (mayor: %d, minor: %d, extra: %s)", versionString.c_str(), mongoVersionMayor, mongoVersionMinor, extra.c_str())); return connection; }
/* **************************************************************************** * * parseUrl - * * Breaks an URL into pieces. It returns false if the string passed as first * argument is not a valid URL. Otherwise, it returns true. * */ bool parseUrl(std::string url, std::string& host, int& port, std::string& path) { /* Sanity check */ if (url == "") { return false; } /* First: split by the first '/' to get host:ip and path */ std::vector<std::string> urlTokens; int components = stringSplit(url, '/', urlTokens); /* http://some.host.com/my/path * ^^ ^ ^ * || | | * ----- ------------- -- ---- * 0 2 3 4 position in urlTokens vector * 1 23 4 5 coponentes */ if ((components < 3) || (components == 3 && urlTokens[2].length() == 0)) { return false; } path = ""; /* Note that components could be 3, in which case we don't enter in the for. This is * the case of URL without '/' like eg. "http://www.google.com" */ for (int ix = 3; ix < components; ++ix ) { path += "/" + urlTokens[ix]; } if (path == "") { /* Minimum path is always "/" */ path = "/"; } /* Second: split third token for host and port */ std::string auxIp; std::string auxPort; // First we check if it is IPv6 if (getIPv6Port(urlTokens[2], auxIp, auxPort)) { // IPv6 host = auxIp; port = atoi(auxPort.c_str()); LM_VVV(("Parsed IPv6: '%s' and port: '%d'", host.c_str(), port)); } else { // IPv4 std::vector<std::string> hostTokens; components = stringSplit(urlTokens[2], ':', hostTokens); /* some.host.com:8080 * ^ * | * ------------- ---- * 0 1 position in urlTokens vector * 1 2 components */ /* Sanity check */ if (components > 2) { return false; } host = hostTokens[0]; if (components == 2) { port = atoi(hostTokens[1].c_str()); } else { port = DEFAULT_HTTP_PORT; } } return true; }
CompletionType evaluate() { Register<Value> value; switch (method) { case ToString: case ValueOf: if (!getThis()->isObject()) { throw getErrorInstance("TypeError"); } value = static_cast<ObjectValue*>(getThis())->getValueProperty(); if (!value->isString()) { throw getErrorInstance("TypeError"); } break; case CharAt: value = charAt(); break; case CharCodeAt: value = charCodeAt(); break; case Concat: value = concat(getThis()); break; case IndexOf: value = indexOf(getThis()); break; case LastIndexOf: value = lastIndexOf(getThis()); break; case LocaleCompare: value = localeCompare(getThis()); break; case Match: value = stringMatch(); break; case Replace: value = stringReplace(); break; case Search: value = stringSearch(); break; case Slice: value = slice(getThis()); break; case Split: value = stringSplit(); break; case Substring: value = substring(getThis()); break; case Substr: value = substr(getThis()); break; case ToLowerCase: case ToLocaleLowerCase: value = toLowerCase(getThis()); break; case ToUpperCase: case ToLocaleUpperCase: value = toUpperCase(getThis()); break; } return CompletionType(CompletionType::Return, value, ""); }
/* **************************************************************************** * * getEntities - * * GET /v2/entities * * Payload In: None * Payload Out: Entities * * URI parameters: * - limit=NUMBER * - offset=NUMBER * - count=true/false * - id * - idPattern * - q * - geometry * - coords * * 01. Fill in QueryContextRequest * 02. Call standard op postQueryContext * 03. Render Entities response * 04. Cleanup and return result */ std::string getEntities ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { Entities entities; std::string answer; std::string pattern = ".*"; // all entities, default value std::string id = ciP->uriParam["id"]; std::string idPattern = ciP->uriParam["idPattern"]; std::string q = ciP->uriParam["q"]; std::string geometry = ciP->uriParam["geometry"]; std::string coords = ciP->uriParam["coords"]; std::string out; if ((idPattern != "") && (id != "")) { OrionError oe(SccBadRequest, "Incompatible parameters: id, IdPattern"); TIMED_RENDER(answer = oe.render(ciP, "")); return answer; } else if (id != "") { // FIXME: a more efficient query could be possible ... std::vector<std::string> idsV; stringSplit(id, ',', idsV); for (unsigned int ix = 0; ix != idsV.size(); ++ix) { if (ix != 0) { pattern += "|"; } pattern += idsV[ix]; } } else if (idPattern != "") { pattern = idPattern; } // Making sure geometry and coords are not used individually if ((coords != "") && (geometry == "")) { OrionError oe(SccBadRequest, "URI param /coords/ used without /geometry/"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } else if ((geometry != "") && (coords == "")) { OrionError oe(SccBadRequest, "URI param /geometry/ used without /coords/"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } // Making sure geometry is valid (if present) orion::Geometry geo; std::vector<std::string> coordsV; if (geometry != "") { std::string errorString; if (geo.parse(geometry.c_str(), &errorString) != 0) { OrionError oe(SccBadRequest, std::string("error parsing geometry: ") + errorString); TIMED_RENDER(out = oe.render(ciP, "")); return out; } if ((geo.areaType != "polygon") && (geo.areaType != "circle")) { OrionError oe(SccBadRequest, "URI param /geometry/ must be either /polygon/ or /circle/"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } // // As 'geometry' is present, so is 'coords' - checking coords // int noOfCoords = stringSplit(coords, ';', coordsV); if (noOfCoords == 0) { OrionError oe(SccBadRequest, "URI param /coords/ has no coordinates"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } if ((geo.areaType == "circle") && (noOfCoords != 1)) { OrionError oe(SccBadRequest, "Too many coordinates for circle"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } if ((geo.areaType == "polygon") && (noOfCoords < 3)) { OrionError oe(SccBadRequest, "Too few coordinates for polygon"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } } // // 01. Fill in QueryContextRequest - type "" is valid for all types // parseDataP->qcr.res.fill(pattern, ciP->uriParam["type"], "true", EntityTypeEmptyOrNotEmpty, ""); // If URI param 'q' is given, its value must be put in a scope if (q != "") { Scope* scopeP = new Scope(SCOPE_TYPE_SIMPLE_QUERY, q); parseDataP->qcr.res.restriction.scopeVector.push_back(scopeP); } // If URI params 'geometry' and 'coords' are given, another scope is to be created for this if ((coords != "") && (geometry != "")) { Scope* scopeP = new Scope(SCOPE_TYPE_LOCATION, ""); std::string errorString; if (scopeP->fill(&geo, coordsV, &errorString) != 0) { OrionError oe(SccBadRequest, errorString); TIMED_RENDER(out = oe.render(ciP, "")); return out; } parseDataP->qcr.res.restriction.scopeVector.push_back(scopeP); } // 02. Call standard op postQueryContext answer = postQueryContext(ciP, components, compV, parseDataP); if (ciP->httpStatusCode != SccOk) { // Something went wrong in the query, an invalid pattern for example parseDataP->qcr.res.release(); return answer; } // 03. Render Entities response if (parseDataP->qcrs.res.contextElementResponseVector.size() == 0) { ciP->httpStatusCode = SccOk; answer = "[]"; } else { entities.fill(&parseDataP->qcrs.res); TIMED_RENDER(answer = entities.render(ciP, EntitiesResponse)); } // 04. Cleanup and return result entities.release(); parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * Entity::render - * * The rendering of JSON in APIv2 depends on the URI param 'options' * Rendering methods: * o 'normalized' (default) * o 'keyValues' (less verbose, only name and values shown for attributes - no type, no metadatas) * o 'values' (only the values of the attributes are printed, in a vector) */ std::string Entity::render(ConnectionInfo* ciP, RequestType requestType, bool comma) { RenderFormat renderFormat = NGSI_V2_NORMALIZED; if (ciP->uriParamOptions[OPT_KEY_VALUES] == true) { renderFormat = NGSI_V2_KEYVALUES; } else if (ciP->uriParamOptions[OPT_VALUES] == true) { renderFormat = NGSI_V2_VALUES; } else if (ciP->uriParamOptions[OPT_UNIQUE_VALUES] == true) { renderFormat = NGSI_V2_UNIQUE_VALUES; } if ((oe.details == "") && ((oe.reasonPhrase == "OK") || (oe.reasonPhrase == ""))) { std::string out; std::vector<std::string> metadataFilter; std::vector<std::string> attrsFilter; if (ciP->uriParam[URI_PARAM_METADATA] != "") { stringSplit(ciP->uriParam[URI_PARAM_METADATA], ',', metadataFilter); } if (ciP->uriParam[URI_PARAM_ATTRIBUTES] != "") { stringSplit(ciP->uriParam[URI_PARAM_ATTRIBUTES], ',', attrsFilter); } // Add special attributes representing entity dates if ((creDate != 0) && (ciP->uriParamOptions[DATE_CREATED] || (std::find(attrsFilter.begin(), attrsFilter.end(), DATE_CREATED) != attrsFilter.end()))) { ContextAttribute* caP = new ContextAttribute(DATE_CREATED, DATE_TYPE, creDate); attributeVector.push_back(caP); } if ((modDate != 0) && (ciP->uriParamOptions[DATE_MODIFIED] || (std::find(attrsFilter.begin(), attrsFilter.end(), DATE_MODIFIED) != attrsFilter.end()))) { ContextAttribute* caP = new ContextAttribute(DATE_MODIFIED, DATE_TYPE, modDate); attributeVector.push_back(caP); } if ((renderFormat == NGSI_V2_VALUES) || (renderFormat == NGSI_V2_UNIQUE_VALUES)) { out = "["; if (attributeVector.size() != 0) { out += attributeVector.toJson(renderFormat, attrsFilter, metadataFilter, false); } out += "]"; } else { out = "{"; if (renderId) { out += JSON_VALUE("id", id); out += ","; /* This is needed for entities coming from NGSIv1 (which allows empty or missing types) */ out += JSON_STR("type") + ":" + ((type != "")? JSON_STR(type) : JSON_STR(DEFAULT_ENTITY_TYPE)); } std::string attrsOut; if (attributeVector.size() != 0) { attrsOut += attributeVector.toJson(renderFormat, attrsFilter, metadataFilter, false); } // // Note that just attributeVector.size() != 0 (used in previous versions) cannot be used // as ciP->uriParam["attrs"] filter could remove all the attributes // if (attrsOut != "") { if (renderId) { out += "," + attrsOut; } else { out += attrsOut; } } out += "}"; } if (comma) { out += ","; } return out; } return oe.toJson(); }