Browse Source

Merge branch 'master' of https://github.com/civetweb/civetweb into cipher_list

Mateusz Gralka 9 years ago
parent
commit
d4a3902f02
5 changed files with 184 additions and 93 deletions
  1. 3 0
      Qt/CivetWeb.pro
  2. 12 4
      docs/Building.md
  3. 10 0
      docs/Contribution.md
  4. 77 52
      docs/Embedding.md
  5. 82 37
      src/civetweb.c

+ 3 - 0
Qt/CivetWeb.pro

@@ -20,3 +20,6 @@ INCLUDEPATH +=  \
     ../include/
     ../include/
 
 
 LIBS += -lws2_32 -lComdlg32
 LIBS += -lws2_32 -lComdlg32
+
+DEFINES += USE_IPV6
+DEFINES += USE_WEBSOCKET

+ 12 - 4
docs/Building.md

@@ -1,7 +1,7 @@
 Building Civetweb
 Building Civetweb
 =========
 =========
 
 
-This guide covers the build instructions for stand-alone web server.
+This guide covers the build instructions for the stand-alone web server.
 See [Embedding.md](https://github.com/civetweb/civetweb/blob/master/docs/Embedding.md) for information on extending an application.
 See [Embedding.md](https://github.com/civetweb/civetweb/blob/master/docs/Embedding.md) for information on extending an application.
 
 
 #### Where to get the source code?
 #### Where to get the source code?
@@ -13,8 +13,8 @@ Building for Windows
 
 
 #### Using Visual Studio
 #### Using Visual Studio
 Open the *VS2012/civetweb.sln* in Visual Studio.
 Open the *VS2012/civetweb.sln* in Visual Studio.
-To include SSL support, you may have to use yaSSL.  However, it is GPL licensed.
-See [yaSSL.md](https://github.com/civetweb/civetweb/blob/master/docs/yaSSL.md) for more information.
+To include SSL support, you may have to add an extra library for the cryptography support. You might wish to use yaSSL.  However, it is GPL licensed. See [yaSSL.md](https://github.com/civetweb/civetweb/blob/master/docs/yaSSL.md) for more information.
+Alternatively, you might wish to use OpenSSL. See [OpenSSL.md](https://github.com/civetweb/civetweb/blob/master/docs/OpenSSL.md) for more information.
 
 
 #### Using MinGW-w64 or TDM-GCC
 #### Using MinGW-w64 or TDM-GCC
 In the start menu locate and run the "Run terminal" batch file. For TDM-GCC this is named "MinGW Command Prompt".
 In the start menu locate and run the "Run terminal" batch file. For TDM-GCC this is named "MinGW Command Prompt".
@@ -23,6 +23,14 @@ Navigate to the civetweb sources directory and run:
 mingw32-make CC=gcc
 mingw32-make CC=gcc
 ```
 ```
 
 
+#### Using Qt Creator
+Open the Qt Designer project in the Qt folder
+
+#### Using CMake
+Except for Lua and Duktape support, CivetWeb can also be built with CMake.
+CMake can be used for all supported operating systems.
+
+
 Building for Linux, BSD, and OSX
 Building for Linux, BSD, and OSX
 ---------
 ---------
 
 
@@ -150,7 +158,7 @@ Building on Android
 This is a small guide to help you run civetweb on Android. Currently it is
 This is a small guide to help you run civetweb on Android. Currently it is
 tested on the HTC Wildfire. If you have managed to run it on other devices
 tested on the HTC Wildfire. If you have managed to run it on other devices
 as well, please comment or drop an email in the mailing list.
 as well, please comment or drop an email in the mailing list.
-Note : You dont need root access to run civetweb on Android.
+Note: You do not need root access to run civetweb on Android.
 
 
 - Download the source from the Downloads page.
 - Download the source from the Downloads page.
 - Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)
 - Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)

+ 10 - 0
docs/Contribution.md

@@ -0,0 +1,10 @@
+Contributing to CivetWeb (**Draft**)
+====
+
+Contributions to CivetWeb are welcome.
+
+- Please first create an issue on GitHub or create a thread on the CivetWeb discussion group.
+- If possible, create a pull request on GitHub. Please take care your modifications pass the continuous integration checks. These checks are performed automatically when you create a pull request, but they may take some hours.
+- Alternatively, you can post a patch. However, pull requests are preferred.
+- Contributor names are listed in CREDITS.md, unless you don't want your name to be listed there.
+

+ 77 - 52
docs/Embedding.md

@@ -1,34 +1,45 @@
-Embedding Civetweb
+Embedding CivetWeb
 =========
 =========
 
 
-Civetweb is primarily designed so applications can easily add HTTP server functionality.  For example, an application server could use Civetweb to enable a web service interface for automation or remote control.
+CivetWeb is primarily designed so applications can easily add HTTP and HTTPS server as well as WebSocket functionality.  For example, an application server could use CivetWeb to enable a web service interface for automation or remote control.
+
+However, it can also be used as a stand-alone executable. It can deliver static files and offers built-in server side Lua, JavaScript and CGI support.
+
 
 
 Files
 Files
 ------
 ------
 
 
 There is just a small set of files to compile in to the application,
 There is just a small set of files to compile in to the application,
-but if a library is desired, see [Building.md](https://github.com/civetweb/civetweb/blob/master/docs/Building.md)
+but if a library is desired, see [Building.md](https://github.com/CivetWeb/CivetWeb/blob/master/docs/Building.md)
 
 
 #### Regarding the INL file extension
 #### Regarding the INL file extension
-The *INL* file extension represents code that is statically included inline in a source file.  Slightly different from C++ where it means "inline" code which is technically not the same as static code. Civetweb overloads this extension for the sake of clarity as opposed to having .c extensions on files that should not be directly compiled.
-
-#### Required Files
+The *INL* file extension represents code that is statically included inline in a source file.  Slightly different from C++ where it means "inline" code which is technically not the same as static code. CivetWeb overloads this extension for the sake of clarity as opposed to having .c extensions on files that should not be directly compiled.
 
 
-  1. HTTP Server API
-    - src/civetweb.c
-    - include/civetweb.h
-  2. MD5 API
-    - src/md5.inl
-  3. C++ Wrapper (Optional)
-    - src/CivetServer.cpp
-    - include/CivetServer.h
+#### HTTP Server Source Files
 
 
-#### Other Files
+These files constitute the CivetWeb library.  They do not contain a `main` function,
+but all functions required to run a HTTP server.
 
 
-  1. Reference C Server
-    - src/main.c
-  2. Reference C++ Server
-    - examples/embedded_cpp/embedded_cpp.cpp
+  - HTTP Server API
+      - include/civetweb.c
+  - C implementation
+    - src/civetweb.c
+    - src/md5.inl (MD5 calculation)    
+  - Optional: C++ Wrapper
+    - include/CivetServer.h (C++ interface)
+    - src/CivetServer.cpp (C++ wrapper implementation)
+    
+#### Executable Source Files
+
+These files can be used to build a server executable. They contain a `main` function
+starting the HTTP server.
+
+  - Stand-alone C Server
+      - src/main.c
+  - Reference embedded C Server
+      - examples/embedded_c/embedded_c.c
+  - Reference embedded C++ Server
+      - examples/embedded_cpp/embedded_cpp.cpp
 
 
 Quick Start
 Quick Start
 ------
 ------
@@ -36,16 +47,19 @@ Quick Start
 By default, the server will automatically serve up files like a normal HTTP server.  An embedded server is most likely going to overload this functionality.
 By default, the server will automatically serve up files like a normal HTTP server.  An embedded server is most likely going to overload this functionality.
 
 
 ### C
 ### C
-  - Use ```mg_start()``` to start the server.
+  - Include the C interface ```civetweb.h```.
+  - Use `mg_start()` to start the server.
       - Use *options* to select the port and document root among other things.
       - Use *options* to select the port and document root among other things.
       - Use *callbacks* to add your own hooks.
       - Use *callbacks* to add your own hooks.
-  - Use ```mg_set_request_handler()``` to easily add your own request handlers.
-  - Use ```mg_stop()``` to stop the server.
+  - Use `mg_set_request_handler()` to easily add your own request handlers.
+  - Use `mg_stop()` to stop the server.
 
 
 ### C++
 ### C++
+  - Note that CivetWeb is Clean C, and C++ interface ```CivetServer.h``` is only a wrapper layer around the C interface.
+    Not all CivetWeb features available in C are also available in C++.
   - Create CivetHandlers for each URI.
   - Create CivetHandlers for each URI.
-  - Register the handlers with ```CivetServer::addHandler()```
-  - ```CivetServer``` starts on contruction and stops on destruction.
+  - Register the handlers with `CivetServer::addHandler()`
+  - `CivetServer` starts on contruction and stops on destruction.
   - Use contructor *options* to select the port and document root among other things.
   - Use contructor *options* to select the port and document root among other things.
   - Use constructor *callbacks* to add your own hooks.
   - Use constructor *callbacks* to add your own hooks.
 
 
@@ -103,15 +117,23 @@ Lua is a server side include functionality.  Files ending in .lua will be proces
   - src/third_party/lfs.c
   - src/third_party/lfs.c
   - src/third_party/lfs.h
   - src/third_party/lfs.h
 
 
+This build is valid for Lua version Lua 5.2. It is also possible to build with Lua 5.1 (including LuaJIT) or Lua 5.3.
+
 
 
-Civetweb internals
+JavaScript Support
 ------
 ------
 
 
-Civetweb is multithreaded web server. `mg_start()` function allocates
+CivetWeb can be built with server side JavaScript support by including the Duktape library.
+
+
+CivetWeb internals
+------
+
+CivetWeb is multithreaded web server. `mg_start()` function allocates
 web server context (`struct mg_context`), which holds all information
 web server context (`struct mg_context`), which holds all information
 about web server instance:
 about web server instance:
 
 
-- configuration options. Note that civetweb makes internal copies of
+- configuration options. Note that CivetWeb makes internal copies of
   passed options.
   passed options.
 - SSL context, if any
 - SSL context, if any
 - user-defined callbacks
 - user-defined callbacks
@@ -119,30 +141,30 @@ about web server instance:
 - a queue for accepted sockets
 - a queue for accepted sockets
 - mutexes and condition variables for inter-thread synchronization
 - mutexes and condition variables for inter-thread synchronization
 
 
-When `mg_start()` returns, all initialization is quaranteed to be complete
+When `mg_start()` returns, all initialization is guaranteed to be complete
 (e.g. listening ports are opened, SSL is initialized, etc). `mg_start()` starts
 (e.g. listening ports are opened, SSL is initialized, etc). `mg_start()` starts
-two threads: a master thread, that accepts new connections, and several
+some threads: a master thread, that accepts new connections, and several
 worker threads, that process accepted connections. The number of worker threads
 worker threads, that process accepted connections. The number of worker threads
 is configurable via `num_threads` configuration option. That number puts a
 is configurable via `num_threads` configuration option. That number puts a
-limit on number of simultaneous requests that can be handled by civetweb.
-If you embed civetweb into a program that uses SSL outside civetweb as well,
+limit on number of simultaneous requests that can be handled by CivetWeb.
+If you embed CivetWeb into a program that uses SSL outside CivetWeb as well,
 you may need to initialize SSL before calling `mg_start()`, and set the pre-
 you may need to initialize SSL before calling `mg_start()`, and set the pre-
 processor define SSL_ALREADY_INITIALIZED. This is not required if SSL is used
 processor define SSL_ALREADY_INITIALIZED. This is not required if SSL is used
-only within civetweb.
-
-When master thread accepts new connection, a new accepted socket (described by
-`struct socket`) it placed into the accepted sockets queue,
-which has size of 20 (see [code](https://github.com/civetweb/civetweb/blob/3892e0199e6ca9613b160535d9d107ede09daa43/civetweb.c#L486)). Any idle worker thread
-can grab accepted sockets from that queue. If all worker threads are busy,
-master thread can accept and queue up to 20 more TCP connections,
-filling up the queue.
-In the attempt to queue next accepted connection, master thread blocks
-until there is space in a queue. When master thread is blocked on a
-full queue, TCP layer in OS can also queue incoming connection.
-The number is limited by the `listen()` call parameter on listening socket,
-which is `SOMAXCONN` in case of Civetweb, and depends on a platform.
-
-Worker threads are running in an infinite loop, which in simplified form
+only within CivetWeb.
+
+When master thread accepts new a connection, a new accepted socket (described
+by `struct socket`) it placed into the accepted sockets queue,
+which has size of `MGSQLEN` (default 20).
+Any idle worker thread can grab accepted sockets from that queue.
+If all worker threads are busy, master thread can accept and queue up to
+20 more TCP connections, filling up the queue.
+In the attempt to queue even more accepted connection, the master thread blocks
+until there is space in the queue. When the master thread is blocked on a
+full queue, the operating system can also queue incoming connection.
+The number is limited by the `listen()` call parameter,
+which is `SOMAXCONN` and depends on the platform.
+
+Worker threads are running in an infinite loop, which in a simplified form
 looks something like this:
 looks something like this:
 
 
     static void *worker_thread() {
     static void *worker_thread() {
@@ -151,12 +173,14 @@ looks something like this:
       }
       }
     }
     }
 
 
-Function `consume_socket()` gets new accepted socket from the civetweb socket
+Function `consume_socket()` gets a new accepted socket from the CivetWeb socket
 queue, atomically removing it from the queue. If the queue is empty,
 queue, atomically removing it from the queue. If the queue is empty,
-`consume_socket()` blocks and waits until new sockets are placed in a queue
-by the master thread. `process_new_connection()` actually processes the
+`consume_socket()` blocks and waits until a new socket is placed in the queue
+by the master thread. 
+
+`process_new_connection()` actually processes the
 connection, i.e. reads the request, parses it, and performs appropriate action
 connection, i.e. reads the request, parses it, and performs appropriate action
-depending on a parsed request.
+depending on the parsed request.
 
 
 Master thread uses `poll()` and `accept()` to accept new connections on
 Master thread uses `poll()` and `accept()` to accept new connections on
 listening sockets. `poll()` is used to avoid `FD_SETSIZE` limitation of
 listening sockets. `poll()` is used to avoid `FD_SETSIZE` limitation of
@@ -164,5 +188,6 @@ listening sockets. `poll()` is used to avoid `FD_SETSIZE` limitation of
 to use hi-performance alternatives like `epoll()` or `kqueue()`. Worker
 to use hi-performance alternatives like `epoll()` or `kqueue()`. Worker
 threads use blocking IO on accepted sockets for reading and writing data.
 threads use blocking IO on accepted sockets for reading and writing data.
 All accepted sockets have `SO_RCVTIMEO` and `SO_SNDTIMEO` socket options set
 All accepted sockets have `SO_RCVTIMEO` and `SO_SNDTIMEO` socket options set
-(controlled by `request_timeout_ms` civetweb option, 30 seconds default) which
-specify read/write timeout on client connection.
+(controlled by the `request_timeout_ms` CivetWeb option, 30 seconds default) 
+which specifies a read/write timeout on client connections.
+

+ 82 - 37
src/civetweb.c

@@ -149,12 +149,12 @@ clock_gettime(int clk_id, struct timespec *t)
 		return 0;
 		return 0;
 
 
 	} else if (clk_id == CLOCK_MONOTONIC) {
 	} else if (clk_id == CLOCK_MONOTONIC) {
-		static uint64_t start_time = 0;
+		static uint64_t clock_start_time = 0;
 		static mach_timebase_info_data_t timebase_ifo = {0, 0};
 		static mach_timebase_info_data_t timebase_ifo = {0, 0};
 
 
 		uint64_t now = mach_absolute_time();
 		uint64_t now = mach_absolute_time();
 
 
-		if (start_time == 0) {
+		if (clock_start_time == 0) {
 			kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
 			kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
 #if defined(DEBUG)
 #if defined(DEBUG)
 			assert(mach_status == KERN_SUCCESS);
 			assert(mach_status == KERN_SUCCESS);
@@ -162,10 +162,11 @@ clock_gettime(int clk_id, struct timespec *t)
 			/* appease "unused variable" warning for release builds */
 			/* appease "unused variable" warning for release builds */
 			(void)mach_status;
 			(void)mach_status;
 #endif
 #endif
-			start_time = now;
+			clock_start_time = now;
 		}
 		}
 
 
-		now = (uint64_t)((double)(now - start_time) * (double)timebase_ifo.numer
+		now = (uint64_t)((double)(now - clock_start_time)
+		                 * (double)timebase_ifo.numer
 		                 / (double)timebase_ifo.denom);
 		                 / (double)timebase_ifo.denom);
 
 
 		t->tv_sec = now / 1000000000;
 		t->tv_sec = now / 1000000000;
@@ -270,6 +271,7 @@ typedef long off_t;
 #endif /* !EWOULDBLOCK */
 #endif /* !EWOULDBLOCK */
 #define _POSIX_
 #define _POSIX_
 #define INT64_FMT "I64d"
 #define INT64_FMT "I64d"
+#define UINT64_FMT "I64u"
 
 
 #define WINCDECL __cdecl
 #define WINCDECL __cdecl
 #define SHUT_RD (0)
 #define SHUT_RD (0)
@@ -426,6 +428,7 @@ typedef unsigned short int in_port_t;
 #define ERRNO (errno)
 #define ERRNO (errno)
 #define INVALID_SOCKET (-1)
 #define INVALID_SOCKET (-1)
 #define INT64_FMT PRId64
 #define INT64_FMT PRId64
+#define UINT64_FMT PRIu64
 typedef int SOCKET;
 typedef int SOCKET;
 #define WINCDECL
 #define WINCDECL
 
 
@@ -1182,7 +1185,8 @@ struct mg_context {
 	    cfg_worker_threads;     /* The number of configured worker threads. */
 	    cfg_worker_threads;     /* The number of configured worker threads. */
 	pthread_t *workerthreadids; /* The worker thread IDs */
 	pthread_t *workerthreadids; /* The worker thread IDs */
 
 
-	unsigned long start_time; /* Server start time, used for authentication */
+	time_t start_time;        /* Server start time, used for authentication */
+	uint64_t auth_nonce_mask; /* Mask for all nonce values */
 	pthread_mutex_t nonce_mutex; /* Protects nonce_count */
 	pthread_mutex_t nonce_mutex; /* Protects nonce_count */
 	unsigned long nonce_count;   /* Used nonces, used for authentication */
 	unsigned long nonce_count;   /* Used nonces, used for authentication */
 
 
@@ -1276,7 +1280,7 @@ mg_atomic_inc(volatile int *addr)
 	 * so whatever you use, the other SDK is likely to raise a warning. */
 	 * so whatever you use, the other SDK is likely to raise a warning. */
 	ret = InterlockedIncrement((volatile long *)addr);
 	ret = InterlockedIncrement((volatile long *)addr);
 #elif defined(__GNUC__)                                                        \
 #elif defined(__GNUC__)                                                        \
-    && (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ > 0))
+    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
 	ret = __sync_add_and_fetch(addr, 1);
 	ret = __sync_add_and_fetch(addr, 1);
 #else
 #else
 	ret = (++(*addr));
 	ret = (++(*addr));
@@ -1294,7 +1298,7 @@ mg_atomic_dec(volatile int *addr)
 	 * so whatever you use, the other SDK is likely to raise a warning. */
 	 * so whatever you use, the other SDK is likely to raise a warning. */
 	ret = InterlockedDecrement((volatile long *)addr);
 	ret = InterlockedDecrement((volatile long *)addr);
 #elif defined(__GNUC__)                                                        \
 #elif defined(__GNUC__)                                                        \
-    && (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ > 0))
+    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
 	ret = __sync_sub_and_fetch(addr, 1);
 	ret = __sync_sub_and_fetch(addr, 1);
 #else
 #else
 	ret = (--(*addr));
 	ret = (--(*addr));
@@ -1578,6 +1582,7 @@ mg_vsnprintf(const struct mg_connection *conn,
 	buf[n] = '\0';
 	buf[n] = '\0';
 }
 }
 
 
+
 static void
 static void
 mg_snprintf(const struct mg_connection *conn,
 mg_snprintf(const struct mg_connection *conn,
             int *truncated,
             int *truncated,
@@ -1593,6 +1598,7 @@ mg_snprintf(const struct mg_connection *conn,
 	va_end(ap);
 	va_end(ap);
 }
 }
 
 
+
 static int
 static int
 get_option_index(const char *name)
 get_option_index(const char *name)
 {
 {
@@ -1606,6 +1612,7 @@ get_option_index(const char *name)
 	return -1;
 	return -1;
 }
 }
 
 
+
 const char *
 const char *
 mg_get_option(const struct mg_context *ctx, const char *name)
 mg_get_option(const struct mg_context *ctx, const char *name)
 {
 {
@@ -1619,18 +1626,21 @@ mg_get_option(const struct mg_context *ctx, const char *name)
 	}
 	}
 }
 }
 
 
+
 struct mg_context *
 struct mg_context *
 mg_get_context(const struct mg_connection *conn)
 mg_get_context(const struct mg_connection *conn)
 {
 {
 	return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
 	return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
 }
 }
 
 
+
 void *
 void *
 mg_get_user_data(const struct mg_context *ctx)
 mg_get_user_data(const struct mg_context *ctx)
 {
 {
 	return (ctx == NULL) ? NULL : ctx->user_data;
 	return (ctx == NULL) ? NULL : ctx->user_data;
 }
 }
 
 
+
 void
 void
 mg_set_user_connection_data(const struct mg_connection *conn, void *data)
 mg_set_user_connection_data(const struct mg_connection *conn, void *data)
 {
 {
@@ -1639,6 +1649,7 @@ mg_set_user_connection_data(const struct mg_connection *conn, void *data)
 	}
 	}
 }
 }
 
 
