// static bool OTPaths::ToReal(const String& strExactPath, String& out_strCanonicalPath) { if (!strExactPath.Exists()) { otErr << __FUNCTION__ << ": Null: " << "strExactPath" << " passed in!\n"; OT_FAIL; } #ifdef _WIN32 #ifdef _UNICODE const char* szPath = strExactPath.Get(); size_t newsize = strlen(szPath) + 1; wchar_t* wzPath = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wzPath, newsize, szPath, 4096); wchar_t szBuf[4096] = L""; if (GetFullPathName(wzPath, 4096, szBuf, nullptr)) { out_strCanonicalPath.Set(utf8util::UTF8FromUTF16(szBuf)); return true; } else { out_strCanonicalPath.Set(""); return false; } #else char_t szBuf[4096] = ""; char_t const* szPath = strRealPath.Get(); if (GetFullPathName(szPath, 4096, szBuf, nullptr)) { out_strCanonicalPath.Set(szBuf); return true; } else { out_strCanonicalPath.Set(""); return false; } #endif #else char* actualpath = realpath(strExactPath.Get(), NULL); if (actualpath == NULL) { if (errno == ENOTDIR) { otWarn << "Input value to RealPath is not a directory: (Realpath: " "skipping)\n"; out_strCanonicalPath.Set(strExactPath); return true; } if (errno == ENOENT) { otWarn << "File doesn't exist: (Realpath: skipping)\n"; out_strCanonicalPath.Set(strExactPath); return true; } OT_ASSERT_MSG((errno != EACCES), "Error (Realpath: EACCES): Unable to " "build RealPath: access denied"); OT_ASSERT_MSG( (errno != EINVAL), "Error (RealPath: EINVAL): Input value into RealPath was nullptr"); OT_ASSERT_MSG( (errno != ELOOP), "Error (RealPath: ELOOP): Resloving links resulted in a loop."); OT_ASSERT_MSG((errno != ENAMETOOLONG), "Error (RealPath: ENAMETOOLONG): Name too int64_t."); OT_ASSERT_MSG((errno != ERANGE), "Error (RealPath: ERANGE): Resulting " "path is too int64_t for the buffer"); OT_ASSERT_MSG((errno != EIO), "Error (RealPath: EIO): Unable to access path."); OT_ASSERT_MSG( (false), "Error (RealPath: OTHER): Something bad Happend with 'realpath'."); } out_strCanonicalPath.Set(actualpath); free(actualpath); return true; #endif }
// UNIX: // void * memcpy(void* restrict s1, const void* restrict s2, size_t n); // // static void* OTPassword::safe_memcpy(void* dest, uint32_t dest_size, const void* src, uint32_t src_length, bool bZeroSource) // if true, sets the // source buffer to // zero after copying // is done. { // Make sure they aren't null. OT_ASSERT(nullptr != dest); OT_ASSERT(nullptr != src); // Make sure they aren't the same pointer. OT_ASSERT(src != dest); // Make sure it will fit. OT_ASSERT_MSG(src_length <= dest_size, "ASSERT: safe_memcpy: destination buffer too small.\n"); // Make sure they don't overlap. // First assert does the beginning of the string, makes sure it's not within // the bounds of the destination // string. Second assert does the same thing for the end of the string. // Finally a third is needed to make sure // we're not in a situation where the beginning is less than the dest // beginning, yet the end is also more than // the dest ending! // OT_ASSERT_MSG( false == ((static_cast<const uint8_t*>(src) > static_cast<uint8_t*>(dest)) && (static_cast<const uint8_t*>(src) < (static_cast<uint8_t*>(dest) + dest_size))), "ASSERT: safe_memcpy: Unexpected memory overlap, start of src.\n"); OT_ASSERT_MSG( false == (((static_cast<const uint8_t*>(src) + src_length) > static_cast<uint8_t*>(dest)) && ((static_cast<const uint8_t*>(src) + src_length) < (static_cast<uint8_t*>(dest) + dest_size))), "ASSERT: safe_memcpy: Unexpected memory overlap, end of src.\n"); OT_ASSERT(false == ((static_cast<const uint8_t*>(src) <= static_cast<uint8_t*>(dest)) && ((static_cast<const uint8_t*>(src) + src_length) >= (static_cast<uint8_t*>(dest) + dest_size)))); #ifdef _WIN32 bool bSuccess = (0 == memcpy_s(dest, static_cast<size_t>(dest_size), src, static_cast<size_t>(src_length))); #else bool bSuccess = (memcpy(dest, src, static_cast<size_t>(src_length)) == dest); #endif if (bSuccess) { if (bZeroSource) { OTPassword::zeroMemory(const_cast<void*>(src), src_length); } return dest; } return nullptr; }
// static bool OTPaths::ConfirmCreateFolder(const String& strExactPath, bool& out_Exists, bool& out_IsNew) { const bool bExists = (strExactPath.Exists() && !strExactPath.Compare("")); OT_ASSERT_MSG( bExists, "OTPaths::ConfirmCreateFolder: Assert failed: no strFolderName\n"); std::string l_strExactPath(strExactPath.Get()); if ('/' != *l_strExactPath.rbegin()) return false; // not a directory. // Confirm If Directory Exists Already out_Exists = PathExists(strExactPath); if (out_Exists) { out_IsNew = false; return true; // Already Have Folder, lets return true! } else { // It dosn't exist: lets create it. #ifdef _WIN32 bool bCreateDirSuccess = (_mkdir(strExactPath.Get()) == 0); #else bool bCreateDirSuccess = (mkdir(strExactPath.Get(), 0700) == 0); #endif if (!bCreateDirSuccess) { otErr << "OTPaths::" << __FUNCTION__ << ": Unable To Confirm " "Created Directory " << strExactPath << ".\n"; out_IsNew = false; out_Exists = false; return false; } // At this point if the folder still doesn't exist, nothing we can do. // We // already tried to create the folder, and SUCCEEDED, and then STILL // failed // to find it (if this is still false.) else { bool bCheckDirExist = PathExists(strExactPath); if (!bCheckDirExist) { otErr << "OTPaths::" << __FUNCTION__ << ": " "Unable To Confirm Created Directory " << strExactPath << ".\n"; out_IsNew = false; out_Exists = false; return false; } else { out_IsNew = true; out_Exists = false; return true; // We have created and checked the Folder } } } }
// currently only "user" accounts (normal user asset accounts) are added to // this list Any "special" accounts, such as basket reserve accounts, or voucher // reserve accounts, or cash reserve accounts, are not included on this list. bool AssetContract::VisitAccountRecords(AccountVisitor& visitor) const { String strInstrumentDefinitionID, strAcctRecordFile; GetIdentifier(strInstrumentDefinitionID); strAcctRecordFile.Format("%s.a", strInstrumentDefinitionID.Get()); std::unique_ptr<OTDB::Storable> pStorable(OTDB::QueryObject( OTDB::STORED_OBJ_STRING_MAP, OTFolders::Contract().Get(), strAcctRecordFile.Get())); OTDB::StringMap* pMap = dynamic_cast<OTDB::StringMap*>(pStorable.get()); // There was definitely a StringMap loaded from local storage. // (Even an empty one, possibly.) This is the only block that matters in // this function. // if (nullptr != pMap) { Identifier* pNotaryID = visitor.GetNotaryID(); OT_ASSERT_MSG(nullptr != pNotaryID, "Assert: nullptr Notary ID on functor. " "(How did you even construct the " "thing?)"); auto& theMap = pMap->the_map; // todo: optimize: will probably have to use a database for this, // int64_t term. // (What if there are a million acct IDs in this flat file? Not // scaleable.) // for (auto& it : theMap) { const std::string& str_acct_id = it.first; // Containing the account ID. const std::string& str_instrument_definition_id = it.second; // Containing the instrument definition ID. (Just in // case // someone copied the wrong file here...) if (!strInstrumentDefinitionID.Compare( str_instrument_definition_id.c_str())) { otErr << "OTAssetContract::VisitAccountRecords: Error: wrong " "instrument definition ID (" << str_instrument_definition_id << ") when expecting: " << strInstrumentDefinitionID << "\n"; } else { Account* pAccount = nullptr; std::unique_ptr<Account> theAcctAngel; const Identifier theAccountID(str_acct_id.c_str()); // Before loading it from local storage, let's first make sure // it's not already loaded. // (visitor functor has a list of 'already loaded' accounts, // just in case.) // mapOfAccounts* pLoadedAccounts = visitor.GetLoadedAccts(); if (nullptr != pLoadedAccounts) // there are some accounts already loaded, { // let's see if the one we're looking for is there... auto found_it = pLoadedAccounts->find(str_acct_id); if (pLoadedAccounts->end() != found_it) // FOUND IT. { pAccount = found_it->second; OT_ASSERT(nullptr != pAccount); if (theAccountID != pAccount->GetPurportedAccountID()) { otErr << "Error: the actual account didn't have " "the ID that the std::map SAID it had! " "(Should never happen.)\n"; pAccount = nullptr; } } } // I guess it wasn't already loaded... // Let's try to load it. // if (nullptr == pAccount) { pAccount = Account::LoadExistingAccount(theAccountID, *pNotaryID); theAcctAngel.reset(pAccount); } bool bSuccessLoadingAccount = ((pAccount != nullptr) ? true : false); if (bSuccessLoadingAccount) { bool bTriggerSuccess = visitor.Trigger(*pAccount); if (!bTriggerSuccess) otErr << __FUNCTION__ << ": Error: Trigger Failed."; } else { otErr << __FUNCTION__ << ": Error: Failed Loading Account!"; } } } return true; } return true; }
int32_t main (int32_t argc, char **argv) { OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n" "(transport build: OTMessage -> TCP -> SSL)\n" "IF YOU PREFER TO USE XmlRpc with HTTP, then rebuild from main folder like this:\n\n" "cd ..; make clean; make rpc\n\n", OTLog::Version()); // ----------------------------------------------------------------------- // This object handles all the actual transaction notarization details. // (This file you are reading is a wrapper for OTServer, which adds the transport layer.) OTServer theServer; // ----------------------------------------------------------------------- #ifdef _WIN32 WSADATA wsaData; WORD wVersionRequested = MAKEWORD( 2, 2 ); int32_t err = WSAStartup( wVersionRequested, &wsaData ); /* Tell the user that we could not find a usable */ /* Winsock DLL. */ OT_ASSERT_MSG((err == 0), "WSAStartup failed!\n"); /* Confirm that the WinSock DLL supports 2.2. */ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ bool bWinsock = (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2); /* Tell the user that we could not find a usable */ /* WinSock DLL. */ if (!bWinsock) WSACleanup(); // do cleanup. OT_ASSERT_MSG((!bWinsock), "Could not find a usable version of Winsock.dll\n"); /* The Winsock DLL is acceptable. Proceed to use it. */ /* Add network programming using Winsock here */ /* then call WSACleanup when done using the Winsock dll */ OTLog::vOutput(0,"The Winsock 2.2 dll was found okay\n"); #endif OTLog::vOutput(0, "\n\nWelcome to Open Transactions, version %s.\n\n", OTLog::Version()); // ----------------------------------------------------------------------- // The beginnings of an INI file!! #ifndef _WIN32 // if UNIX (NOT windows) wordexp_t exp_result; wordexp(OT_INI_FILE_DEFAULT, &exp_result, 0); const OTString strIniFileDefault(exp_result.we_wordv[0]); wordfree(&exp_result); #else const OTString strIniFileDefault(OT_INI_FILE_DEFAULT); #endif OTString strPath(SERVER_PATH_DEFAULT); { CSimpleIniA ini; SI_Error rc = ini.LoadFile(strIniFileDefault.Get()); if (rc >=0) { const char * pVal = ini.GetValue("paths", "server_path", SERVER_PATH_DEFAULT); // todo stop hardcoding. if (NULL != pVal) { strPath.Set(pVal); OTLog::vOutput(0, "Reading ini file (%s). \n Found Server data_folder path: %s \n", strIniFileDefault.Get(), strPath.Get()); } else { strPath.Set(SERVER_PATH_DEFAULT); OTLog::vOutput(0, "Reading ini file (%s): \n Failed reading Server data_folder path. Using: %s \n", strIniFileDefault.Get(), strPath.Get()); } } else { strPath.Set(SERVER_PATH_DEFAULT); OTLog::vOutput(0, "Unable to load ini file (%s) to find data_folder path\n Will assume that server data_folder is at path: %s \n", strIniFileDefault.Get(), strPath.Get()); } } // ----------------------------------------------------------------------- OTString strCAFile, strDHFile, strKeyFile; //, strSSLPassword; if (argc < 1) { OTLog::vOutput(0, "\n==> USAGE: %s [absolute_path_to_data_folder]\n\n" // OTLog::vOutput(0, "\n==> USAGE: %s <SSL-password> [absolute_path_to_data_folder]\n\n" #if defined (FELLOW_TRAVELER) // "(Password defaults to '%s' if left blank.)\n" "(Folder defaults to '%s' if left blank.)\n" #else "The test password is always 'test'.\n" "OT will try to read the data_folder path from your ini file. If you prefer\n" "to specify it at the command line, and you want to see the exact path, type:\n" " cd data_folder && pwd && cd ..\n" #endif "\n\n", argv[0] #if defined (FELLOW_TRAVELER) // , KEY_PASSWORD, , strPath.Get() #endif ); #if defined (FELLOW_TRAVELER) // strSSLPassword.Set(KEY_PASSWORD); OTLog::SetMainPath(strPath.Get()); #else exit(1); #endif } else if (argc < 2) { // strSSLPassword.Set(argv[1]); OTLog::SetMainPath(strPath.Get()); } else { // strSSLPassword.Set(argv[1]); OTLog::SetMainPath(argv[1]); // formerly [2] } OTLog::vOutput(0, "Using as path to data folder: %s\n", OTLog::Path()); strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE); strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE); strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE); // ----------------------------------------------------------------------- // Init loads up server's nym so it can decrypt messages sent in envelopes. // It also does various other initialization work. // // (Envelopes prove that ONLY someone who actually had the server contract, // and had loaded it into his wallet, could ever connect to the server or // communicate with it. And if that person is following the contract, there // is only one server he can connect to, and one key he can use to talk to it.) OTLog::Output(0, "\n\nNow loading the server nym, which will also ask you for a password, to unlock\n" "its private key. (Default password is \"test\".)\n"); // Initialize SSL -- This MUST occur before any Private Keys are loaded! SFSocketGlobalInit(); // Any app that uses OT has to initialize SSL first. theServer.Init(); // Keys, etc are loaded here. // ----------------------------------------------------------------------- // We're going to listen on the same port that is listed in our server contract. // // OTString strHostname; // The hostname of this server, according to its own contract. int32_t nPort=0; // The port of this server, according to its own contract. OT_ASSERT_MSG(theServer.GetConnectInfo(strHostname, nPort), "Unable to find my own connect info (which is in my server contract BTW.)\n"); const int32_t nServerPort = nPort; // ----------------------------------------------------------------------- SFSocket *socket = NULL; listOfConnections theConnections; // Alloc Socket socket = SFSocketAlloc(); OT_ASSERT_MSG(NULL != socket, "SFSocketAlloc Failed\n"); // Initialize SSL Socket int32_t nSFSocketInit = SFSocketInit(socket, strCAFile.Get(), strDHFile.Get(), strKeyFile.Get(), strSSLPassword.Get(), NULL); OT_ASSERT_MSG(nSFSocketInit >= 0, "SFSocketInit Context Failed\n"); // Listen on Address/Port int32_t nSFSocketListen = SFSocketListen(socket, INADDR_ANY, nServerPort); OT_ASSERT_MSG(nSFSocketListen >= 0, "nSFSocketListen Failed\n"); theServer.ActivateCron(); do { SFSocket * clientSocket = NULL; // Accept Client Connection if (NULL != (clientSocket = SFSocketAccept(socket))) { OTClientConnection * pClient = new OTClientConnection(*clientSocket, theServer); theConnections.push_back(pClient); OTLog::Output(0, "Accepting new connection.\n"); } // READ THROUGH ALL CLIENTS HERE, LOOP A LIST // AND process in-buffer onto our list of messages. OTClientConnection * pConnection = NULL; for (listOfConnections::iterator ii = theConnections.begin(); ii != theConnections.end(); ++ii) { if (pConnection = *ii) { // Here we read the bytes from the pipe into the client's buffer // As necessary this function also processes those bytes into OTMessages // and adds them to the Input List for that client. pConnection->ProcessBuffer(); } } // Now loop through them all again, and process their messages onto the reply list. pConnection = NULL; for (listOfConnections::iterator ii = theConnections.begin(); ii != theConnections.end(); ++ii) { if (pConnection = *ii) { OTMessage * pMsg = NULL; while (pMsg = pConnection->GetNextInputMessage()) { OTMessage * pReply = new OTMessage; OT_ASSERT(NULL != pReply); if (theServer.ProcessUserCommand(*pMsg, *pReply, pConnection)) { OTLog::vOutput(0, "Successfully processed user command: %s.\n", pMsg->m_strCommand.Get()); pConnection->AddToOutputList(*pReply); } else { OTLog::Output(0, "Unable to process user command in XML, or missing payload, in main.\n"); delete pReply; pReply = NULL; } // I am responsible to delete this here. delete pMsg; pMsg = NULL; } } } // Now loop through them all again, and process their replies down the pipe pConnection = NULL; for (listOfConnections::iterator ii = theConnections.begin(); ii != theConnections.end(); ++ii) { if (pConnection = *ii) { OTMessage * pMsg = NULL; while (pMsg = pConnection->GetNextOutputMessage()) { pConnection->ProcessReply(*pMsg); // I am responsible to delete this here. delete pMsg; pMsg = NULL; } } } // The Server now processes certain things on a regular basis. // This method call is what gives it the opportunity to do that. theServer.ProcessCron(); // Now go to sleep for a tenth of a second. // (Main loop processes ten times per second, currently.) OTLog::SleepMilliseconds(100); // 100 ms == (1 second / 10) } while (1); // Close and Release Socket Resources SFSocketRelease(socket); #ifdef _WIN32 WSACleanup(); #endif return(0); }
bool OTASCIIArmor::GetString(OTString & theData, bool bLineBreaks) const //bLineBreaks=true { size_t outSize = 0; uint8_t * pData = NULL; theData.Release(); if (GetLength() < 1) { return true; } pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0)); if (pData) { long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.) unsigned char* pDest = new unsigned char [nDestLen+10]; // For safety. OT_ASSERT(NULL != pDest); int nErr = ezuncompress( pDest, &nDestLen, pData, outSize ); if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = new unsigned char [nDestLen]; // enough room now OT_ASSERT(NULL != pDest); nErr = ezuncompress( pDest, &nDestLen, pData, outSize ); } // Now we're done with this memory, let's free it. delete [] pData; pData=NULL; // ---------------------------------------- if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Buffer error in OTASCIIArmor::GetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_STREAM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "pDest is NULL in OTASCIIArmor::GetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_DATA_ERROR ) { delete [] pDest; pDest = NULL; OTLog::vError("corrupted pSrc passed to ezuncompress OTASCIIArmor::GetString, size: %d\n", outSize); OT_ASSERT(false); return false; // not really necessary but just making sure. } else if ( nErr == EZ_MEM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Out of memory in OTASCIIArmor::GetString\n"); return false; // not really necessary but just making sure. } // This enforces the null termination. (using the extra parameter nDestLen as nEnforcedMaxLength) theData.Set((const char*)pDest, nDestLen); delete [] pDest; pDest=NULL; return true; } else { OTLog::Error("NULL pData while base64_decodeing pData.\n"); return false; } }
//static size_t OTString::safe_strlen(const char * s, size_t max) { OT_ASSERT_MSG(max <= MAX_STRING_LENGTH, "OT_String::safe_strlen: ASSERT: max length passed in is longer than allowed.\n"); return strnlen(s, max); }
// NOTE: OpenSSL will store the EVP_PKEY inside the X509, and when I get it, // I'm not supposed to destroy the x509 until I destroy the EVP_PKEY FIRST! // (AND it reference-counts.) // Since I want ability to destroy the two, independent of each other, I made // static functions here for copying public and private keys, so I am ALWAYS // working with MY OWN copy of any given key, and not OpenSSL's reference-counted // one. // // Furthermore, BIO_mem_buf doesn't allocate its own memory, but uses the memory // you pass to it. You CANNOT free that memory until you destroy the BIO. // // That's why you see me copying one bio into a payload, before copying it into // the next bio. Todo security: copy it into an OTPassword here, instead of an // OTPayload, which is safer, and more appropriate for a private key. Make sure // OTPassword can accommodate a bit larger size than what it does now. // //static // CALLER must EVP_pkey_free! EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::CopyPrivateKey(EVP_PKEY & theKey, OTPasswordData * pPWData/*=NULL*/, OTPassword * pImportPassword/*=NULL*/) { const EVP_CIPHER * pCipher = EVP_des_ede3_cbc(); // todo should this algorithm be hardcoded? // ---------------------------------------- // Create a new memory buffer on the OpenSSL side OpenSSL_BIO bmem = BIO_new(BIO_s_mem()); OT_ASSERT(NULL != bmem); EVP_PKEY * pReturnKey = NULL; // ---------------------------------------- // write a private key to that buffer, from theKey // OTPasswordData thePWDataWrite("OTAsymmetricKey_OpenSSL::CopyPrivateKey is calling PEM_write_bio_PrivateKey..."); // todo optimization: might just remove the password callback here, and just write the private key in the clear, // and then load it up again, saving the encrypt/decrypt step that otherwise occurs, and then as long as we OpenSSL_cleanse // the BIO, then it SHOULD stil be safe, right? // int32_t nWriteBio = false; if (NULL == pImportPassword) nWriteBio = PEM_write_bio_PrivateKey(bmem, &theKey, pCipher, NULL, 0, OTAsymmetricKey::GetPasswordCallback(), NULL == pPWData ? &thePWDataWrite : pPWData); else nWriteBio = PEM_write_bio_PrivateKey(bmem, &theKey, pCipher, NULL, 0, 0, const_cast<void*>(reinterpret_cast<const void*>(pImportPassword->getPassword()))); // ------------------------------------------------------------------------ if (0 == nWriteBio) { OTLog::vError("%s: Failed writing EVP_PKEY to memory buffer.\n", __FUNCTION__); } else { OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", __FUNCTION__); char * pChar = NULL; // After the below call, pChar will point to the memory buffer where the private key supposedly is, // and lSize will contain the size of that memory. // const int64_t lSize = BIO_get_mem_data(bmem, &pChar); const uint32_t nSize = static_cast<uint32_t>(lSize); if (nSize > 0) { OTPayload theData; // Set the buffer size in our own memory. theData.SetPayloadSize(nSize); void * pv = OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination theData.GetSize(), // size of destination buffer. pChar, // source nSize); // length of source. // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done. if (NULL != pv) { // ----------------------------------------------- // Next, copy theData's contents into a new BIO_mem_buf, // so OpenSSL can load the key out of it. // OpenSSL_BIO keyBio = BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), theData.GetSize()); OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::CopyPrivateKey: Assert: NULL != keyBio \n"); // ------------------------------------------- // Next we load up the key from the BIO string into an instantiated key object. // OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::CopyPrivateKey is calling PEM_read_bio_PUBKEY..."); if (NULL == pImportPassword) pReturnKey = PEM_read_bio_PrivateKey( keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), NULL == pPWData ? &thePWData : pPWData); else pReturnKey = PEM_read_bio_PrivateKey( keyBio, NULL, 0, const_cast<void*>(reinterpret_cast<const void*>(pImportPassword->getPassword()))); // ------------------------------------------- } else OTLog::vError("%s: Error: Failed copying memory from BIO into OTPayload.\n"); // ------------------------------------------- } else { OTLog::vError("%s: Failed copying private key into memory.\n", __FUNCTION__); } } return pReturnKey; }
// Take a public key, theKey (input), and create an armored version of // it into ascKey (output.) // // OpenSSL loaded key ===> ASCII-Armored export of same key. // //static // bool OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::ArmorPublicKey(EVP_PKEY & theKey, OTASCIIArmor & ascKey) { bool bReturnVal = false; const char * szFunc = "OTAsymmetricKey_OpenSSL::ArmorPublicKey"; ascKey.Release(); // ---------------------------------------- // Create a new memory buffer on the OpenSSL side OpenSSL_BIO bmem = BIO_new(BIO_s_mem()); OT_ASSERT_MSG(NULL != bmem, "OTAsymmetricKey_OpenSSL::ArmorPublicKey: ASSERT: NULL != bmem"); int64_t lSize = 0; // ---------------------------------------- // write a public key to that buffer, from theKey (parameter.) // int32_t nWriteBio = PEM_write_bio_PUBKEY(bmem, &theKey); if (0 == nWriteBio) { OTLog::vError("%s: Error: Failed writing EVP_PKEY to memory buffer.\n", szFunc); } else { OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", szFunc); OTPayload theData; char * pChar = NULL; // After the below call, pChar will point to the memory buffer where the public key // supposedly is, and lSize will contain the size of that memory. // lSize = BIO_get_mem_data(bmem, &pChar); uint32_t nSize = static_cast<uint32_t>(lSize); // todo security, etc. Fix this assumed type conversion. if (nSize > 0) { // Set the buffer size in our own memory. theData.SetPayloadSize(nSize); // void * pv = OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination theData.GetSize(), // size of destination buffer. pChar, // source nSize); // length of source. // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done. // ------------------------------------------------ // This base64 encodes the public key data // ascKey.SetData(theData); OTLog::vOutput(5, "%s: Success copying public key into memory.\n", szFunc); bReturnVal = true; } else { OTLog::vError("%s: Failed copying public key into memory.\n", szFunc); } } return bReturnVal; }
const bool OTPaths::ToReal(const OTString & strExactPath, OTString & out_strCanonicalPath) { if (!strExactPath.Exists()) { OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strExactPath"); OT_ASSERT(false); } #ifdef _WIN32 #ifdef _UNICODE const char * szPath = strExactPath.Get(); size_t newsize = strlen(szPath) + 1; wchar_t * wzPath = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wzPath, newsize, szPath,4096); wchar_t szBuf[4096]= L""; if(GetFullPathName(wzPath,4096,szBuf,NULL)) { out_strCanonicalPath.Set(utf8util::UTF8FromUTF16(szBuf)); return true; } else { out_strCanonicalPath.Set(""); return false; } #else char_t szBuf[4096]=""; char_t const * szPath = strRealPath.Get(); if(GetFullPathName(szPath,4096,szBuf,NULL)) { out_strCanonicalPath.Set(szBuf); return true; } else { out_strCanonicalPath.Set(""); return false; } #endif #else long path_max=0; #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf("/", _PC_PATH_MAX); if (path_max <= 0) path_max = 4096; #endif char actualpath [path_max+1]; actualpath[0] = '\0'; char *ptr=NULL; if (NULL == realpath(strExactPath.Get(), actualpath)) { if (errno == ENOTDIR) { OTLog::vOutput(1,"Input value to RealPath is not a directory: (Realpath: skipping)\n"); out_strCanonicalPath.Set(strExactPath); return true; } if (errno == ENOENT) { OTLog::vOutput(1,"File doesn't exist: (Realpath: skipping)\n"); out_strCanonicalPath.Set(strExactPath); return true; } OT_ASSERT_MSG((errno != EACCES),"Error (Realpath: EACCES): Unable to build RealPath: access denied"); OT_ASSERT_MSG((errno != EINVAL),"Error (RealPath: EINVAL): Input value into RealPath was NULL"); OT_ASSERT_MSG((errno != ELOOP),"Error (RealPath: ELOOP): Resloving links resulted in a loop."); OT_ASSERT_MSG((errno != ENAMETOOLONG),"Error (RealPath: ENAMETOOLONG): Name too long."); OT_ASSERT_MSG((errno != ERANGE),"Error (RealPath: ERANGE): Resulting path is too long for the buffer"); OT_ASSERT_MSG((errno != EIO),"Error (RealPath: EIO): Unable to access path."); OT_ASSERT_MSG((false),"Error (RealPath: OTHER): Something bad Happend with 'realpath'."); } out_strCanonicalPath.Set(actualpath); return true; #endif }
//static // CALLER must EVP_pkey_free! EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::CopyPublicKey(EVP_PKEY & theKey, OTPasswordData * pPWData/*=NULL*/, OTPassword * pImportPassword/*=NULL*/) { // ---------------------------------------- // Create a new memory buffer on the OpenSSL side OpenSSL_BIO bmem = BIO_new(BIO_s_mem()); OT_ASSERT_MSG(NULL != bmem, "OTAsymmetricKey_OpenSSL::CopyPublicKey: ASSERT: NULL != bmem"); EVP_PKEY * pReturnKey = NULL; // ---------------------------------------- // write a public key to that buffer, from theKey (parameter.) // int32_t nWriteBio = PEM_write_bio_PUBKEY(bmem, &theKey); if (0 == nWriteBio) { OTLog::vError("%s: Error: Failed writing EVP_PKEY to memory buffer.\n", __FUNCTION__); } else { OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", __FUNCTION__); char * pChar = NULL; // After the below call, pChar will point to the memory buffer where the public key // supposedly is, and lSize will contain the size of that memory. // const int64_t lSize = BIO_get_mem_data(bmem, &pChar); const uint32_t nSize = static_cast<uint32_t>(lSize); if (nSize > 0) { OTPayload theData; // Set the buffer size in our own memory. theData.SetPayloadSize(nSize); void * pv = OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination theData.GetSize(), // size of destination buffer. pChar, // source nSize); // length of source. // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done. if (NULL != pv) { // ----------------------------------------------- // Next, copy theData's contents into a new BIO_mem_buf, // so OpenSSL can load the key out of it. // OpenSSL_BIO keyBio = BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), theData.GetSize()); OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::CopyPublicKey: Assert: NULL != keyBio \n"); // ------------------------------------------- // Next we load up the key from the BIO string into an instantiated key object. // OTPasswordData thePWData(NULL == pImportPassword ? "Enter your wallet master passphrase. (OTAsymmetricKey_OpenSSL::CopyPublicKey is calling PEM_read_bio_PUBKEY...)" : "Enter the passphrase for your exported Nym."); if (NULL == pImportPassword) pReturnKey = PEM_read_bio_PUBKEY(keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), NULL == pPWData ? &thePWData : pPWData); else pReturnKey = PEM_read_bio_PUBKEY(keyBio, NULL, 0, pImportPassword); // ------------------------------------------- // We don't need the BIO anymore. // Free the BIO and related buffers, filters, etc. (auto with scope). // } else OTLog::vError("%s: Error: Failed copying memory from BIO into OTPayload.\n"); // ------------------------------------------- } else { OTLog::vError("%s: Failed copying private key into memory.\n", __FUNCTION__); } } return pReturnKey; }
// return -1 if error, 0 if nothing, and 1 if the node was processed. int OTBasket::ProcessXMLNode(irr::io::IrrXMLReader*& xml) { if (!strcmp("currencyBasket", xml->getNodeName())) { OTString strSubCount, strMinTrans; strSubCount = xml->getAttributeValue("contractCount"); strMinTrans = xml->getAttributeValue("minimumTransfer"); m_nSubCount = atoi(strSubCount.Get()); m_lMinimumTransfer = atol(strMinTrans.Get()); OTLog::Output(1, "Loading currency basket...\n"); return 1; } else if (!strcmp("requestExchange", xml->getNodeName())) { OTString strTransferMultiple, strRequestAccountID, strDirection, strTemp; strTransferMultiple = xml->getAttributeValue("transferMultiple"); strRequestAccountID = xml->getAttributeValue("transferAccountID"); strDirection = xml->getAttributeValue("direction"); strTemp = xml->getAttributeValue("closingTransactionNo"); if (strTransferMultiple.Exists()) m_nTransferMultiple = atoi(strTransferMultiple.Get()); if (strRequestAccountID.Exists()) m_RequestAccountID.SetString(strRequestAccountID); if (strDirection.Exists()) m_bExchangingIn = strDirection.Compare("in"); if (strTemp.Exists()) SetClosingNum(atol( strTemp.Get() )); OTLog::vOutput(2, "Basket Transfer multiple is %d. Direction is %s. Closing number is %ld. " "Target account is:\n%s\n", m_nTransferMultiple, strDirection.Get(), m_lClosingTransactionNo, strRequestAccountID.Get()); return 1; } else if (!strcmp("basketItem", xml->getNodeName())) { BasketItem * pItem = new BasketItem; OT_ASSERT_MSG(NULL != pItem, "Error allocating memory in OTBasket::ProcessXMLNode\n"); OTString strTemp; strTemp = xml->getAttributeValue("minimumTransfer"); if (strTemp.Exists()) pItem->lMinimumTransferAmount = atol( strTemp.Get() ); strTemp = xml->getAttributeValue("closingTransactionNo"); if (strTemp.Exists()) pItem->lClosingTransactionNo = atol( strTemp.Get() ); OTString strSubAccountID(xml->getAttributeValue("accountID")), strContractID(xml->getAttributeValue("assetID")); pItem->SUB_ACCOUNT_ID.SetString(strSubAccountID); pItem->SUB_CONTRACT_ID.SetString(strContractID); m_dequeItems.push_back(pItem); OTLog::Output(2, "Loaded basket item.\n"); return 1; } return 0; }
// ********************************************************************************************************* // // // *** SERVER MAIN *** // // // The MAIN function for the server software, which starts up the ZMQ listener, as well // as well as the Open Transactions library and the OT Server object. // // After initialization, this function becomes the "main loop" of OT server. // int main(int argc, char* argv[]) { OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n" "(transport build: OTMessage -> OTEnvelope -> ZMQ )\n\n", OTLog::Version()); // WINSOCK WINDOWS // ----------------------------------------------------------------------- #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; int err; /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { /* Tell the user that we could not find a usable */ /* Winsock DLL. */ printf("WSAStartup failed with error: %d\n", err); return 1; } /* Confirm that the WinSock DLL supports 2.2. */ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ printf("Could not find a usable version of Winsock.dll\n"); WSACleanup(); return 1; } else printf("The Winsock 2.2 dll was found okay\n"); /* The Winsock DLL is acceptable. Proceed to use it. */ /* Add network programming using Winsock here */ /* then call WSACleanup when done using the Winsock dll */ #endif // *********************************************************************** // INITIALIZATION and CLEANUP (for the OT library, and for this server application.) // class __ot_server_ { OTServer * m_pServer; public: OTServer * GetServer() { return m_pServer; } // ----------------------------------- __ot_server_() : m_pServer(NULL) // INIT { // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- // OTLog class exists on both client and server sides. // #define OT_NO_SIGNAL_HANDLING if you want to turn off OT's signal handling. // #if defined(OT_SIGNAL_HANDLING) OTLog::SetupSignalHandler(); // This is optional! (I, of course, am using it in this test app...) #endif // ----------------------------------------------------------------------- // I instantiate this here (instead of globally) so that I am assured that any globals and other // setup is already done before we instantiate the server object itself. // OT_ASSERT_MSG(NULL == m_pServer, "server main(): ASSERT: NULL == m_pServer."); m_pServer = new OTServer; // // (This .cpp file you are currently reading is a wrapper for OTServer, // which adds the transport layer.) // OT_ASSERT_MSG(NULL != m_pServer, "server main(): ASSERT: Unable to instantiate OT server.\n"); OTString pathUserAppDataPath, pathIniFileLocation; pathUserAppDataPath = GetRoamingAppDataLocation(); pathIniFileLocation.Format("%s%s%s", pathUserAppDataPath.Get(), OTLog::PathSeparator(), SERVER_INI_FILE_DEFAULT); OTString pathOTServerDataLocation; OTLog::vOutput(0, "\nFound ot_init.cfg in: \n %s \nNow checking to see if it contains the OT Server path...", pathIniFileLocation.Get()); // Read the File, If successful use result if (false == GetOTAppDataFolderLocation(pathIniFileLocation, pathOTServerDataLocation)) { OTLog::vOutput(0, "Path not found... Will attempt default!... \n"); // Not successfull will will assume it is in default location: pathOTServerDataLocation.Format("%s%s%s", pathUserAppDataPath.Get(), OTLog::PathSeparator(), SERVER_PATH_DEFAULT); }; OTLog::vOutput(0, " %s \n", pathOTServerDataLocation.Get()); OTLog::SetMainPath(pathOTServerDataLocation.Get()); // <============ SET MAIN PATH OTLog::vOutput(0, "Using server_data path: %s\n", OTLog::Path()); // ----------------------------------------------------------------------- OTCrypto::It()->Init(); // <========== (OpenSSL gets initialized here.) } // **************************************** // ~__ot_server_() // CLEANUP { OTLog::vOutput(0, "\n\n OT version %s, shutting down and cleaning up.\n", OTLog::Version()); // ------------------------------ if (NULL != m_pServer) delete m_pServer; m_pServer = NULL; // ------------------------------ // We clean these up in reverse order from the Init function, which just seems // like the best default, in absence of any brighter ideas. // OTCrypto::It()->Cleanup(); // <======= (OpenSSL gets cleaned up here.) // ------------------------- // (This is at the bottom, since we do the cleanup in the // reverse order from initialization.) #ifdef _WIN32 WSACleanup(); #endif } }; // *********************************************************************** // // INSTANTIATE and INITIALIZE... // // (Cleanup happens automatically when this object goes out of scope.) // __ot_server_ the_server_obj; OTServer * pServer = the_server_obj.GetServer(); OT_ASSERT(NULL != pServer); // ----------------------------------------------------------------------- // OTString strCAFile, strDHFile, strKeyFile; //, strSSLPassword; // strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE); // strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE); // strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE); // ----------------------------------------------------------------------- // // UPDATE: This was moved to OTLog::OT_Init(), which is called above, by the // nested cleanup class. // // Initialize SSL -- This MUST occur before any Private Keys are loaded! // SSL_library_init(); // SSL_load_error_strings(); // ----------------------------------------------------------------------- // OTServer::Init loads up server's nym so it can decrypt messages sent in // envelopes. It also does various other initialization work. // // (Envelopes prove that ONLY someone who actually had the server contract, // and had loaded it into his wallet, could ever connect to the server or // communicate with it. And if that person is following the contract, there // is only one server he can connect to, and one key he can use to talk to it.) // OTLog::vOutput(0, "\nNow loading the server nym, which will also ask you for a password, to unlock\n" "its private key. (Default password is \"%s\".)\n", KEY_PASSWORD); pServer->Init(); // Keys, etc are loaded here. ===> Assumes main path is set! <=== // ----------------------------------------------------------------------- // We're going to listen on the same port that is listed in our server contract. // // OTString strHostname; // The hostname of this server, according to its own contract. int nPort=0; // The port of this server, according to its own contract. const bool bConnectInfo = pServer->GetConnectInfo(strHostname, nPort); OT_ASSERT_MSG(bConnectInfo, "server main: Unable to find my own connect info (which SHOULD be in my server contract, BTW.) Perhaps you failed trying to open that contract? Have you tried the test password? (\"test\")\n"); const int nServerPort = nPort; // ----------------------------------------------------------------------- // OT CRON // // A heartbeat for recurring transactions, such as markets, payment plans, // and smart contracts. pServer->ActivateCron(); // NOTE: Currently we trigger OT Cron's processing internally, but there's no reason why, in the // future, we can't make an actual cron job that triggers a script, that fires a message // to OT, causing OT to process its Cron (even if we were single-threaded we could do this...) // // Have to put some thought into it... // // Wouldn't require much security, since OT can still be smart enough not to process cron any // more often than X minutes, no matter HOW many times the ProcessCron script fires. // Thing is, though, that with this setup, we can't really guarantee that cron will EVER be // triggered -- whereas the way OT is now, at least we know it WILL fire every X seconds. // // -------------------------------------- // // NETWORK // // Prepare our context and listening socket... OTSocket theSocket; OTString strBindPath; strBindPath.Format("%s%d", "tcp://*:", nServerPort); theSocket.Listen(strBindPath); // ****************************************************************************************** // // *** MAIN LOOP *** // do // --------------------------- { // =-=-=- HEARTBEAT -=-=-= // // The Server now processes certain things on a regular basis. // ProcessCron is what gives it the opportunity to do that. // All of the Cron Items (including market trades, payment plans, smart contracts...) // they all have their hooks here... // pServer->ProcessCron(); // Internally this is smart enough to know how often to actually activate itself. // Most often it just returns doing nothing (waiting for its timer.) // ----------------------------------------------------------------------- // Wait for client http requests (and process replies out to them.) // ---------------------------------------------------------------------- // Number of requests to process per heartbeat: OTServer::GetHeartbeatNoRequests() // // Loop: process up to 10 client requests, then sleep for 1/10th second. // That's a total of 100 requests per second. Can the computers handle it? // Is it too much or too little? Todo: load testing. // // Then: check for shutdown flag. // // Then: go back to the top ("do") and repeat the loop.... process cron, // process 10 client requests, sleep, check for shutdown, etc. // // Timer t; // start timer t.start(); const double tick1 = t.getElapsedTimeInMilliSec(); // ----------------------------------------------------- // // PROCESS X NUMBER OF REQUESTS (THIS PULSE.) // // Theoretically the "number of requests" that we process EACH PULSE. // (The timing code here is still pretty new, need to do some load testing.) // for (int i = 0; i < /*10*/OTServer::GetHeartbeatNoRequests(); i++) { std::string str_Message; // With 100ms heartbeat, receive will try 100 ms, then 200 ms, then 400 ms, total of 700. // That's about 15 Receive() calls every 10 seconds. Therefore if I want the ProcessCron() // to trigger every 10 seconds, I need to set the cron interval to roll over every 15 heartbeats. // Therefore I will be using a real Timer for Cron, instead of the damn intervals. // bool bReceived = theSocket.Receive(str_Message); if (bReceived) { std::string str_Reply; // Output. if (str_Message.length() <= 0) { OTLog::Error("server main: Received a message, but of 0 length or less. Weird. (Skipping it.)\n"); } else // ------------------------------------ { // true == YES, DISCONNECT m_pSocket, something must have gone wrong. // false == NO, do NOT disconnect m_pSocket, everything went wonderfully! // const bool bShouldDisconnect = ProcessMessage_ZMQ(*pServer, str_Message, str_Reply); // <================== PROCESS the message! // -------------------------------------------------- if ((str_Reply.length() <= 0) || bShouldDisconnect) { OTLog::vOutput(0, "server main: ERROR: Unfortunately, not every client request is " "legible or worthy of a server response. :-) " "Msg:\n\n%s\n\n", str_Message.c_str()); theSocket.Listen(); } else { bool bSuccessSending = theSocket.Send(str_Reply); // <===== SEND THE REPLY if (false == bSuccessSending) OTLog::vError("server main: Socket ERROR: failed while trying to send reply " "back to client! \n\n MESSAGE:\n%s\n\nREPLY:\n%s\n\n", str_Message.c_str(), str_Reply.c_str()); // -------------------------------------------------- } } } } // for // ----------------------------------------------------------------------- // // IF the time we had available wasn't all used up -- if some of it is still // available, then SLEEP until we reach the NEXT PULSE. (In practice, we will // probably use TOO MUCH time, not too little--but then again OT isn't ALWAYS // processing a message. There could be plenty of dead time in between...) // const double tick2 = t.getElapsedTimeInMilliSec(); const long elapsed = static_cast<long>(tick2 - tick1); long lSleepMS = 0; if (elapsed < /*100*/OTServer::GetHeartbeatMsBetweenBeats()) { lSleepMS = OTServer::GetHeartbeatMsBetweenBeats() - elapsed; // Now go to sleep. // (The main loop processes ten times per second, currently.) OTLog::SleepMilliseconds(lSleepMS); // 100 ms == (1 second / 10) } // ----------------------------------------------------------------------- // ARTIFICIAL LIMIT: // 10 requests per heartbeat, 10 rounds per second == 100 requests per second. // // *** ONE HUNDRED CLIENT MESSAGES PER SECOND is the same as: // // 6000 PER MINUTE == 360,000 PER HOUR == 8,640,000 PER DAY*** // // Speeding it up is just a matter of adjusting the above numbers, and LOAD TESTING, // to see if OT can handle it. (Not counting optimization of course.) // // ----------------------------------------------------------------------- if (pServer->IsFlaggedForShutdown()) { OTLog::Output(0, "main: OT Server is shutting down gracefully....\n"); break; } } while (1); // (MAIN LOOP) // ------------------------------------ return 0; }
bool OTSocket::Receive(std::string & str_Message) { OT_ASSERT_MSG(NULL != m_pContext, "m_pContext == NULL in OTSocket::Receive()"); OT_ASSERT_MSG(NULL != m_pSocket, "m_pSocket == NULL in OTSocket::Receive()"); // ----------------------------------- const long lLatencyRecvMilliSec = OTLog::GetLatencyReceiveMs(); const long lLatencyRecvMicroSec = lLatencyRecvMilliSec*1000; // *********************************** // Get the request. zmq::message_t request; bool bSuccessReceiving = false; // If failure receiving, re-tries 2 times, with 4000 ms max delay between each (Doubling every time.) // if (OTLog::IsBlocking()) { bSuccessReceiving = m_pSocket->recv(&request); // Blocking. } else // not blocking { long lDoubling = lLatencyRecvMicroSec; int nReceiveTries = OTLog::GetLatencyReceiveNoTries(); bool expect_request = true; while (expect_request) { // Poll socket for a request, with timeout zmq::pollitem_t items[] = { { *m_pSocket, 0, ZMQ_POLLIN, 0 } }; const int nPoll = zmq::poll (&items[0], 1, lDoubling); lDoubling *= 2; // 100 ms, then 200 ms, then 400 ms == total of 700 ms per receive. (About 15 per 10 seconds.) // If we got a request, process it if (items[0].revents & ZMQ_POLLIN) { bSuccessReceiving = m_pSocket->recv(&request, ZMQ_NOBLOCK); // <=========== RECEIVE =============== OTLog::SleepMilliseconds( 1 ); if (!bSuccessReceiving) { if (false == HandleReceivingError()) expect_request = false; } else break; // (Success -- we're done in this loop.) } else if (nReceiveTries == 0) { // OTLog::Error("OTSocket::Receive: Tried to receive, based on polling data, but failed even after retries.\n"); expect_request = false; break; } else if ((-1) == nPoll) // error. { if (false == HandlePollingError()) expect_request = false; } --nReceiveTries; } } // *********************************** if (bSuccessReceiving && (request.size() > 0)) { str_Message.reserve(request.size()); str_Message.append(static_cast<const char *>(request.data()), request.size()); } return (bSuccessReceiving && (request.size() > 0)); }
int main (int argc, char **argv) { OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n" "(transport build: OTMessage -> TCP -> SSL)\n" "NOTE: IF YOU PREFER TO USE XmlRpc with Http transport, then rebuild using:\n" "\"make -f Makefile.rpc\" (but make sure the client is built the same way.)\n\n", OTLog::Version()); // ----------------------------------------------------------------------- // This object handles all the actual transaction notarization details. // (This file you are reading is a wrapper for OTServer, which adds the transport layer.) OTServer theServer; // ----------------------------------------------------------------------- #ifdef _WIN32 WSADATA wsaData; WORD wVersionRequested = MAKEWORD( 2, 2 ); int nWSA = WSAStartup( wVersionRequested, &wsaData ); OT_ASSERT_MSG(0 != nWSA, "Error calling WSAStartup.\n"); #endif OTLog::vOutput(0, "\n\nWelcome to Open Transactions, version %s.\n\n", OTLog::Version()); // ----------------------------------------------------------------------- OTString strCAFile, strDHFile, strKeyFile, strSSLPassword; if (argc < 2) { OTLog::vOutput(0, "Usage: transaction <SSL-password> <data_folder path>\n\n" "(Password defaults to '%s' if left blank on the command line.)\n" "(Folder defaults to '%s' if left blank.)\n", KEY_PASSWORD, SERVER_PATH_DEFAULT); strSSLPassword.Set(KEY_PASSWORD); OTLog::SetMainPath(SERVER_PATH_DEFAULT); } else if (argc < 3) { OTLog::vOutput(0, "Usage: transaction <SSL-password> <data_folder path>\n\n" "(Folder defaults to '%s' if left blank.)\n", SERVER_PATH_DEFAULT); strSSLPassword.Set(argv[1]); OTLog::SetMainPath(SERVER_PATH_DEFAULT); } else { strSSLPassword.Set(argv[1]); OTLog::SetMainPath(argv[2]); } strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE); strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE); strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE); // ----------------------------------------------------------------------- // Init loads up server's nym so it can decrypt messages sent in envelopes. // It also does various other initialization work. // // (Envelopes prove that ONLY someone who actually had the server contract, // and had loaded it into his wallet, could ever connect to the server or // communicate with it. And if that person is following the contract, there // is only one server he can connect to, and one key he can use to talk to it.) OTLog::Output(0, "\n\nNow loading the server nym, which will also ask you for a password, to unlock\n" "its private key. (Default password is \"test\".)\n"); // Initialize SSL -- This MUST occur before any Private Keys are loaded! SFSocketGlobalInit(); // Any app that uses OT has to initialize SSL first. theServer.Init(); // Keys, etc are loaded here. // ----------------------------------------------------------------------- // We're going to listen on the same port that is listed in our server contract. // // OTString strHostname; // The hostname of this server, according to its own contract. int nPort=0; // The port of this server, according to its own contract. OT_ASSERT_MSG(theServer.GetConnectInfo(strHostname, nPort), "Unable to find my own connect info (which is in my server contract BTW.)\n"); const int nServerPort = nPort; // ----------------------------------------------------------------------- SFSocket *socket = NULL; listOfConnections theConnections; // Alloc Socket socket = SFSocketAlloc(); OT_ASSERT_MSG(NULL != socket, "SFSocketAlloc Failed\n"); // Initialize SSL Socket int nSFSocketInit = SFSocketInit(socket, strCAFile.Get(), strDHFile.Get(), strKeyFile.Get(), strSSLPassword.Get(), NULL); OT_ASSERT_MSG(nSFSocketInit >= 0, "SFSocketInit Context Failed\n"); // Listen on Address/Port int nSFSocketListen = SFSocketListen(socket, INADDR_ANY, nServerPort); OT_ASSERT_MSG(nSFSocketListen >= 0, "nSFSocketListen Failed\n"); theServer.ActivateCron(); do { SFSocket * clientSocket = NULL; // Accept Client Connection if (NULL != (clientSocket = SFSocketAccept(socket))) { OTClientConnection * pClient = new OTClientConnection(*clientSocket, theServer); theConnections.push_back(pClient); OTLog::Output(0, "Accepting new connection.\n"); } // READ THROUGH ALL CLIENTS HERE, LOOP A LIST // AND process in-buffer onto our list of messages. OTClientConnection * pConnection = NULL; for (listOfConnections::iterator ii = theConnections.begin(); ii != theConnections.end(); ++ii) { if (pConnection = *ii) { // Here we read the bytes from the pipe into the client's buffer // As necessary this function also processes those bytes into OTMessages // and adds them to the Input List for that client. pConnection->ProcessBuffer(); } } // Now loop through them all again, and process their messages onto the reply list. pConnection = NULL; for (listOfConnections::iterator ii = theConnections.begin(); ii != theConnections.end(); ++ii) { if (pConnection = *ii) { OTMessage * pMsg = NULL; while (pMsg = pConnection->GetNextInputMessage()) { OTMessage * pReply = new OTMessage; OT_ASSERT(NULL != pReply); if (theServer.ProcessUserCommand(*pMsg, *pReply, pConnection)) { OTLog::vOutput(0, "Successfully processed user command: %s.\n", pMsg->m_strCommand.Get()); pConnection->AddToOutputList(*pReply); } else { OTLog::Output(0, "Unable to process user command in XML, or missing payload, in main.\n"); delete pReply; pReply = NULL; } // I am responsible to delete this here. delete pMsg; pMsg = NULL; } } } // Now loop through them all again, and process their replies down the pipe pConnection = NULL; for (listOfConnections::iterator ii = theConnections.begin(); ii != theConnections.end(); ++ii) { if (pConnection = *ii) { OTMessage * pMsg = NULL; while (pMsg = pConnection->GetNextOutputMessage()) { pConnection->ProcessReply(*pMsg); // I am responsible to delete this here. delete pMsg; pMsg = NULL; } } } // The Server now processes certain things on a regular basis. // This method call is what gives it the opportunity to do that. theServer.ProcessCron(); // Now go to sleep for a tenth of a second. // (Main loop processes ten times per second, currently.) OTLog::SleepMilliseconds(100); // 100 ms == (1 second / 10) } while (1); // Close and Release Socket Resources SFSocketRelease(socket); #ifdef _WIN32 WSACleanup(); #endif return(0); }
EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::InstantiatePrivateKey(OTPasswordData * pPWData/*=NULL*/) { OT_ASSERT(m_pKey == NULL); OT_ASSERT(backlink->m_p_ascKey != NULL); OT_ASSERT(backlink->IsPrivate()); // ------------------------------ EVP_PKEY * pReturnKey = NULL; OTPayload theData; // after base64-decoding the ascii-armored string, the (encrypted) binary will be stored here. // -------------------------------------- // This line base64 decodes the ascii-armored string into binary object theData... // backlink->m_p_ascKey->GetData(theData); // theData now contains binary data, the encrypted private key itself, no longer in text-armoring. // // Note, for future optimization: the ASCII-ARMORING could be used for serialization, but the BIO (still encrypted) // could be used in RAM for this object. Otherwise you just have to do the extra step of ascii-decoding it first to get // the BIO, before being able to instantiate the key itself from that. That final step can't change, but I can remove // the step before it, in most cases, by just storing the BIO itself, instead of the ascii-armored string. Or perhaps // make them both available...hm. // -------------------------------------- // Copy the encrypted binary private key data into an OpenSSL memory BIO... // if (theData.GetSize() > 0) { OpenSSL_BIO keyBio = BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), theData.GetSize()); // theData will zeroMemory upon destruction. OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::InstantiatePrivateKey: Assert: NULL != keyBio \n"); // -------------------------------------- // Here's thePWData we use if we didn't have anything else: // OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::InstantiatePrivateKey is calling PEM_read_bio_PrivateKey..."); if (NULL == pPWData) pPWData = &thePWData; pReturnKey = PEM_read_bio_PrivateKey( keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), pPWData ); // Free the BIO and related buffers, filters, etc. backlink->ReleaseKeyLowLevel(); // -------------------------------------- if (NULL != pReturnKey) { m_pKey = pReturnKey; // TODO (remove theTimer entirely. OTCachedKey replaces already.) // I set this timer because the above required a password. But now that master key is working, // the above would flow through even WITHOUT the user typing his passphrase (since master key still // not timed out.) Resulting in THIS timer being reset! Todo: I already shortened this timer to 30 // seconds, but need to phase it down to 0 and then remove it entirely! Master key takes over now! // backlink->m_timer.start(); // Note: this isn't the ultimate timer solution. See notes in ReleaseKeyLowLevel. OTLog::vOutput(4, "%s: Success reading private key from ASCII-armored data.\n\n", __FUNCTION__); // OTLog::vOutput(4, "%s: Success reading private key from ASCII-armored data:\n\n%s\n\n", // __FUNCTION__, m_p_ascKey->Get()); return m_pKey; } } OTLog::vError("%s: Failed reading private key from ASCII-armored data.\n\n", __FUNCTION__); // OTLog::vError("%s: Failed reading private key from ASCII-armored data:\n\n%s\n\n", // __FUNCTION__, m_p_ascKey->Get()); return NULL; }
/// if we pack, compress, encode on the way in, that means, therefore, we /// need to decode, uncompress, then unpack on our way out. Right? /// /// This function will base64-DECODE the string contents, then uncompress them using /// zlib, and then unpack the result using whatever is the default packer (MsgPack, Protobuf, etc). /// /// I originally added compression because message sizes were too big. Now I'm adding packing, /// to solve any issues of binary compatibility across various platforms. // bool OTASCIIArmor::GetAndUnpackString(OTString & strData, bool bLineBreaks) const //bLineBreaks=true { size_t outSize = 0; uint8_t * pData = NULL; strData.Release(); if (GetLength() < 1) { return true; } // -------------------------------------------------------------- // pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0)); if (pData) { // ------------------------------------------- // EASY ZLIB // long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.) unsigned char* pDest = new unsigned char [nDestLen+10]; // For safety. OT_ASSERT(NULL != pDest); int nErr = ezuncompress( pDest, &nDestLen, pData, static_cast<long> (outSize) ); if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = new unsigned char [nDestLen]; // enough room now OT_ASSERT(NULL != pDest); nErr = ezuncompress( pDest, &nDestLen, pData, static_cast<long> (outSize) ); } // Now we're done with this memory, let's free it. delete [] pData; pData=NULL; // ---------------------------------------- if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Buffer error in OTASCIIArmor::GetAndUnpackString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_STREAM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "pDest is NULL in OTASCIIArmor::GetAndUnpackString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_DATA_ERROR ) { delete [] pDest; pDest = NULL; OTLog::vError("corrupted pSrc passed to ezuncompress OTASCIIArmor::GetAndUnpackString, size: %d\n", outSize); OT_ASSERT(false); return false; // not really necessary but just making sure. } else if ( nErr == EZ_MEM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Out of memory in OTASCIIArmor::GetAndUnpackString\n"); return false; // not really necessary but just making sure. } // --------------------------------------- // PUT THE PACKED BUFFER HERE, AND UNPACK INTO strData // -------------------------------------------------------- OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either. OTDB::PackedBuffer * pBuffer = pPacker->CreateBuffer(); // Need to clean this up. OT_ASSERT(NULL != pBuffer); OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // This will make sure buffer is deleted later. const size_t theDestLen = nDestLen; pBuffer->SetData(pDest, // const unsigned char * theDestLen); delete [] pDest; pDest=NULL; // ----------------------------- OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING)); OT_ASSERT(NULL != pOTDBString); OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // clean up this string. bool bUnpacked = pPacker->Unpack(*pBuffer, *pOTDBString); // ---------------------- if (false == bUnpacked) { OTLog::Error("Failed unpacking string in OTASCIIArmor::GetAndUnpackString.\n"); return false; } // -------------------------------------------------------- // This enforces the null termination. (using the 2nd parameter as nEnforcedMaxLength) strData.Set(pOTDBString->m_string.c_str(), static_cast<uint32_t> (pOTDBString->m_string.length())); return true; } else { OTLog::Error("OTASCIIArmor::GetAndUnpackString: NULL pData while base64-decoding pData.\n"); return false; } }
__OTcreatemint_RAII() { if(!OTLog::Init(SERVER_CONFIG_KEY,0)) { assert(false); }; // setup the logger. OTLog::vOutput(0, "\n\nWelcome to Open Transactions -- 'createmint', version %s\n", OTLog::Version()); // ------------------------------------ #ifdef _WIN32 WSADATA wsaData; WORD wVersionRequested = MAKEWORD( 2, 2 ); int err = WSAStartup( wVersionRequested, &wsaData ); /* Tell the user that we could not find a usable */ /* Winsock DLL. */ OT_ASSERT_MSG((err == 0), "WSAStartup failed!\n"); /* Confirm that the WinSock DLL supports 2.2. */ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ bool bWinsock = (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2); /* Tell the user that we could not find a usable */ /* WinSock DLL. */ if (!bWinsock) WSACleanup(); // do cleanup. OT_ASSERT_MSG((!bWinsock), "Could not find a usable version of Winsock.dll\n"); /* The Winsock DLL is acceptable. Proceed to use it. */ /* Add network programming using Winsock here */ /* then call WSACleanup when done using the Winsock dll */ OTLog::vOutput(0,"The Winsock 2.2 dll was found okay\n"); #endif // ------------------------------------ // SIGNALS // #if defined(OT_SIGNAL_HANDLING) // OTLog::SetupSignalHandler(); // <===== SIGNALS // // This is optional! You can always remove it using the OT_NO_SIGNAL_HANDLING // option, and plus, the internals only execute once anyway. (It keeps count.) #endif // ------------------------------------ // // OT Server Path: // { bool bSetupPathsSuccess = false; if(!OTDataFolder::Init(SERVER_CONFIG_KEY)) { OT_FAIL; } else bSetupPathsSuccess = true; OT_ASSERT_MSG(bSetupPathsSuccess, "main(): Assert failed: Failed to set OT Path"); } // ----------------------------------------------------------------------- OTCrypto::It()->Init(); // (OpenSSL gets initialized here.) // ------------------------------------ }
bool OTASCIIArmor::SetString(const OTString & theData, bool bLineBreaks) //=true { // OTLog::vError("DEBUGGING OTASCIIARMOR::SETSTRING, INPUT: --------->%s<---------", theData.Get()); Release(); if (theData.GetLength() < 1) return true; char * pString = NULL; // Set up source buffer and destination buffer long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.) const long lSourcelen = sizeof(unsigned char)*theData.GetLength()+1;// for null terminator unsigned char* pSource = new unsigned char[lSourcelen+10]; // for safety unsigned char* pDest = new unsigned char[nDestLen+10]; // for safety OT_ASSERT(NULL != pSource); OT_ASSERT(NULL != pDest); memcpy(pSource, (const unsigned char*)theData.Get(), lSourcelen ); // Now we are compressing first before base64-encoding (for strings, anyway) int nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen ); // If the destination buffer wasn't the right size the first time around, // then we re-allocate it to the right size (which we now know) and try again... if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = new unsigned char [nDestLen]; // enough room now OT_ASSERT(NULL != pDest); nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen ); } // Clean this up... delete [] pSource; pSource = NULL; // Still errors? if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Error allocating memory in OTASCIIArmor::SetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_STREAM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "pDest is NULL in OTASCIIArmor::SetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_DATA_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "corrupted pSrc passed to ezuncompress OTASCIIArmor::SetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_MEM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Out of memory in OTASCIIArmor::SetString\n"); return false; // not really necessary but just making sure. } OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetString\n"); // Success if (0 < nDestLen) { // Now let's base-64 encode it... pString = OT_base64_encode((const uint8_t*)pDest, nDestLen, (bLineBreaks ? 1 : 0)); // pString = OT_base64_encode((const uint8_t*)theData.Get(), theData.GetLength()+1, (bLineBreaks ? 1 : 0)); // this was before we used compression. delete [] pDest; pDest = NULL; if (pString) { Set(pString); delete [] pString; pString=NULL; return true; } else { OTLog::Error("pString NULL in OTASCIIArmor::SetString\n"); } } else { OTLog::Error("nDestLen 0 in OTASCIIArmor::SetString\n"); } if (pDest) delete [] pDest; pDest = NULL; return false; }
// Asks for password twice. (For confirmation when changing password or creating nym.) // void OTCallback::runTwo(const char * szDisplay, OTPassword & theOutput) // child class will override. { OT_ASSERT_MSG(false, "OTCallback::runTwo: ASSERT (The child class was supposed to override this method.)\n"); }
/// Lookup the current mint for any given instrument definition ID and series. Mint* Transactor::getMint(const Identifier& INSTRUMENT_DEFINITION_ID, int32_t nSeries) // Each asset contract has its own // Mint. { Mint* pMint = nullptr; for (auto& it : mintsMap_) { pMint = it.second; OT_ASSERT_MSG(nullptr != pMint, "nullptr mint pointer in Transactor::getMint\n"); Identifier theID; pMint->GetIdentifier(theID); if ((INSTRUMENT_DEFINITION_ID == theID) && // if the ID on the Mint matches the ID passed in (nSeries == pMint->GetSeries())) // and the series also matches... return pMint; // return the pointer right here, we're done. } // The mint isn't in memory for the series requested. const String INSTRUMENT_DEFINITION_ID_STR(INSTRUMENT_DEFINITION_ID); String strMintFilename; strMintFilename.Format("%s%s%s%s%d", server_->m_strNotaryID.Get(), Log::PathSeparator(), INSTRUMENT_DEFINITION_ID_STR.Get(), ".", nSeries); const char* szFoldername = OTFolders::Mint().Get(); const char* szFilename = strMintFilename.Get(); pMint = Mint::MintFactory(server_->m_strNotaryID, server_->m_strServerNymID, INSTRUMENT_DEFINITION_ID_STR); // You cannot hash the Mint to get its ID. (The ID is a hash of the asset // contract.) // Instead, you must READ the ID from the Mint file, and then compare it to // the one expected // to see if they match (similar to how Account IDs are verified.) OT_ASSERT_MSG(nullptr != pMint, "Error allocating memory for Mint in Transactor::getMint"); String strSeries; strSeries.Format("%s%d", ".", nSeries); // if (pMint->LoadMint(strSeries.Get())) { if (pMint->VerifyMint(server_->m_nymServer)) // I don't verify the // Mint's // expiration date here, just its // signature, ID, etc. { // (Expiry dates are enforced on tokens during deposit--and checked // against mint-- // but expiry dates are only enforced on the Mint itself during a // withdrawal.) // It's a multimap now... // mintsMap_[INSTRUMENT_DEFINITION_ID_STR.Get()] = pMint; mintsMap_.insert(std::pair<std::string, Mint*>( INSTRUMENT_DEFINITION_ID_STR.Get(), pMint)); return pMint; } else { Log::vError( "Error verifying Mint in Transactor::getMint:\n%s%s%s\n", szFoldername, Log::PathSeparator(), szFilename); } } else { Log::vError("Error loading Mint in Transactor::getMint:\n%s%s%s\n", szFoldername, Log::PathSeparator(), szFilename); } if (nullptr != pMint) delete pMint; pMint = nullptr; return nullptr; }
// The MAIN function for the server software, which starts up the XmlRpc (http server), // as well as Open Transactions. // int main(int argc, char* argv[]) { OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n" "(transport build: OTMessage -> OTEnvelope -> ZMQ )\n\n", OTLog::Version()); // ----------------------------------------------------------------------- #ifdef _WIN32 WSADATA wsaData; WORD wVersionRequested = MAKEWORD( 2, 2 ); int nWSA = WSAStartup( wVersionRequested, &wsaData ); OT_ASSERT_MSG(0 != nWSA, "Error calling WSAStartup.\n"); #endif // ----------------------------------------------------------------------- // I instantiate this here (instead of globally) so that I am assured all the globals // are ready to go before the server is created. I still have it as a global pointer, though, // so I can get to it wherever I need to. g_pServer = new OTServer; // (This file you are reading is a wrapper for OTServer, which adds the transport layer.) OT_ASSERT_MSG(NULL != g_pServer, "Unable to instantiate OT server...\n"); // ----------------------------------------------------------------------- // The beginnings of an INI file!! OTString strIniFileDefault; OTLog::TransformFilePath(OT_INI_FILE_DEFAULT, strIniFileDefault); OTString strPath, strRawPath(SERVER_PATH_DEFAULT); { CSimpleIniA ini; SI_Error rc = ini.LoadFile(strIniFileDefault.Get()); if (rc >=0) { { const char * pVal = ini.GetValue("paths", "server_path", SERVER_PATH_DEFAULT); // todo stop hardcoding. if (NULL != pVal) { strRawPath.Set(pVal); OTLog::vOutput(0, "Reading ini file (%s). \n Found Server data_folder path: %s \n", strIniFileDefault.Get(), strRawPath.Get()); } else { strRawPath.Set(SERVER_PATH_DEFAULT); OTLog::vOutput(0, "Reading ini file (%s): \n Failed reading Server data_folder path. Using: %s \n", strIniFileDefault.Get(), strRawPath.Get()); } } } else { strRawPath.Set(SERVER_PATH_DEFAULT); OTLog::vOutput(0, "Unable to load ini file (%s) to find data_folder path\n Will assume that server data_folder is at path: %s \n", strIniFileDefault.Get(), strRawPath.Get()); } } // ----------------------------------------------------------------------- OTString strCAFile, strDHFile, strKeyFile; //, strSSLPassword; OTLog::TransformFilePath(strRawPath.Get(), strPath); OTLog::SetMainPath(strPath.Get()); OTLog::vOutput(0, "Using data_folder path: %s\n", OTLog::Path()); strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE); strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE); strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE); // ----------------------------------------------------------------------- // Initialize SSL -- This MUST occur before any Private Keys are loaded! SSL_library_init(); SSL_load_error_strings(); // Init loads up server's nym so it can decrypt messages sent in envelopes. // It also does various other initialization work. // // (Envelopes prove that ONLY someone who actually had the server contract, // and had loaded it into his wallet, could ever connect to the server or // communicate with it. And if that person is following the contract, there // is only one server he can connect to, and one key he can use to talk to it.) OTLog::vOutput(0, "\nNow loading the server nym, which will also ask you for a password, to unlock\n" "its private key. (Default password is \"%s\".)\n", KEY_PASSWORD); g_pServer->Init(); // Keys, etc are loaded here. // ----------------------------------------------------------------------- // We're going to listen on the same port that is listed in our server contract. // // OTString strHostname; // The hostname of this server, according to its own contract. int nPort=0; // The port of this server, according to its own contract. OT_ASSERT_MSG(g_pServer->GetConnectInfo(strHostname, nPort), "Unable to find my own connect info (which is in my server contract BTW.)\n"); const int nServerPort = nPort; // int nSFSocketInit = SFSocketInit(socket, // strCAFile.Get(), // strDHFile.Get(), // strKeyFile.Get(), // strSSLPassword.Get(), // NULL); // ----------------------------------------------------------------------- // For re-occuring actions (like markets and payment plans.) // g_pServer->ActivateCron(); // ----------------------------------- // Prepare our context and socket zmq::context_t context(1); zmq::socket_t socket(context, ZMQ_REP); OTString strBindPath; strBindPath.Format("%s%d", "tcp://*:", nServerPort); socket.bind(strBindPath.Get()); // ----------------------------------------------------------------------- // Let's get the HTTP server up and running... // Switching out XmlRpc for 0MQ (ZeroMQ) // // XmlRpc::setVerbosity(1); // // // Create the server socket on the specified port // theXmlRpcServer.bindAndListen(nServerPort); // // // Enable introspection, so clients can see what services this server supports. (Open Transactions...) // theXmlRpcServer.enableIntrospection(true); // ----------------------------------------------------------------------- // Initialize poll set zmq::pollitem_t items [] = { { socket, 0, ZMQ_POLLIN, 0 }, }; // ---------------------------------------------------------- do // THE HEARTBEAT LOOP FOR THE OPEN-TRANSACTIONS SERVER! { // The Server now processes certain things on a regular basis. // ProcessCron is what gives it the opportunity to do that. // All of the Cron Items (including market trades, and payment plans...) have their hooks here... // g_pServer->ProcessCron(); // ----------------------------------------------------------------------- // Wait for client http requests (and process replies out to them.) // // theXmlRpcServer.work(10.0); // supposedly milliseconds -- but it's actually seconds. // Loop: process up to 10 client requests, then sleep for 1/10th second. // // Then: check for shutdown. // // Then: go back to the top and repeat.... process cron, loop 10 client requests, sleep, check for shutdown, etc. // // for (int i = 0; i < /*10*/OTServer::GetHeartbeatNoRequests(); i++) { // Switching to ZeroMQ library. zmq::message_t message; zmq::poll(&items[0], 1, 0); // non-blocking // zmq::poll(&items[0], 1, -1); if ((items[0].revents & ZMQ_POLLIN) && socket.recv(&message, ZMQ_NOBLOCK)) { // socket.recv(&message); // Convert the ZMQ message to a std::string std::string str_Message; str_Message.reserve(message.size()); str_Message.append(static_cast<const char *>(message.data()), message.size()); // Process task std::string str_Reply; // Output. ProcessMessage_ZMQ(str_Message, str_Reply); // ----------------------------------------------- // Convert the std::string (reply) into a ZMQ message zmq::message_t reply (str_Reply.length()); if (str_Reply.length() > 0) memcpy((void *) reply.data(), str_Reply.c_str(), str_Reply.length()); // -------------------------------- // Send reply back to client int nSendTries = 0; bool bSuccessSending = false; // HALF-SECOND DELAY IF FAILURE SENDING REPLY... // (While it tries to re-send 5 times.) // while ((nSendTries++ < OTLog::GetLatencySendNoTries()/*5*/) && (false == (bSuccessSending = socket.send(reply, ZMQ_NOBLOCK)))) OTLog::SleepMilliseconds(/*100*/OTLog::GetLatencySendMs()); if (false == bSuccessSending) OTLog::vError("Socket error: failed while trying to send reply back to client! \n\n MESSAGE:\n%s\n\nREPLY:\n%s\n\n", str_Message.c_str(), str_Reply.c_str()); } } // for // ----------------------------------------------------------------------- // Now go to sleep for a tenth of a second. // (The main loop processes ten times per second, currently.) OTLog::SleepMilliseconds(/*100*/OTServer::GetHeartbeatMsBetweenBeats()); // 100 ms == (1 second / 10) // ----------------------------------------------------------------------- // ARTIFICIAL LIMIT: // 10 requests per heartbeat, 10 rounds per second == 100 requests per second. // // *** ONE HUNDRED CLIENT MESSAGES PER SECOND is the same as: // // 6000 PER MINUTE == 360,000 PER HOUR == 8,640,000 PER DAY*** // // Speeding it up is just a matter of adjusting the above numbers, and TESTING to see if OT can handle it. // (Not counting optimization of course.) // // ----------------------------------------------------------------------- if (g_pServer->IsFlaggedForShutdown()) { OTLog::Output(0, "Server is shutting down gracefully....\n"); break; } } while (1); // TODO: cleanup OpenSSL here. #ifdef _WIN32 WSACleanup(); #endif return 0; }
/// This function first Packs the incoming string, using whatever is the default packer. (MsgPack or Protobuf). /// Then it Compresses the packed binary data using zlib. (ezcompress.) /// Then it Base64-Encodes the compressed binary and sets it as a string on THIS OBJECT. /// /// I added these pieces 1-by-1 over time. At first the messages were too long, so I started compressing them. /// Then they were not binary compatible across various platforms, so I added the packing. // bool OTASCIIArmor::SetAndPackString(const OTString & theData, bool bLineBreaks) //=true { // OTLog::vError("DEBUGGING OTASCIIARMOR::SETSTRING, INPUT: --------->%s<---------", theData.Get()); Release(); if (theData.GetLength() < 1) return true; // -------------------------------------------------------- OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either. // Here I use the default storage context to create the object (the blob.) // I also originally created OTASCIIArmor::GetPacker() using OTDB_DEFAULT_PACKER, // so I know everything is compatible. // OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING)); OT_ASSERT(NULL != pOTDBString); // Beyond this point, responsible to delete pString. OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // make sure memory is cleaned up. // ----------------------------- const uint32_t theStringSize32 = theData.GetLength(); const size_t theStringSize = theStringSize32; // might need a cast here. // todo make sure this will handle sizes as big as I need. pOTDBString->m_string.assign(theData.Get(), // const char * theStringSize); OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pOTDBString); // Now we PACK our string before compressing/encoding it. if (NULL == pBuffer) { OTLog::Error("Failed packing string in OTASCIIArmor::SetAndPackString. \n"); return false; } OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up. // -------------------------------------------------------- const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData()); const size_t theSize = pBuffer->GetSize(); // -------------------------------------------------------- char * pString = NULL; // Set up source buffer and destination buffer long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.) const long lSourcelen = theSize; unsigned char* pSource = new unsigned char[lSourcelen+10]; // for safety unsigned char* pDest = new unsigned char[nDestLen+10]; // for safety OT_ASSERT(NULL != pSource); OT_ASSERT(NULL != pDest); memcpy(pSource, static_cast<const unsigned char*>(pUint), theSize ); // Now we are compressing first before base64-encoding (for strings, anyway) int nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen ); // If the destination buffer wasn't the right size the first time around, // then we re-allocate it to the right size (which we now know) and try again... if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = new unsigned char [nDestLen]; // enough room now OT_ASSERT(NULL != pDest); nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen ); } // Clean this up... delete [] pSource; pSource = NULL; // Still errors? if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Error allocating memory in OTASCIIArmor::SetAndPackString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_STREAM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "pDest is NULL in OTASCIIArmor::SetAndPackString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_DATA_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "corrupted pSrc passed to ezuncompress OTASCIIArmor::SetAndPackString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_MEM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Out of memory in OTASCIIArmor::SetAndPackString\n"); return false; // not really necessary but just making sure. } OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetAndPackString\n"); // Success if (0 < nDestLen) { // Now let's base-64 encode it... pString = OT_base64_encode((const uint8_t*)pDest, nDestLen, (bLineBreaks ? 1 : 0)); delete [] pDest; pDest = NULL; if (pString) { Set(pString); delete [] pString; pString=NULL; return true; } else { OTLog::Error("pString NULL in OTASCIIArmor::SetAndPackString\n"); } } else { OTLog::Error("nDestLen 0 in OTASCIIArmor::SetAndPackString\n"); } if (pDest) delete [] pDest; pDest = NULL; return false; }
// Used for making sure that certain necessary folders actually exist. (Creates them otherwise.) // // If you pass in "spent", then this function will make sure that "<path>/spent" actually exists, // or create it. WARNING: If what you want to pass is "spent/sub-folder-to-spent" then make SURE // you call it with "spent" FIRST, so you are sure THAT folder has been created, otherwise the // folder creation will definitely fail on the sub-folder call (if the primary folder wasn't // already there, that is.) // bool OTLog::ConfirmOrCreateFolder(const char * szFolderName) { OT_ASSERT_MSG(NULL != szFolderName, "OTLog::ConfirmOrCreateFolder: Assert failed: NULL != szFolderName"); OTString strFolderName(szFolderName); // DIRECTORY IS PRESENT? struct stat st; OTString strRawPath; if (strFolderName.Compare(".")) strRawPath.Format("%s", OTLog::Path()); else strRawPath.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), strFolderName.Get()); // OTLog::vError("**** Path: %s Foldername: %s Total: %s \n", // OTLog::Path(), szFolderName, strRawPath.Get()); /*ACTUAL OUTPUT: **** Path: /Users/au/Library/Application Foldername: nyms Total: "/Users/au/Library/Application/nyms" */ OTString strPath; OTLog::TransformFilePath(strRawPath.Get(), strPath); OTLog::vOutput(1, "OTLog::ConfirmOrCreateFolder: Transformed %s into %s \n", strRawPath.Get(), strPath.Get()); bool bDirIsPresent = (0 == stat(strPath.Get(), &st)); // ---------------------------------------------------------------------------- // IF NO, CREATE IT if (!bDirIsPresent) { #ifdef _WIN32 if (_mkdir(strPath.Get()) == -1) #else if (mkdir(strPath.Get(), 0700) == -1) #endif { OTLog::vError("OTLog::ConfirmOrCreateFolder: Unable to create %s.\n", strPath.Get()); return false; } // Now we have created it, so let's check again... bDirIsPresent = (0 == stat(strPath.Get(), &st)); if (bDirIsPresent) OTLog::vOutput(0, "Created folder: %s\n", strPath.Get()); } // ---------------------------------------------------------------------------- // At this point if the folder still doesn't exist, nothing we can do. We // already tried to create the folder, and SUCCEEDED, and then STILL failed // to find it (if this is still false.) if (!bDirIsPresent) { OTLog::vError("OTLog::ConfirmOrCreateFolder: Unable to find newly-created folder: %s\n", strPath.Get()); return false; } return true; }