NaCl runtime fixes
[mono.git] / mono / metadata / rand.c
index 188d09a5b543f5e04db7a68a9b0fd1a457b1b84a..4ed1203f85df3390b9d75bd5c597ec955c0c6dea 100644 (file)
@@ -6,8 +6,8 @@
  *      Patrik Torstensson (p@rxc.se)
  *     Sebastien Pouliot (sebastien@ximian.com)
  *
- * (C) 2001 Ximian, Inc.
- * (C) 2004 Novell (http://www.novell.com)
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  */
 
 #include <config.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
 
 #include <mono/metadata/object.h>
 #include <mono/metadata/rand.h>
 #include <mono/metadata/exception.h>
 
-#if !defined(PLATFORM_WIN32)
+#if !defined(__native_client__) && !defined(HOST_WIN32)
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <errno.h>
@@ -92,9 +97,10 @@ get_entropy_from_server (const char *path, guchar *buf, int len)
 }
 #endif
 
-#if defined (PLATFORM_WIN32)
+#if defined (HOST_WIN32)
 
-#include <WinCrypt.h>
+#include <windows.h>
+#include <wincrypt.h>
 
 #ifndef PROV_INTEL_SEC
 #define PROV_INTEL_SEC         22
@@ -103,6 +109,13 @@ get_entropy_from_server (const char *path, guchar *buf, int len)
 #define CRYPT_VERIFY_CONTEXT   0xF0000000
 #endif
 
+MonoBoolean
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngOpen (void)
+{
+       /* FALSE == Local (instance) handle for randomness */
+       return FALSE;
+}
+
 gpointer
 ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (MonoArray *seed)
 {
@@ -151,13 +164,14 @@ ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngGetBytes (gpo
        if (!CryptGenRandom (provider, len, buf)) {
                CryptReleaseContext (provider, 0);
                /* we may have lost our context with CryptoAPI, but all hope isn't lost yet! */
-               provider = ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (NULL);
+               provider = (HCRYPTPROV) ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (NULL);
                if (!CryptGenRandom (provider, len, buf)) {
                        CryptReleaseContext (provider, 0);
                        provider = 0;
                        /* exception will be thrown in managed code */
                }
-       } 
+       }
+       return (gpointer) provider;
 }
 
 void
@@ -166,6 +180,58 @@ ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngClose (gpoint
        CryptReleaseContext ((HCRYPTPROV) handle, 0);
 }
 
+#elif defined (__native_client__)
+
+#include <time.h>
+
+MonoBoolean
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngOpen (void)
+{
+       srand (time (NULL));
+       return TRUE;
+}
+
+gpointer
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (MonoArray *seed)
+{
+       return -1;
+}
+
+gpointer 
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngGetBytes (gpointer handle, MonoArray *arry)
+{      
+       guint32 len = mono_array_length (arry);
+       guchar *buf = mono_array_addr (arry, guchar, 0);
+
+       /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */
+       gint count = 0;
+       gint err;
+
+       do {
+               if (len - count >= sizeof (long))
+               {
+                       *(long*)buf = rand();
+                       count += sizeof (long);
+               }
+               else if (len - count >= sizeof (short))
+               {
+                       *(short*)buf = rand();
+                       count += sizeof (short);
+               }
+               else if (len - count >= sizeof (char))
+               {
+                       *buf = rand();
+                       count += sizeof (char);
+               }
+       } while (count < len);
+
+       return (gpointer)-1L;
+}
+
+void
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngClose (gpointer handle) 
+{
+}
 #else
 
 #ifndef NAME_DEV_URANDOM
@@ -173,14 +239,13 @@ ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngClose (gpoint
 #endif
 
 static gboolean egd = FALSE;
+static gint file = -1;
 
-gpointer
-ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (MonoArray *seed)
+MonoBoolean
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngOpen (void)
 {
-       gint file = -1;
-
-       if (egd)
-               return -1;
+       if (egd || (file >= 0))
+               return TRUE;
 
 #if defined (NAME_DEV_URANDOM)
        file = open (NAME_DEV_URANDOM, O_RDONLY);
@@ -194,37 +259,47 @@ ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (M
        if (file < 0) {
                const char *socket_path = g_getenv("MONO_EGD_SOCKET");
                egd = (socket_path != NULL);
-               return -1;
        }
 
+       /* TRUE == Global handle for randomness */
+       return TRUE;
+}
+
+gpointer
+ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (MonoArray *seed)
+{
        /* if required exception will be thrown in managed code */
-       return ((file < 0) ? NULL : (gpointer) file);
+       return ((!egd && (file < 0)) ? NULL : GINT_TO_POINTER (file));
 }
 
 gpointer 
 ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngGetBytes (gpointer handle, MonoArray *arry)
 {
-       gint file = (gint) handle;
+       gint file = GPOINTER_TO_INT (handle);
        guint32 len = mono_array_length (arry);
        guchar *buf = mono_array_addr (arry, guchar, 0);
 
        if (egd) {
-               const char *socket_path = getenv ("MONO_EGD_SOCKET");
+               const char *socket_path = g_getenv ("MONO_EGD_SOCKET");
                /* exception will be thrown in managed code */
                if (socket_path == NULL)
                        return NULL; 
                get_entropy_from_server (socket_path, mono_array_addr (arry, guchar, 0), mono_array_length (arry));
-               return -1;
-       }
-       else {
+               return (gpointer) -1;
+       } else {
                /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */
                gint count = 0;
                gint err;
 
                do {
                        err = read (file, buf + count, len - count);
+                       if (err < 0) {
+                               if (errno == EINTR)
+                                       continue;
+                               break;
+                       }
                        count += err;
-               } while (err >= 0 && count < len);
+               } while (count < len);
 
                if (err < 0) {
                        g_warning("Entropy error! Error in read (%s).", strerror (errno));
@@ -241,8 +316,6 @@ ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngGetBytes (gpo
 void
 ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngClose (gpointer handle) 
 {
-       if (!egd)
-               close ((gint) handle);
 }
 
 #endif /* OS definition */