+
 void *
 void *
 mg_get_user_connection_data(const struct mg_connection *conn)
 mg_get_user_connection_data(const struct mg_connection *conn)
 {
 {
@@ -1648,6 +1659,7 @@ mg_get_user_connection_data(const struct mg_connection *conn)
 	return NULL;
 	return NULL;
 }
 }
 
 
+
 size_t
 size_t
 mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
 mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
 {
 {
@@ -1662,6 +1674,7 @@ mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
 	return i;
 	return i;
 }
 }
 
 
+
 int
 int
 mg_get_server_ports(const struct mg_context *ctx,
 mg_get_server_ports(const struct mg_context *ctx,
                     int size,
                     int size,
@@ -1700,6 +1713,7 @@ mg_get_server_ports(const struct mg_context *ctx,
 	return cnt;
 	return cnt;
 }
 }
 
 
+
 static void
 static void
 sockaddr_to_string(char *buf, size_t len, const union usa *usa)
 sockaddr_to_string(char *buf, size_t len, const union usa *usa)
 {
 {
@@ -1731,6 +1745,7 @@ sockaddr_to_string(char *buf, size_t len, const union usa *usa)
 #endif
 #endif
 }
 }
 
 
+
 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
  * included in all responses other than 100, 101, 5xx. */
  * included in all responses other than 100, 101, 5xx. */
 static void
 static void
@@ -1747,6 +1762,7 @@ gmt_time_string(char *buf, size_t buf_len, time_t *t)
 	}
 	}
 }
 }
 
 
