diff options
Diffstat (limited to 'src/util.cpp')
| -rw-r--r-- | src/util.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..0b794d4 --- /dev/null +++ b/src/util.cpp | |||
| @@ -0,0 +1,393 @@ | |||
| 1 | // Copyright (c) 2009 Satoshi Nakamoto | ||
| 2 | // Distributed under the MIT/X11 software license, see the accompanying | ||
| 3 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. | ||
| 4 | |||
| 5 | #include "headers.h" | ||
| 6 | |||
| 7 | |||
| 8 | |||
| 9 | bool fDebug = false; | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | #ifdef _WIN32 | ||
| 15 | // Init openssl library multithreading support (OpenSSL < 1.1 needed callbacks; | ||
| 16 | // OpenSSL 1.1+/3 is internally thread-safe, so the Linux build skips this). | ||
| 17 | static HANDLE* lock_cs; | ||
| 18 | |||
| 19 | void win32_locking_callback(int mode, int type, const char* file, int line) | ||
| 20 | { | ||
| 21 | if (mode & CRYPTO_LOCK) | ||
| 22 | WaitForSingleObject(lock_cs[type], INFINITE); | ||
| 23 | else | ||
| 24 | ReleaseMutex(lock_cs[type]); | ||
| 25 | } | ||
| 26 | #endif | ||
| 27 | |||
| 28 | // Init | ||
| 29 | class CInit | ||
| 30 | { | ||
| 31 | public: | ||
| 32 | CInit() | ||
| 33 | { | ||
| 34 | #ifdef _WIN32 | ||
| 35 | // Init openssl library multithreading support | ||
| 36 | lock_cs = (HANDLE*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(HANDLE)); | ||
| 37 | for (int i = 0; i < CRYPTO_num_locks(); i++) | ||
| 38 | lock_cs[i] = CreateMutex(NULL,FALSE,NULL); | ||
| 39 | CRYPTO_set_locking_callback(win32_locking_callback); | ||
| 40 | |||
| 41 | // Seed random number generator with screen scrape and other hardware sources | ||
| 42 | RAND_screen(); | ||
| 43 | #endif | ||
| 44 | // Seed random number generator with perfmon / high-res timer data | ||
| 45 | RandAddSeed(true); | ||
| 46 | } | ||
| 47 | ~CInit() | ||
| 48 | { | ||
| 49 | #ifdef _WIN32 | ||
| 50 | // Shutdown openssl library multithreading support | ||
| 51 | CRYPTO_set_locking_callback(NULL); | ||
| 52 | for (int i =0 ; i < CRYPTO_num_locks(); i++) | ||
| 53 | CloseHandle(lock_cs[i]); | ||
| 54 | OPENSSL_free(lock_cs); | ||
| 55 | #endif | ||
| 56 | } | ||
| 57 | } | ||
| 58 | instance_of_cinit; | ||
| 59 | |||
| 60 | |||
| 61 | |||
| 62 | |||
| 63 | void RandAddSeed(bool fPerfmon) | ||
| 64 | { | ||
| 65 | #ifdef _WIN32 | ||
| 66 | // Seed with CPU performance counter | ||
| 67 | LARGE_INTEGER PerformanceCount; | ||
| 68 | QueryPerformanceCounter(&PerformanceCount); | ||
| 69 | RAND_add(&PerformanceCount, sizeof(PerformanceCount), 1.5); | ||
| 70 | memset(&PerformanceCount, 0, sizeof(PerformanceCount)); | ||
| 71 | |||
| 72 | static int64 nLastPerfmon; | ||
| 73 | if (fPerfmon || GetTime() > nLastPerfmon + 5 * 60) | ||
| 74 | { | ||
| 75 | nLastPerfmon = GetTime(); | ||
| 76 | |||
| 77 | // Seed with the entire set of perfmon data | ||
| 78 | unsigned char pdata[250000]; | ||
| 79 | memset(pdata, 0, sizeof(pdata)); | ||
| 80 | unsigned long nSize = sizeof(pdata); | ||
| 81 | long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize); | ||
| 82 | RegCloseKey(HKEY_PERFORMANCE_DATA); | ||
| 83 | if (ret == ERROR_SUCCESS) | ||
| 84 | { | ||
| 85 | uint256 hash; | ||
| 86 | SHA256(pdata, nSize, (unsigned char*)&hash); | ||
| 87 | RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash))); | ||
| 88 | hash = 0; | ||
| 89 | memset(pdata, 0, nSize); | ||
| 90 | printf("RandAddSeed() got %d bytes of performance data\n", nSize); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | #else | ||
| 94 | // Seed with a high-resolution timer; OpenSSL also seeds itself from | ||
| 95 | // /dev/urandom, so this is just extra entropy. No perfmon on Linux. | ||
| 96 | (void)fPerfmon; | ||
| 97 | struct timespec ts; | ||
| 98 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
| 99 | RAND_add(&ts, sizeof(ts), 1.5); | ||
| 100 | memset(&ts, 0, sizeof(ts)); | ||
| 101 | #endif | ||
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | |||
| 106 | |||
| 107 | |||
| 108 | |||
| 109 | |||
| 110 | |||
| 111 | |||
| 112 | |||
| 113 | // Safer snprintf | ||
| 114 | // - prints up to limit-1 characters | ||
| 115 | // - output string is always null terminated even if limit reached | ||
| 116 | // - return value is the number of characters actually printed | ||
| 117 | int my_snprintf(char* buffer, size_t limit, const char* format, ...) | ||
| 118 | { | ||
| 119 | if (limit == 0) | ||
| 120 | return 0; | ||
| 121 | va_list arg_ptr; | ||
| 122 | va_start(arg_ptr, format); | ||
| 123 | int ret = _vsnprintf(buffer, limit, format, arg_ptr); | ||
| 124 | va_end(arg_ptr); | ||
| 125 | if (ret < 0 || ret >= limit) | ||
| 126 | { | ||
| 127 | ret = limit - 1; | ||
| 128 | buffer[limit-1] = 0; | ||
| 129 | } | ||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | |||
| 133 | |||
| 134 | string strprintf(const char* format, ...) | ||
| 135 | { | ||
| 136 | char buffer[50000]; | ||
| 137 | char* p = buffer; | ||
| 138 | int limit = sizeof(buffer); | ||
| 139 | int ret; | ||
| 140 | loop | ||
| 141 | { | ||
| 142 | va_list arg_ptr; | ||
| 143 | va_start(arg_ptr, format); | ||
| 144 | ret = _vsnprintf(p, limit, format, arg_ptr); | ||
| 145 | va_end(arg_ptr); | ||
| 146 | if (ret >= 0 && ret < limit) | ||
| 147 | break; | ||
| 148 | if (p != buffer) | ||
| 149 | delete p; | ||
| 150 | limit *= 2; | ||
| 151 | p = new char[limit]; | ||
| 152 | if (p == NULL) | ||
| 153 | throw std::bad_alloc(); | ||
| 154 | } | ||
| 155 | #ifdef _MSC_VER | ||
| 156 | // msvc optimisation | ||
| 157 | if (p == buffer) | ||
| 158 | return string(p, p+ret); | ||
| 159 | #endif | ||
| 160 | string str(p, p+ret); | ||
| 161 | if (p != buffer) | ||
| 162 | delete p; | ||
| 163 | return str; | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | bool error(const char* format, ...) | ||
| 168 | { | ||
| 169 | char buffer[50000]; | ||
| 170 | int limit = sizeof(buffer); | ||
| 171 | va_list arg_ptr; | ||
| 172 | va_start(arg_ptr, format); | ||
| 173 | int ret = _vsnprintf(buffer, limit, format, arg_ptr); | ||
| 174 | va_end(arg_ptr); | ||
| 175 | if (ret < 0 || ret >= limit) | ||
| 176 | { | ||
| 177 | ret = limit - 1; | ||
| 178 | buffer[limit-1] = 0; | ||
| 179 | } | ||
| 180 | printf("ERROR: %s\n", buffer); | ||
| 181 | return false; | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | void PrintException(std::exception* pex, const char* pszThread) | ||
| 186 | { | ||
| 187 | char pszModule[260]; | ||
| 188 | pszModule[0] = '\0'; | ||
| 189 | #ifdef _WIN32 | ||
| 190 | GetModuleFileName(NULL, pszModule, sizeof(pszModule)); | ||
| 191 | _strlwr(pszModule); | ||
| 192 | #else | ||
| 193 | strncpy(pszModule, "bitflash-node", sizeof(pszModule) - 1); | ||
| 194 | #endif | ||
| 195 | char pszMessage[1000]; | ||
| 196 | if (pex) | ||
| 197 | snprintf(pszMessage, sizeof(pszMessage), | ||
| 198 | "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); | ||
| 199 | else | ||
| 200 | snprintf(pszMessage, sizeof(pszMessage), | ||
| 201 | "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); | ||
| 202 | printf("\n\n************************\n%s", pszMessage); | ||
| 203 | if (wxTheApp) | ||
| 204 | wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR); | ||
| 205 | throw; | ||
| 206 | //DebugBreak(); | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | void ParseString(const string& str, char c, vector<string>& v) | ||
| 211 | { | ||
| 212 | unsigned int i1 = 0; | ||
| 213 | unsigned int i2; | ||
| 214 | do | ||
| 215 | { | ||
| 216 | i2 = str.find(c, i1); | ||
| 217 | v.push_back(str.substr(i1, i2-i1)); | ||
| 218 | i1 = i2+1; | ||
| 219 | } | ||
| 220 | while (i2 != str.npos); | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | string FormatMoney(int64 n, bool fPlus) | ||
| 225 | { | ||
| 226 | n /= CENT; | ||
| 227 | string str = strprintf("%I64d.%02I64d", (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100); | ||
| 228 | for (int i = 6; i < str.size(); i += 4) | ||
| 229 | if (isdigit(str[str.size() - i - 1])) | ||
| 230 | str.insert(str.size() - i, 1, ','); | ||
| 231 | if (n < 0) | ||
| 232 | str.insert((unsigned int)0, 1, '-'); | ||
| 233 | else if (fPlus && n > 0) | ||
| 234 | str.insert((unsigned int)0, 1, '+'); | ||
| 235 | return str; | ||
| 236 | } | ||
| 237 | |||
| 238 | bool ParseMoney(const char* pszIn, int64& nRet) | ||
| 239 | { | ||
| 240 | string strWhole; | ||
| 241 | int64 nCents = 0; | ||
| 242 | const char* p = pszIn; | ||
| 243 | while (isspace(*p)) | ||
| 244 | p++; | ||
| 245 | for (; *p; p++) | ||
| 246 | { | ||
| 247 | if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4])) | ||
| 248 | continue; | ||
| 249 | if (*p == '.') | ||
| 250 | { | ||
| 251 | p++; | ||
| 252 | if (!isdigit(p[0]) || !isdigit(p[1])) | ||
| 253 | return false; | ||
| 254 | nCents = atoi64(p); | ||
| 255 | if (nCents < 0 || nCents > 99) | ||
| 256 | return false; | ||
| 257 | p += 2; | ||
| 258 | break; | ||
| 259 | } | ||
| 260 | if (isspace(*p)) | ||
| 261 | break; | ||
| 262 | if (!isdigit(*p)) | ||
| 263 | return false; | ||
| 264 | strWhole.insert(strWhole.end(), *p); | ||
| 265 | } | ||
| 266 | for (; *p; p++) | ||
| 267 | if (!isspace(*p)) | ||
| 268 | return false; | ||
| 269 | if (strWhole.size() > 17) | ||
| 270 | return false; | ||
| 271 | int64 nWhole = atoi64(strWhole); | ||
| 272 | int64 nValue = nWhole * 100 + nCents; | ||
| 273 | if (nValue / 100 != nWhole) | ||
| 274 | return false; | ||
| 275 | nValue *= CENT; | ||
| 276 | nRet = nValue; | ||
| 277 | return true; | ||
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | |||
| 282 | |||
| 283 | |||
| 284 | |||
| 285 | |||
| 286 | |||
| 287 | |||
| 288 | |||
| 289 | bool FileExists(const char* psz) | ||
| 290 | { | ||
| 291 | #ifdef WIN32 | ||
| 292 | return GetFileAttributes(psz) != -1; | ||
| 293 | #else | ||
| 294 | return access(psz, 0) != -1; | ||
| 295 | #endif | ||
| 296 | } | ||
| 297 | |||
| 298 | int GetFilesize(FILE* file) | ||
| 299 | { | ||
| 300 | int nSavePos = ftell(file); | ||
| 301 | int nFilesize = -1; | ||
| 302 | if (fseek(file, 0, SEEK_END) == 0) | ||
| 303 | nFilesize = ftell(file); | ||
| 304 | fseek(file, nSavePos, SEEK_SET); | ||
| 305 | return nFilesize; | ||
| 306 | } | ||
| 307 | |||
| 308 | |||
| 309 | |||
| 310 | |||
| 311 | |||
| 312 | |||
| 313 | |||
| 314 | |||
| 315 | uint64 GetRand(uint64 nMax) | ||
| 316 | { | ||
| 317 | if (nMax == 0) | ||
| 318 | return 0; | ||
| 319 | |||
| 320 | // The range of the random source must be a multiple of the modulus | ||
| 321 | // to give every possible output value an equal possibility | ||
| 322 | uint64 nRange = (_UI64_MAX / nMax) * nMax; | ||
| 323 | uint64 nRand = 0; | ||
| 324 | do | ||
| 325 | RAND_bytes((unsigned char*)&nRand, sizeof(nRand)); | ||
| 326 | while (nRand >= nRange); | ||
| 327 | return (nRand % nMax); | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 331 | |||
| 332 | |||
| 333 | |||
| 334 | |||
| 335 | |||
| 336 | |||
| 337 | |||
| 338 | |||
| 339 | // | ||
| 340 | // "Never go to sea with two chronometers; take one or three." | ||
| 341 | // Our three chronometers are: | ||
| 342 | // - System clock | ||
| 343 | // - Median of other server's clocks | ||
| 344 | // - NTP servers | ||
| 345 | // | ||
| 346 | // note: NTP isn't implemented yet, so until then we just use the median | ||
| 347 | // of other nodes clocks to correct ours. | ||
| 348 | // | ||
| 349 | |||
| 350 | int64 GetTime() | ||
| 351 | { | ||
| 352 | return time(NULL); | ||
| 353 | } | ||
| 354 | |||
| 355 | static int64 nTimeOffset = 0; | ||
| 356 | |||
| 357 | int64 GetAdjustedTime() | ||
| 358 | { | ||
| 359 | return GetTime() + nTimeOffset; | ||
| 360 | } | ||
| 361 | |||
| 362 | void AddTimeData(unsigned int ip, int64 nTime) | ||
| 363 | { | ||
| 364 | int64 nOffsetSample = nTime - GetTime(); | ||
| 365 | |||
| 366 | // Ignore duplicates | ||
| 367 | static set<unsigned int> setKnown; | ||
| 368 | if (!setKnown.insert(ip).second) | ||
| 369 | return; | ||
| 370 | |||
| 371 | // Add data | ||
| 372 | static vector<int64> vTimeOffsets; | ||
| 373 | if (vTimeOffsets.empty()) | ||
| 374 | vTimeOffsets.push_back(0); | ||
| 375 | vTimeOffsets.push_back(nOffsetSample); | ||
| 376 | printf("Added time data, samples %d, ip %08x, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), ip, vTimeOffsets.back(), vTimeOffsets.back()/60); | ||
| 377 | if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) | ||
| 378 | { | ||
| 379 | sort(vTimeOffsets.begin(), vTimeOffsets.end()); | ||
| 380 | int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2]; | ||
| 381 | nTimeOffset = nMedian; | ||
| 382 | if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60) | ||
| 383 | { | ||
| 384 | // Only let other nodes change our clock so far before we | ||
| 385 | // go to the NTP servers | ||
| 386 | /// todo: Get time from NTP servers, then set a flag | ||
| 387 | /// to make sure it doesn't get changed again | ||
| 388 | } | ||
| 389 | foreach(int64 n, vTimeOffsets) | ||
| 390 | printf("%+I64d ", n); | ||
| 391 | printf("| nTimeOffset = %+I64d (%+I64d minutes)\n", nTimeOffset, nTimeOffset/60); | ||
| 392 | } | ||
| 393 | } | ||