Beispiel #1
0
// 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
}
Beispiel #2
0
// 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;
}
Beispiel #3
0
// 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;
	}
}
Beispiel #7
0
//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;	
}
Beispiel #10
0
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));
}
Beispiel #15
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;
	}
}
Beispiel #18
0
		__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");
}
Beispiel #21
0
/// 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;	
}
Beispiel #24
0
// 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;
}