+
 /* difftime for struct timespec. Return value is in seconds. */
 /* difftime for struct timespec. Return value is in seconds. */
 static double
 static double
 mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
 mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
@@ -1755,6 +1771,7 @@ mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
 	       + (double)(ts_now->tv_sec - ts_before->tv_sec);
 	       + (double)(ts_now->tv_sec - ts_before->tv_sec);
 }
 }
 
 
+
 /* Print error message to the opened error log stream. */
 /* Print error message to the opened error log stream. */
 void
 void
 mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 mg_cry(const struct mg_connection *conn, const char *fmt, ...)
@@ -1803,6 +1820,7 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 	}
 	}
 }
 }
 
 
+
 /* Return fake connection structure. Used for logging, if connection
 /* Return fake connection structure. Used for logging, if connection
  * is not applicable at the moment of logging. */
  * is not applicable at the moment of logging. */
 static struct mg_connection *
 static struct mg_connection *
@@ -1813,12 +1831,14 @@ fc(struct mg_context *ctx)
 	return &fake_connection;
 	return &fake_connection;
 }
 }
 
 
+
 const char *
 const char *
 mg_version(void)
 mg_version(void)
 {
 {
 	return CIVETWEB_VERSION;
 	return CIVETWEB_VERSION;
 }
 }
 
 
