Adds a modified copy of talk/base to webrtc/base. It is the first step in
migrating talk/base to webrtc/base.
BUG=N/A
R=niklas.enbom@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/17479005
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6129 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/base/helpers.cc b/base/helpers.cc
new file mode 100644
index 0000000..8b14cdf
--- /dev/null
+++ b/base/helpers.cc
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/base/helpers.h"
+
+#include <limits>
+
+#if defined(FEATURE_ENABLE_SSL)
+#include "webrtc/base/sslconfig.h"
+#if defined(SSL_USE_OPENSSL)
+#include <openssl/rand.h>
+#elif defined(SSL_USE_NSS_RNG)
+#include "pk11func.h"
+#else
+#if defined(WEBRTC_WIN)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <ntsecapi.h>
+#endif // WEBRTC_WIN
+#endif // else
+#endif // FEATURE_ENABLED_SSL
+
+#include "webrtc/base/base64.h"
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/timeutils.h"
+
+// Protect against max macro inclusion.
+#undef max
+
+namespace rtc {
+
+// Base class for RNG implementations.
+class RandomGenerator {
+ public:
+ virtual ~RandomGenerator() {}
+ virtual bool Init(const void* seed, size_t len) = 0;
+ virtual bool Generate(void* buf, size_t len) = 0;
+};
+
+#if defined(SSL_USE_OPENSSL)
+// The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
+class SecureRandomGenerator : public RandomGenerator {
+ public:
+ SecureRandomGenerator() : inited_(false) {
+ }
+ ~SecureRandomGenerator() {
+ }
+ virtual bool Init(const void* seed, size_t len) {
+ // By default, seed from the system state.
+ if (!inited_) {
+ if (RAND_poll() <= 0) {
+ return false;
+ }
+ inited_ = true;
+ }
+ // Allow app data to be mixed in, if provided.
+ if (seed) {
+ RAND_seed(seed, len);
+ }
+ return true;
+ }
+ virtual bool Generate(void* buf, size_t len) {
+ if (!inited_ && !Init(NULL, 0)) {
+ return false;
+ }
+ return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
+ }
+
+ private:
+ bool inited_;
+};
+
+#elif defined(SSL_USE_NSS_RNG)
+// The NSS RNG.
+class SecureRandomGenerator : public RandomGenerator {
+ public:
+ SecureRandomGenerator() {}
+ ~SecureRandomGenerator() {}
+ virtual bool Init(const void* seed, size_t len) {
+ return true;
+ }
+ virtual bool Generate(void* buf, size_t len) {
+ return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
+ static_cast<int>(len)) == SECSuccess);
+ }
+};
+
+#else
+#if defined(WEBRTC_WIN)
+class SecureRandomGenerator : public RandomGenerator {
+ public:
+ SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
+ ~SecureRandomGenerator() {
+ FreeLibrary(advapi32_);
+ }
+
+ virtual bool Init(const void* seed, size_t seed_len) {
+ // We don't do any additional seeding on Win32, we just use the CryptoAPI
+ // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
+ // don't need to drag in all of CryptoAPI)
+ if (rtl_gen_random_) {
+ return true;
+ }
+
+ advapi32_ = LoadLibrary(L"advapi32.dll");
+ if (!advapi32_) {
+ return false;
+ }
+
+ rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
+ GetProcAddress(advapi32_, "SystemFunction036"));
+ if (!rtl_gen_random_) {
+ FreeLibrary(advapi32_);
+ return false;
+ }
+
+ return true;
+ }
+ virtual bool Generate(void* buf, size_t len) {
+ if (!rtl_gen_random_ && !Init(NULL, 0)) {
+ return false;
+ }
+ return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
+ }
+
+ private:
+ typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
+ HINSTANCE advapi32_;
+ RtlGenRandomProc rtl_gen_random_;
+};
+
+#elif !defined(FEATURE_ENABLE_SSL)
+
+// No SSL implementation -- use rand()
+class SecureRandomGenerator : public RandomGenerator {
+ public:
+ virtual bool Init(const void* seed, size_t len) {
+ if (len >= 4) {
+ srand(*reinterpret_cast<const int*>(seed));
+ } else {
+ srand(*reinterpret_cast<const char*>(seed));
+ }
+ return true;
+ }
+ virtual bool Generate(void* buf, size_t len) {
+ char* bytes = reinterpret_cast<char*>(buf);
+ for (size_t i = 0; i < len; ++i) {
+ bytes[i] = static_cast<char>(rand());
+ }
+ return true;
+ }
+};
+
+#else
+
+#error No SSL implementation has been selected!
+
+#endif // WEBRTC_WIN
+#endif
+
+// A test random generator, for predictable output.
+class TestRandomGenerator : public RandomGenerator {
+ public:
+ TestRandomGenerator() : seed_(7) {
+ }
+ ~TestRandomGenerator() {
+ }
+ virtual bool Init(const void* seed, size_t len) {
+ return true;
+ }
+ virtual bool Generate(void* buf, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
+ }
+ return true;
+ }
+
+ private:
+ int GetRandom() {
+ return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
+ }
+ int seed_;
+};
+
+// TODO: Use Base64::Base64Table instead.
+static const char BASE64[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+namespace {
+
+// This round about way of creating a global RNG is to safe-guard against
+// indeterminant static initialization order.
+scoped_ptr<RandomGenerator>& GetGlobalRng() {
+ LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
+ (new SecureRandomGenerator()));
+ return global_rng;
+}
+
+RandomGenerator& Rng() {
+ return *GetGlobalRng();
+}
+
+} // namespace
+
+void SetRandomTestMode(bool test) {
+ if (!test) {
+ GetGlobalRng().reset(new SecureRandomGenerator());
+ } else {
+ GetGlobalRng().reset(new TestRandomGenerator());
+ }
+}
+
+bool InitRandom(int seed) {
+ return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
+}
+
+bool InitRandom(const char* seed, size_t len) {
+ if (!Rng().Init(seed, len)) {
+ LOG(LS_ERROR) << "Failed to init random generator!";
+ return false;
+ }
+ return true;
+}
+
+std::string CreateRandomString(size_t len) {
+ std::string str;
+ CreateRandomString(len, &str);
+ return str;
+}
+
+bool CreateRandomString(size_t len,
+ const char* table, int table_size,
+ std::string* str) {
+ str->clear();
+ scoped_ptr<uint8[]> bytes(new uint8[len]);
+ if (!Rng().Generate(bytes.get(), len)) {
+ LOG(LS_ERROR) << "Failed to generate random string!";
+ return false;
+ }
+ str->reserve(len);
+ for (size_t i = 0; i < len; ++i) {
+ str->push_back(table[bytes[i] % table_size]);
+ }
+ return true;
+}
+
+bool CreateRandomString(size_t len, std::string* str) {
+ return CreateRandomString(len, BASE64, 64, str);
+}
+
+bool CreateRandomString(size_t len, const std::string& table,
+ std::string* str) {
+ return CreateRandomString(len, table.c_str(),
+ static_cast<int>(table.size()), str);
+}
+
+uint32 CreateRandomId() {
+ uint32 id;
+ if (!Rng().Generate(&id, sizeof(id))) {
+ LOG(LS_ERROR) << "Failed to generate random id!";
+ }
+ return id;
+}
+
+uint64 CreateRandomId64() {
+ return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
+}
+
+uint32 CreateRandomNonZeroId() {
+ uint32 id;
+ do {
+ id = CreateRandomId();
+ } while (id == 0);
+ return id;
+}
+
+double CreateRandomDouble() {
+ return CreateRandomId() / (std::numeric_limits<uint32>::max() +
+ std::numeric_limits<double>::epsilon());
+}
+
+} // namespace rtc