+
 const struct mg_request_info *
 const struct mg_request_info *
 mg_get_request_info(const struct mg_connection *conn)
 mg_get_request_info(const struct mg_connection *conn)
 {
 {
@@ -1828,6 +1848,7 @@ mg_get_request_info(const struct mg_connection *conn)
 	return &conn->request_info;
 	return &conn->request_info;
 }
 }
 
 
+
 /* Skip the characters until one of the delimiters characters found.
 /* Skip the characters until one of the delimiters characters found.
  * 0-terminate resulting word. Skip the delimiter and following whitespaces.
  * 0-terminate resulting word. Skip the delimiter and following whitespaces.
  * Advance pointer to buffer to the next word. Return found 0-terminated word.
  * Advance pointer to buffer to the next word. Return found 0-terminated word.
@@ -1882,6 +1903,7 @@ skip_quoted(char **buf,
 	return begin_word;
 	return begin_word;
 }
 }
 
 
+
 /* Simplified version of skip_quoted without quote char
 /* Simplified version of skip_quoted without quote char
  * and whitespace == delimiters */
  * and whitespace == delimiters */
 static char *
 static char *
@@ -1890,6 +1912,7 @@ skip(char **buf, const char *delimiters)
 	return skip_quoted(buf, delimiters, delimiters, 0);
 	return skip_quoted(buf, delimiters, delimiters, 0);
 }
 }
 
 
+
 /* Return HTTP header value, or NULL if not found. */
 /* Return HTTP header value, or NULL if not found. */
 static const char *
 static const char *
 get_header(const struct mg_request_info *ri, const char *name)
 get_header(const struct mg_request_info *ri, const char *name)
@@ -1906,6 +1929,7 @@ get_header(const struct mg_request_info *ri, const char *name)
 	return NULL;
 	return NULL;
 }
 }
 
 
+
 const char *
 const char *
 mg_get_header(const struct mg_connection *conn, const char *name)
 mg_get_header(const struct mg_connection *conn, const char *name)
 {
 {
@@ -1916,6 +1940,7 @@ mg_get_header(const struct mg_connection *conn, const char *name)
 	return get_header(&conn->request_info, name);
 	return get_header(&conn->request_info, name);
 }
 }
 
 
+
 /* A helper function for traversing a comma separated list of values.
 /* A helper function for traversing a comma separated list of values.
  * It returns a list pointer shifted to the next value, or NULL if the end
  * It returns a list pointer shifted to the next value, or NULL if the end
  * of the list found.
  * of the list found.
@@ -3343,6 +3368,42 @@ set_non_blocking_mode(SOCKET sock)
 	return 0;
 	return 0;
 }
 }
 #endif /* _WIN32 */
 #endif /* _WIN32 */
+/* End of initial operating system specific define block. */
+
+
+/* Get a random number (independent of C rand function) */
+static uint64_t
+get_random(void)
+{
+	static uint64_t lfsr = 0; /* Linear feedback shift register */
+	static uint64_t lcg = 0;  /* Linear congruential generator */
+	struct timespec now;
+
+	memset(&now, 0, sizeof(now));
+	clock_gettime(CLOCK_MONOTONIC, &now);
+
+	if (lfsr == 0) {
+		/* lfsr will be only 0 if has not been initialized,
+		 * so this code is called only once. */
+		lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
+		       ^ ((uint64_t)(ptrdiff_t)&now) ^ ((uint64_t)pthread_self())
+		       ^ (((uint64_t)time(NULL)) << 33);
+		lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
+		      + (uint64_t)(ptrdiff_t)&now;
+	} else {
+		/* Get the next step of both random number generators. */
+		lfsr = (lfsr >> 1)
+		       | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
+		          << 63);
+		lcg = lcg * 6364136223846793005 + 1442695040888963407;
+	}
+
+	/* Combining two pseudo-random number generators and a high resolution part
+	 * of the current server time will make it hard (impossible?) to guess the
+	 * next number. */
+	return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec);
+}
+
 
 
 /* Write data to the IO channel - opened file descriptor, socket or SSL
 /* Write data to the IO channel - opened file descriptor, socket or SSL
  * descriptor. Return number of bytes written. */
  * descriptor. Return number of bytes written. */
@@ -4829,7 +4890,7 @@ parse_auth_header(struct mg_connection *conn,
 {
 {
 	char *name, *value, *s;
 	char *name, *value, *s;
 	const char *auth_header;
 	const char *auth_header;
-	unsigned long nonce;
+	uint64_t nonce;
 
 
 	if (!ah || !conn) {
 	if (!ah || !conn) {
 		return 0;
 		return 0;
@@ -4890,13 +4951,13 @@ parse_auth_header(struct mg_connection *conn,
 		return 0;
 		return 0;
 	}
 	}
 	s = NULL;
 	s = NULL;
-	nonce = strtoul(ah->nonce, &s, 10);
+	nonce = strtoull(ah->nonce, &s, 10);
 	if ((s == NULL) || (*s != 0)) {
 	if ((s == NULL) || (*s != 0)) {
 		return 0;
 		return 0;
 	}
 	}
 
 
 	/* Convert the nonce from the client to a number. */
 	/* Convert the nonce from the client to a number. */
-	nonce ^= (uintptr_t)(conn->ctx);
+	nonce ^= conn->ctx->auth_nonce_mask;
 
 
 	/* The converted number corresponds to the time the nounce has been
 	/* The converted number corresponds to the time the nounce has been
 	 * created. This should not be earlier than the server start. */
 	 * created. This should not be earlier than the server start. */
@@ -4906,14 +4967,14 @@ parse_auth_header(struct mg_connection *conn,
 	/* However, the reasonable default is to not accept a nonce from a
 	/* However, the reasonable default is to not accept a nonce from a
 	 * previous start, so if anyone changed the access rights between
 	 * previous start, so if anyone changed the access rights between
 	 * two restarts, a new login is required. */
 	 * two restarts, a new login is required. */
-	if (nonce < conn->ctx->start_time) {
+	if (nonce < (uint64_t)conn->ctx->start_time) {
 		/* nonce is from a previous start of the server and no longer valid
 		/* nonce is from a previous start of the server and no longer valid
 		 * (replay attack?) */
 		 * (replay attack?) */
 		return 0;
 		return 0;
 	}
 	}
 	/* Check if the nonce is too high, so it has not (yet) been used by the
 	/* Check if the nonce is too high, so it has not (yet) been used by the
 	 * server. */
 	 * server. */
-	if (nonce >= conn->ctx->start_time + conn->ctx->nonce_count) {
+	if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
 		return 0;
 		return 0;
 	}
 	}
 #endif
 #endif
@@ -5143,14 +5204,14 @@ send_authorization_request(struct mg_connection *conn)
 	time_t curtime = time(NULL);
 	time_t curtime = time(NULL);
 
 
 	if (conn && conn->ctx) {
 	if (conn && conn->ctx) {
-		unsigned long nonce = (unsigned long)(conn->ctx->start_time);
+		uint64_t nonce = (uint64_t)(conn->ctx->start_time);
 
 
 		(void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
 		(void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
 		nonce += conn->ctx->nonce_count;
 		nonce += conn->ctx->nonce_count;
 		++conn->ctx->nonce_count;
 		++conn->ctx->nonce_count;
 		(void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
 		(void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
 
 
-		nonce ^= (uintptr_t)(conn->ctx);
+		nonce ^= conn->ctx->auth_nonce_mask;
 		conn->status_code = 401;
 		conn->status_code = 401;
 		conn->must_close = 1;
 		conn->must_close = 1;
 
 
@@ -5162,7 +5223,7 @@ send_authorization_request(struct mg_connection *conn)
 		          "Connection: %s\r\n"
 		          "Connection: %s\r\n"
 		          "Content-Length: 0\r\n"
 		          "Content-Length: 0\r\n"
 		          "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
 		          "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
-		          "nonce=\"%lu\"\r\n\r\n",
+		          "nonce=\"%" UINT64_FMT "\"\r\n\r\n",
 		          date,
 		          date,
 		          suggest_connection_header(conn),
 		          suggest_connection_header(conn),
 		          conn->ctx->config[AUTHENTICATION_DOMAIN],
 		          conn->ctx->config[AUTHENTICATION_DOMAIN],
@@ -8284,27 +8345,7 @@ mg_websocket_client_write(struct mg_connection *conn,
 {
 {
 	int retval = -1;
 	int retval = -1;
 	char *masked_data = (char *)mg_malloc(((dataLen + 7) / 4) * 4);
 	char *masked_data = (char *)mg_malloc(((dataLen + 7) / 4) * 4);
-	uint32_t masking_key;
-	static uint64_t lfsr = 0;
-	static uint64_t lcg = 0;
-	struct timespec now;
-
-	memset(&now, 0, sizeof(now));
-	clock_gettime(CLOCK_MONOTONIC, &now);
-
-	if (lfsr == 0) {
-		lfsr = (((uint64_t)now.tv_sec) << 21) ^ (uint64_t)now.tv_nsec
-		       ^ (uint64_t)&dataLen;
-		lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
-		      + (uint64_t)data;
-	} else {
-		lfsr = (lfsr >> 1)
-		       | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
-		          << 63);
-		lcg = lcg * 6364136223846793005 + 1442695040888963407;
-	}
-
-	masking_key = (uint32_t)lfsr ^ (uint32_t)lcg ^ (uint32_t)now.tv_nsec;
+	uint32_t masking_key = (uint32_t)get_random();
 
 
 	if (masked_data == NULL) {
 	if (masked_data == NULL) {
 		/* Return -1 in an error case */
 		/* Return -1 in an error case */
@@ -11641,7 +11682,7 @@ master_thread_run(void *thread_func_param)
 	pthread_setspecific(sTlsKey, &tls);
 	pthread_setspecific(sTlsKey, &tls);
 
 
 	/* Server starts *now* */
 	/* Server starts *now* */
-	ctx->start_time = (unsigned long)time(NULL);
+	ctx->start_time = time(NULL);
 
 
 	/* Allocate memory for the listening sockets, and start the server */
 	/* Allocate memory for the listening sockets, and start the server */
 	pfd =
 	pfd =
@@ -11900,6 +11941,10 @@ mg_start(const struct mg_callbacks *callbacks,
 		return NULL;
 		return NULL;
 	}
 	}
 
 
+	/* Random number generator will initialize at the first call */
+	ctx->auth_nonce_mask =
+	    (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
+
 	if (mg_atomic_inc(&sTlsInit) == 1) {
 	if (mg_atomic_inc(&sTlsInit) == 1) {
 
 
 #if defined(_WIN32) && !defined(__SYMBIAN32__)
 #if defined(_WIN32) && !defined(__SYMBIAN32__)