aboutsummaryrefslogtreecommitdiffstats
path: root/app/nginx/src/os
diff options
context:
space:
mode:
Diffstat (limited to 'app/nginx/src/os')
-rw-r--r--app/nginx/src/os/unix/ngx_alloc.c90
-rw-r--r--app/nginx/src/os/unix/ngx_alloc.h45
-rw-r--r--app/nginx/src/os/unix/ngx_atomic.h313
-rw-r--r--app/nginx/src/os/unix/ngx_channel.c253
-rw-r--r--app/nginx/src/os/unix/ngx_channel.h34
-rw-r--r--app/nginx/src/os/unix/ngx_daemon.c70
-rw-r--r--app/nginx/src/os/unix/ngx_darwin.h23
-rw-r--r--app/nginx/src/os/unix/ngx_darwin_config.h97
-rw-r--r--app/nginx/src/os/unix/ngx_darwin_init.c198
-rw-r--r--app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c206
-rw-r--r--app/nginx/src/os/unix/ngx_dlopen.c28
-rw-r--r--app/nginx/src/os/unix/ngx_dlopen.h31
-rw-r--r--app/nginx/src/os/unix/ngx_errno.c87
-rw-r--r--app/nginx/src/os/unix/ngx_errno.h79
-rw-r--r--app/nginx/src/os/unix/ngx_file_aio_read.c216
-rw-r--r--app/nginx/src/os/unix/ngx_files.c906
-rw-r--r--app/nginx/src/os/unix/ngx_files.h395
-rw-r--r--app/nginx/src/os/unix/ngx_freebsd.h25
-rw-r--r--app/nginx/src/os/unix/ngx_freebsd_config.h123
-rw-r--r--app/nginx/src/os/unix/ngx_freebsd_init.c262
-rw-r--r--app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c333
-rw-r--r--app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h82
-rw-r--r--app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h155
-rw-r--r--app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h82
-rw-r--r--app/nginx/src/os/unix/ngx_gcc_atomic_x86.h127
-rw-r--r--app/nginx/src/os/unix/ngx_linux.h16
-rw-r--r--app/nginx/src/os/unix/ngx_linux_aio_read.c148
-rw-r--r--app/nginx/src/os/unix/ngx_linux_config.h123
-rw-r--r--app/nginx/src/os/unix/ngx_linux_init.c60
-rw-r--r--app/nginx/src/os/unix/ngx_linux_sendfile_chain.c442
-rw-r--r--app/nginx/src/os/unix/ngx_os.h102
-rw-r--r--app/nginx/src/os/unix/ngx_posix_config.h171
-rw-r--r--app/nginx/src/os/unix/ngx_posix_init.c134
-rw-r--r--app/nginx/src/os/unix/ngx_process.c630
-rw-r--r--app/nginx/src/os/unix/ngx_process.h88
-rw-r--r--app/nginx/src/os/unix/ngx_process_cycle.c1196
-rw-r--r--app/nginx/src/os/unix/ngx_process_cycle.h61
-rw-r--r--app/nginx/src/os/unix/ngx_readv_chain.c214
-rw-r--r--app/nginx/src/os/unix/ngx_recv.c167
-rw-r--r--app/nginx/src/os/unix/ngx_send.c73
-rw-r--r--app/nginx/src/os/unix/ngx_setaffinity.c53
-rw-r--r--app/nginx/src/os/unix/ngx_setaffinity.h37
-rw-r--r--app/nginx/src/os/unix/ngx_setproctitle.c135
-rw-r--r--app/nginx/src/os/unix/ngx_setproctitle.h52
-rw-r--r--app/nginx/src/os/unix/ngx_shmem.c126
-rw-r--r--app/nginx/src/os/unix/ngx_shmem.h29
-rw-r--r--app/nginx/src/os/unix/ngx_socket.c116
-rw-r--r--app/nginx/src/os/unix/ngx_socket.h64
-rw-r--r--app/nginx/src/os/unix/ngx_solaris.h16
-rw-r--r--app/nginx/src/os/unix/ngx_solaris_config.h112
-rw-r--r--app/nginx/src/os/unix/ngx_solaris_init.c77
-rw-r--r--app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c228
-rw-r--r--app/nginx/src/os/unix/ngx_sunpro_amd64.il43
-rw-r--r--app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h61
-rw-r--r--app/nginx/src/os/unix/ngx_sunpro_sparc64.il36
-rw-r--r--app/nginx/src/os/unix/ngx_sunpro_x86.il44
-rw-r--r--app/nginx/src/os/unix/ngx_thread.h71
-rw-r--r--app/nginx/src/os/unix/ngx_thread_cond.c76
-rw-r--r--app/nginx/src/os/unix/ngx_thread_id.c70
-rw-r--r--app/nginx/src/os/unix/ngx_thread_mutex.c165
-rw-r--r--app/nginx/src/os/unix/ngx_time.c104
-rw-r--r--app/nginx/src/os/unix/ngx_time.h66
-rw-r--r--app/nginx/src/os/unix/ngx_udp_recv.c72
-rw-r--r--app/nginx/src/os/unix/ngx_udp_send.c56
-rw-r--r--app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c245
-rw-r--r--app/nginx/src/os/unix/ngx_user.c90
-rw-r--r--app/nginx/src/os/unix/ngx_user.h24
-rw-r--r--app/nginx/src/os/unix/ngx_writev_chain.c216
-rw-r--r--app/nginx/src/os/win32/nginx.icobin0 -> 1350 bytes
-rw-r--r--app/nginx/src/os/win32/nginx.rc6
-rw-r--r--app/nginx/src/os/win32/nginx_icon16.xpm24
-rw-r--r--app/nginx/src/os/win32/nginx_icon32.xpm39
-rw-r--r--app/nginx/src/os/win32/nginx_icon48.xpm55
-rw-r--r--app/nginx/src/os/win32/ngx_alloc.c44
-rw-r--r--app/nginx/src/os/win32/ngx_alloc.h27
-rw-r--r--app/nginx/src/os/win32/ngx_atomic.h69
-rw-r--r--app/nginx/src/os/win32/ngx_dlopen.c22
-rw-r--r--app/nginx/src/os/win32/ngx_dlopen.h32
-rw-r--r--app/nginx/src/os/win32/ngx_errno.c60
-rw-r--r--app/nginx/src/os/win32/ngx_errno.h71
-rw-r--r--app/nginx/src/os/win32/ngx_event_log.c99
-rw-r--r--app/nginx/src/os/win32/ngx_files.c883
-rw-r--r--app/nginx/src/os/win32/ngx_files.h273
-rw-r--r--app/nginx/src/os/win32/ngx_os.h68
-rw-r--r--app/nginx/src/os/win32/ngx_process.c238
-rw-r--r--app/nginx/src/os/win32/ngx_process.h78
-rw-r--r--app/nginx/src/os/win32/ngx_process_cycle.c1042
-rw-r--r--app/nginx/src/os/win32/ngx_process_cycle.h44
-rw-r--r--app/nginx/src/os/win32/ngx_service.c134
-rw-r--r--app/nginx/src/os/win32/ngx_shmem.c161
-rw-r--r--app/nginx/src/os/win32/ngx_shmem.h33
-rw-r--r--app/nginx/src/os/win32/ngx_socket.c34
-rw-r--r--app/nginx/src/os/win32/ngx_socket.h207
-rw-r--r--app/nginx/src/os/win32/ngx_stat.c34
-rw-r--r--app/nginx/src/os/win32/ngx_thread.c30
-rw-r--r--app/nginx/src/os/win32/ngx_thread.h27
-rw-r--r--app/nginx/src/os/win32/ngx_time.c83
-rw-r--r--app/nginx/src/os/win32/ngx_time.h51
-rw-r--r--app/nginx/src/os/win32/ngx_udp_wsarecv.c149
-rw-r--r--app/nginx/src/os/win32/ngx_user.c23
-rw-r--r--app/nginx/src/os/win32/ngx_user.h25
-rw-r--r--app/nginx/src/os/win32/ngx_win32_config.h282
-rw-r--r--app/nginx/src/os/win32/ngx_win32_init.c297
-rw-r--r--app/nginx/src/os/win32/ngx_wsarecv.c174
-rw-r--r--app/nginx/src/os/win32/ngx_wsarecv_chain.c106
-rw-r--r--app/nginx/src/os/win32/ngx_wsasend.c185
-rw-r--r--app/nginx/src/os/win32/ngx_wsasend_chain.c292
107 files changed, 15870 insertions, 0 deletions
diff --git a/app/nginx/src/os/unix/ngx_alloc.c b/app/nginx/src/os/unix/ngx_alloc.c
new file mode 100644
index 0000000..5c2f787
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_alloc.c
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_uint_t ngx_pagesize;
+ngx_uint_t ngx_pagesize_shift;
+ngx_uint_t ngx_cacheline_size;
+
+
+void *
+ngx_alloc(size_t size, ngx_log_t *log)
+{
+ void *p;
+
+ p = malloc(size);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "malloc(%uz) failed", size);
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);
+
+ return p;
+}
+
+
+void *
+ngx_calloc(size_t size, ngx_log_t *log)
+{
+ void *p;
+
+ p = ngx_alloc(size, log);
+
+ if (p) {
+ ngx_memzero(p, size);
+ }
+
+ return p;
+}
+
+
+#if (NGX_HAVE_POSIX_MEMALIGN)
+
+void *
+ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
+{
+ void *p;
+ int err;
+
+ err = posix_memalign(&p, alignment, size);
+
+ if (err) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "posix_memalign(%uz, %uz) failed", alignment, size);
+ p = NULL;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
+ "posix_memalign: %p:%uz @%uz", p, size, alignment);
+
+ return p;
+}
+
+#elif (NGX_HAVE_MEMALIGN)
+
+void *
+ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
+{
+ void *p;
+
+ p = memalign(alignment, size);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "memalign(%uz, %uz) failed", alignment, size);
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
+ "memalign: %p:%uz @%uz", p, size, alignment);
+
+ return p;
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_alloc.h b/app/nginx/src/os/unix/ngx_alloc.h
new file mode 100644
index 0000000..655db25
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_alloc.h
@@ -0,0 +1,45 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ALLOC_H_INCLUDED_
+#define _NGX_ALLOC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void *ngx_alloc(size_t size, ngx_log_t *log);
+void *ngx_calloc(size_t size, ngx_log_t *log);
+
+#define ngx_free free
+
+
+/*
+ * Linux has memalign() or posix_memalign()
+ * Solaris has memalign()
+ * FreeBSD 7.0 has posix_memalign(), besides, early version's malloc()
+ * aligns allocations bigger than page size at the page boundary
+ */
+
+#if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN)
+
+void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log);
+
+#else
+
+#define ngx_memalign(alignment, size, log) ngx_alloc(size, log)
+
+#endif
+
+
+extern ngx_uint_t ngx_pagesize;
+extern ngx_uint_t ngx_pagesize_shift;
+extern ngx_uint_t ngx_cacheline_size;
+
+
+#endif /* _NGX_ALLOC_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_atomic.h b/app/nginx/src/os/unix/ngx_atomic.h
new file mode 100644
index 0000000..74b8b7f
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_atomic.h
@@ -0,0 +1,313 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ATOMIC_H_INCLUDED_
+#define _NGX_ATOMIC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_LIBATOMIC)
+
+#define AO_REQUIRE_CAS
+#include <atomic_ops.h>
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+typedef long ngx_atomic_int_t;
+typedef AO_t ngx_atomic_uint_t;
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+
+#if (NGX_PTR_SIZE == 8)
+#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)
+#else
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+#endif
+
+#define ngx_atomic_cmp_set(lock, old, new) \
+ AO_compare_and_swap(lock, old, new)
+#define ngx_atomic_fetch_add(value, add) \
+ AO_fetch_and_add(value, add)
+#define ngx_memory_barrier() AO_nop()
+#define ngx_cpu_pause()
+
+
+#elif (NGX_DARWIN_ATOMIC)
+
+/*
+ * use Darwin 8 atomic(3) and barrier(3) operations
+ * optimized at run-time for UP and SMP
+ */
+
+#include <libkern/OSAtomic.h>
+
+/* "bool" conflicts with perl's CORE/handy.h */
+#if 0
+#undef bool
+#endif
+
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+#if (NGX_PTR_SIZE == 8)
+
+typedef int64_t ngx_atomic_int_t;
+typedef uint64_t ngx_atomic_uint_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)
+
+#define ngx_atomic_cmp_set(lock, old, new) \
+ OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock)
+
+#define ngx_atomic_fetch_add(value, add) \
+ (OSAtomicAdd64(add, (int64_t *) value) - add)
+
+#else
+
+typedef int32_t ngx_atomic_int_t;
+typedef uint32_t ngx_atomic_uint_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+
+#define ngx_atomic_cmp_set(lock, old, new) \
+ OSAtomicCompareAndSwap32Barrier(old, new, (int32_t *) lock)
+
+#define ngx_atomic_fetch_add(value, add) \
+ (OSAtomicAdd32(add, (int32_t *) value) - add)
+
+#endif
+
+#define ngx_memory_barrier() OSMemoryBarrier()
+
+#define ngx_cpu_pause()
+
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+
+
+#elif (NGX_HAVE_GCC_ATOMIC)
+
+/* GCC 4.1 builtin atomic operations */
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+typedef long ngx_atomic_int_t;
+typedef unsigned long ngx_atomic_uint_t;
+
+#if (NGX_PTR_SIZE == 8)
+#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)
+#else
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+#endif
+
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+
+
+#define ngx_atomic_cmp_set(lock, old, set) \
+ __sync_bool_compare_and_swap(lock, old, set)
+
+#define ngx_atomic_fetch_add(value, add) \
+ __sync_fetch_and_add(value, add)
+
+#define ngx_memory_barrier() __sync_synchronize()
+
+#if ( __i386__ || __i386 || __amd64__ || __amd64 )
+#define ngx_cpu_pause() __asm__ ("pause")
+#else
+#define ngx_cpu_pause()
+#endif
+
+
+#elif ( __i386__ || __i386 )
+
+typedef int32_t ngx_atomic_int_t;
+typedef uint32_t ngx_atomic_uint_t;
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+
+
+#if ( __SUNPRO_C )
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set);
+
+ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add);
+
+/*
+ * Sun Studio 12 exits with segmentation fault on '__asm ("pause")',
+ * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_x86.il
+ */
+
+void
+ngx_cpu_pause(void);
+
+/* the code in src/os/unix/ngx_sunpro_x86.il */
+
+#define ngx_memory_barrier() __asm (".volatile"); __asm (".nonvolatile")
+
+
+#else /* ( __GNUC__ || __INTEL_COMPILER ) */
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+#include "ngx_gcc_atomic_x86.h"
+
+#endif
+
+
+#elif ( __amd64__ || __amd64 )
+
+typedef int64_t ngx_atomic_int_t;
+typedef uint64_t ngx_atomic_uint_t;
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)
+
+
+#if ( __SUNPRO_C )
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set);
+
+ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add);
+
+/*
+ * Sun Studio 12 exits with segmentation fault on '__asm ("pause")',
+ * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_amd64.il
+ */
+
+void
+ngx_cpu_pause(void);
+
+/* the code in src/os/unix/ngx_sunpro_amd64.il */
+
+#define ngx_memory_barrier() __asm (".volatile"); __asm (".nonvolatile")
+
+
+#else /* ( __GNUC__ || __INTEL_COMPILER ) */
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+#include "ngx_gcc_atomic_amd64.h"
+
+#endif
+
+
+#elif ( __sparc__ || __sparc || __sparcv9 )
+
+#if (NGX_PTR_SIZE == 8)
+
+typedef int64_t ngx_atomic_int_t;
+typedef uint64_t ngx_atomic_uint_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)
+
+#else
+
+typedef int32_t ngx_atomic_int_t;
+typedef uint32_t ngx_atomic_uint_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+
+#endif
+
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+
+
+#if ( __SUNPRO_C )
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+#include "ngx_sunpro_atomic_sparc64.h"
+
+
+#else /* ( __GNUC__ || __INTEL_COMPILER ) */
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+#include "ngx_gcc_atomic_sparc64.h"
+
+#endif
+
+
+#elif ( __powerpc__ || __POWERPC__ )
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+#if (NGX_PTR_SIZE == 8)
+
+typedef int64_t ngx_atomic_int_t;
+typedef uint64_t ngx_atomic_uint_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)
+
+#else
+
+typedef int32_t ngx_atomic_int_t;
+typedef uint32_t ngx_atomic_uint_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+
+#endif
+
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+
+
+#include "ngx_gcc_atomic_ppc.h"
+
+#endif
+
+
+#if !(NGX_HAVE_ATOMIC_OPS)
+
+#define NGX_HAVE_ATOMIC_OPS 0
+
+typedef int32_t ngx_atomic_int_t;
+typedef uint32_t ngx_atomic_uint_t;
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ if (*lock == old) {
+ *lock = set;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ ngx_atomic_int_t old;
+
+ old = *value;
+ *value += add;
+
+ return old;
+}
+
+#define ngx_memory_barrier()
+#define ngx_cpu_pause()
+
+#endif
+
+
+void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin);
+
+#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))
+#define ngx_unlock(lock) *(lock) = 0
+
+
+#endif /* _NGX_ATOMIC_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_channel.c b/app/nginx/src/os/unix/ngx_channel.c
new file mode 100644
index 0000000..1efa066
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_channel.c
@@ -0,0 +1,253 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_channel.h>
+
+
+ngx_int_t
+ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+ ngx_log_t *log)
+{
+ ssize_t n;
+ ngx_err_t err;
+ struct iovec iov[1];
+ struct msghdr msg;
+
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+
+ union {
+ struct cmsghdr cm;
+ char space[CMSG_SPACE(sizeof(int))];
+ } cmsg;
+
+ if (ch->fd == -1) {
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+
+ } else {
+ msg.msg_control = (caddr_t) &cmsg;
+ msg.msg_controllen = sizeof(cmsg);
+
+ ngx_memzero(&cmsg, sizeof(cmsg));
+
+ cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg.cm.cmsg_level = SOL_SOCKET;
+ cmsg.cm.cmsg_type = SCM_RIGHTS;
+
+ /*
+ * We have to use ngx_memcpy() instead of simple
+ * *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
+ * because some gcc 4.4 with -O2/3/s optimization issues the warning:
+ * dereferencing type-punned pointer will break strict-aliasing rules
+ *
+ * Fortunately, gcc with -O1 compiles this ngx_memcpy()
+ * in the same simple assignment as in the code above
+ */
+
+ ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int));
+ }
+
+ msg.msg_flags = 0;
+
+#else
+
+ if (ch->fd == -1) {
+ msg.msg_accrights = NULL;
+ msg.msg_accrightslen = 0;
+
+ } else {
+ msg.msg_accrights = (caddr_t) &ch->fd;
+ msg.msg_accrightslen = sizeof(int);
+ }
+
+#endif
+
+ iov[0].iov_base = (char *) ch;
+ iov[0].iov_len = size;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ n = sendmsg(s, &msg, 0);
+
+ if (n == -1) {
+ err = ngx_errno;
+ if (err == NGX_EAGAIN) {
+ return NGX_AGAIN;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
+{
+ ssize_t n;
+ ngx_err_t err;
+ struct iovec iov[1];
+ struct msghdr msg;
+
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+ union {
+ struct cmsghdr cm;
+ char space[CMSG_SPACE(sizeof(int))];
+ } cmsg;
+#else
+ int fd;
+#endif
+
+ iov[0].iov_base = (char *) ch;
+ iov[0].iov_len = size;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+ msg.msg_control = (caddr_t) &cmsg;
+ msg.msg_controllen = sizeof(cmsg);
+#else
+ msg.msg_accrights = (caddr_t) &fd;
+ msg.msg_accrightslen = sizeof(int);
+#endif
+
+ n = recvmsg(s, &msg, 0);
+
+ if (n == -1) {
+ err = ngx_errno;
+ if (err == NGX_EAGAIN) {
+ return NGX_AGAIN;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "recvmsg() failed");
+ return NGX_ERROR;
+ }
+
+ if (n == 0) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "recvmsg() returned zero");
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n < sizeof(ngx_channel_t)) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "recvmsg() returned not enough data: %z", n);
+ return NGX_ERROR;
+ }
+
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+
+ if (ch->command == NGX_CMD_OPEN_CHANNEL) {
+
+ if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "recvmsg() returned too small ancillary data");
+ return NGX_ERROR;
+ }
+
+ if (cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.cm.cmsg_type != SCM_RIGHTS)
+ {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "recvmsg() returned invalid ancillary data "
+ "level %d or type %d",
+ cmsg.cm.cmsg_level, cmsg.cm.cmsg_type);
+ return NGX_ERROR;
+ }
+
+ /* ch->fd = *(int *) CMSG_DATA(&cmsg.cm); */
+
+ ngx_memcpy(&ch->fd, CMSG_DATA(&cmsg.cm), sizeof(int));
+ }
+
+ if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "recvmsg() truncated data");
+ }
+
+#else
+
+ if (ch->command == NGX_CMD_OPEN_CHANNEL) {
+ if (msg.msg_accrightslen != sizeof(int)) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "recvmsg() returned no ancillary data");
+ return NGX_ERROR;
+ }
+
+ ch->fd = fd;
+ }
+
+#endif
+
+ return n;
+}
+
+
+ngx_int_t
+ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event,
+ ngx_event_handler_pt handler)
+{
+ ngx_event_t *ev, *rev, *wev;
+ ngx_connection_t *c;
+
+ c = ngx_get_connection(fd, cycle->log);
+
+ if (c == NULL) {
+ return NGX_ERROR;
+ }
+
+ c->pool = cycle->pool;
+
+ rev = c->read;
+ wev = c->write;
+
+ rev->log = cycle->log;
+ wev->log = cycle->log;
+
+ rev->channel = 1;
+ wev->channel = 1;
+
+ ev = (event == NGX_READ_EVENT) ? rev : wev;
+
+ ev->handler = handler;
+
+ if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
+ if (ngx_add_conn(c) == NGX_ERROR) {
+ ngx_free_connection(c);
+ return NGX_ERROR;
+ }
+
+ } else {
+ if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
+ ngx_free_connection(c);
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+void
+ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log)
+{
+ if (close(fd[0]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
+ }
+
+ if (close(fd[1]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_channel.h b/app/nginx/src/os/unix/ngx_channel.h
new file mode 100644
index 0000000..362cc64
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_channel.h
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CHANNEL_H_INCLUDED_
+#define _NGX_CHANNEL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+typedef struct {
+ ngx_uint_t command;
+ ngx_pid_t pid;
+ ngx_int_t slot;
+ ngx_fd_t fd;
+} ngx_channel_t;
+
+
+ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+ ngx_log_t *log);
+ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+ ngx_log_t *log);
+ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd,
+ ngx_int_t event, ngx_event_handler_pt handler);
+void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log);
+
+
+#endif /* _NGX_CHANNEL_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_daemon.c b/app/nginx/src/os/unix/ngx_daemon.c
new file mode 100644
index 0000000..ab67211
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_daemon.c
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_int_t
+ngx_daemon(ngx_log_t *log)
+{
+ int fd;
+
+ switch (fork()) {
+ case -1:
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
+ return NGX_ERROR;
+
+ case 0:
+ break;
+
+ default:
+ exit(0);
+ }
+
+ ngx_pid = ngx_getpid();
+
+ if (setsid() == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
+ return NGX_ERROR;
+ }
+
+ umask(0);
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "open(\"/dev/null\") failed");
+ return NGX_ERROR;
+ }
+
+ if (dup2(fd, STDIN_FILENO) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
+ return NGX_ERROR;
+ }
+
+ if (dup2(fd, STDOUT_FILENO) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
+ return NGX_ERROR;
+ }
+
+#if 0
+ if (dup2(fd, STDERR_FILENO) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
+ return NGX_ERROR;
+ }
+#endif
+
+ if (fd > STDERR_FILENO) {
+ if (close(fd) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
diff --git a/app/nginx/src/os/unix/ngx_darwin.h b/app/nginx/src/os/unix/ngx_darwin.h
new file mode 100644
index 0000000..4d01b26
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_darwin.h
@@ -0,0 +1,23 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_DARWIN_H_INCLUDED_
+#define _NGX_DARWIN_H_INCLUDED_
+
+
+void ngx_debug_init(void);
+ngx_chain_t *ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+extern int ngx_darwin_kern_osreldate;
+extern int ngx_darwin_hw_ncpu;
+extern u_long ngx_darwin_net_inet_tcp_sendspace;
+
+extern ngx_uint_t ngx_debug_malloc;
+
+
+#endif /* _NGX_DARWIN_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_darwin_config.h b/app/nginx/src/os/unix/ngx_darwin_config.h
new file mode 100644
index 0000000..cfe3ce2
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_darwin_config.h
@@ -0,0 +1,97 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_DARWIN_CONFIG_H_INCLUDED_
+#define _NGX_DARWIN_CONFIG_H_INCLUDED_
+
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stddef.h> /* offsetof() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <glob.h>
+#include <sys/mount.h> /* statfs() */
+
+#include <sys/filio.h> /* FIONBIO */
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h> /* TCP_NODELAY */
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+
+#include <sys/sysctl.h>
+#include <xlocale.h>
+
+#include <dlfcn.h>
+
+
+#ifndef IOV_MAX
+#define IOV_MAX 64
+#endif
+
+
+#include <ngx_auto_config.h>
+
+
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
+#if (NGX_HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (NGX_HAVE_KQUEUE)
+#include <sys/event.h>
+#endif
+
+
+#define NGX_LISTEN_BACKLOG -1
+
+
+#ifndef NGX_HAVE_INHERITED_NONBLOCK
+#define NGX_HAVE_INHERITED_NONBLOCK 1
+#endif
+
+
+#ifndef NGX_HAVE_CASELESS_FILESYSTEM
+#define NGX_HAVE_CASELESS_FILESYSTEM 1
+#endif
+
+
+#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define NGX_HAVE_DEBUG_MALLOC 1
+
+
+extern char **environ;
+
+
+#endif /* _NGX_DARWIN_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_darwin_init.c b/app/nginx/src/os/unix/ngx_darwin_init.c
new file mode 100644
index 0000000..aabe02f
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_darwin_init.c
@@ -0,0 +1,198 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+char ngx_darwin_kern_ostype[16];
+char ngx_darwin_kern_osrelease[128];
+int ngx_darwin_hw_ncpu;
+int ngx_darwin_kern_ipc_somaxconn;
+u_long ngx_darwin_net_inet_tcp_sendspace;
+
+ngx_uint_t ngx_debug_malloc;
+
+
+static ngx_os_io_t ngx_darwin_io = {
+ ngx_unix_recv,
+ ngx_readv_chain,
+ ngx_udp_unix_recv,
+ ngx_unix_send,
+ ngx_udp_unix_send,
+ ngx_udp_unix_sendmsg_chain,
+#if (NGX_HAVE_SENDFILE)
+ ngx_darwin_sendfile_chain,
+ NGX_IO_SENDFILE
+#else
+ ngx_writev_chain,
+ 0
+#endif
+};
+
+
+typedef struct {
+ char *name;
+ void *value;
+ size_t size;
+ ngx_uint_t exists;
+} sysctl_t;
+
+
+sysctl_t sysctls[] = {
+ { "hw.ncpu",
+ &ngx_darwin_hw_ncpu,
+ sizeof(ngx_darwin_hw_ncpu), 0 },
+
+ { "net.inet.tcp.sendspace",
+ &ngx_darwin_net_inet_tcp_sendspace,
+ sizeof(ngx_darwin_net_inet_tcp_sendspace), 0 },
+
+ { "kern.ipc.somaxconn",
+ &ngx_darwin_kern_ipc_somaxconn,
+ sizeof(ngx_darwin_kern_ipc_somaxconn), 0 },
+
+ { NULL, NULL, 0, 0 }
+};
+
+
+void
+ngx_debug_init(void)
+{
+#if (NGX_DEBUG_MALLOC)
+
+ /*
+ * MacOSX 10.6, 10.7: MallocScribble fills freed memory with 0x55
+ * and fills allocated memory with 0xAA.
+ * MacOSX 10.4, 10.5: MallocScribble fills freed memory with 0x55,
+ * MallocPreScribble fills allocated memory with 0xAA.
+ * MacOSX 10.3: MallocScribble fills freed memory with 0x55,
+ * and no way to fill allocated memory.
+ */
+
+ setenv("MallocScribble", "1", 0);
+
+ ngx_debug_malloc = 1;
+
+#else
+
+ if (getenv("MallocScribble")) {
+ ngx_debug_malloc = 1;
+ }
+
+#endif
+}
+
+
+ngx_int_t
+ngx_os_specific_init(ngx_log_t *log)
+{
+ size_t size;
+ ngx_err_t err;
+ ngx_uint_t i;
+
+ size = sizeof(ngx_darwin_kern_ostype);
+ if (sysctlbyname("kern.ostype", ngx_darwin_kern_ostype, &size, NULL, 0)
+ == -1)
+ {
+ err = ngx_errno;
+
+ if (err != NGX_ENOENT) {
+
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "sysctlbyname(kern.ostype) failed");
+
+ if (err != NGX_ENOMEM) {
+ return NGX_ERROR;
+ }
+
+ ngx_darwin_kern_ostype[size - 1] = '\0';
+ }
+ }
+
+ size = sizeof(ngx_darwin_kern_osrelease);
+ if (sysctlbyname("kern.osrelease", ngx_darwin_kern_osrelease, &size,
+ NULL, 0)
+ == -1)
+ {
+ err = ngx_errno;
+
+ if (err != NGX_ENOENT) {
+
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "sysctlbyname(kern.osrelease) failed");
+
+ if (err != NGX_ENOMEM) {
+ return NGX_ERROR;
+ }
+
+ ngx_darwin_kern_osrelease[size - 1] = '\0';
+ }
+ }
+
+ for (i = 0; sysctls[i].name; i++) {
+ size = sysctls[i].size;
+
+ if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0)
+ == 0)
+ {
+ sysctls[i].exists = 1;
+ continue;
+ }
+
+ err = ngx_errno;
+
+ if (err == NGX_ENOENT) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "sysctlbyname(%s) failed", sysctls[i].name);
+ return NGX_ERROR;
+ }
+
+ ngx_ncpu = ngx_darwin_hw_ncpu;
+
+ if (ngx_darwin_kern_ipc_somaxconn > 32767) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "sysctl kern.ipc.somaxconn must be less than 32768");
+ return NGX_ERROR;
+ }
+
+ ngx_tcp_nodelay_and_tcp_nopush = 1;
+
+ ngx_os_io = ngx_darwin_io;
+
+ return NGX_OK;
+}
+
+
+void
+ngx_os_specific_status(ngx_log_t *log)
+{
+ u_long value;
+ ngx_uint_t i;
+
+ if (ngx_darwin_kern_ostype[0]) {
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
+ ngx_darwin_kern_ostype, ngx_darwin_kern_osrelease);
+ }
+
+ for (i = 0; sysctls[i].name; i++) {
+ if (sysctls[i].exists) {
+ if (sysctls[i].size == sizeof(long)) {
+ value = *(long *) sysctls[i].value;
+
+ } else {
+ value = *(int *) sysctls[i].value;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "%s: %l",
+ sysctls[i].name, value);
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c b/app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c
new file mode 100644
index 0000000..2a76c15
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c
@@ -0,0 +1,206 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same
+ * old bug as early FreeBSD sendfile() syscall:
+ * http://bugs.freebsd.org/33771
+ *
+ * Besides sendfile() has another bug: if one calls sendfile()
+ * with both a header and a trailer, then sendfile() ignores a file part
+ * at all and sends only the header and the trailer together.
+ * For this reason we send a trailer only if there is no a header.
+ *
+ * Although sendfile() allows to pass a header or a trailer,
+ * it may send the header or the trailer and a part of the file
+ * in different packets. And FreeBSD workaround (TCP_NOPUSH option)
+ * does not help.
+ */
+
+
+ngx_chain_t *
+ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ int rc;
+ off_t send, prev_send, sent;
+ off_t file_size;
+ ssize_t n;
+ ngx_uint_t eintr;
+ ngx_err_t err;
+ ngx_buf_t *file;
+ ngx_event_t *wev;
+ ngx_chain_t *cl;
+ ngx_iovec_t header, trailer;
+ struct sf_hdtr hdtr;
+ struct iovec headers[NGX_IOVS_PREALLOCATE];
+ struct iovec trailers[NGX_IOVS_PREALLOCATE];
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+#if (NGX_HAVE_KQUEUE)
+
+ if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
+ (void) ngx_connection_error(c, wev->kq_errno,
+ "kevent() reported about an closed connection");
+ wev->error = 1;
+ return NGX_CHAIN_ERROR;
+ }
+
+#endif
+
+ /* the maximum limit size is the maximum size_t value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
+ limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
+ }
+
+ send = 0;
+
+ header.iovs = headers;
+ header.nalloc = NGX_IOVS_PREALLOCATE;
+
+ trailer.iovs = trailers;
+ trailer.nalloc = NGX_IOVS_PREALLOCATE;
+
+ for ( ;; ) {
+ eintr = 0;
+ prev_send = send;
+
+ /* create the header iovec and coalesce the neighbouring bufs */
+
+ cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
+
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ send += header.size;
+
+ if (cl && cl->buf->in_file && send < limit) {
+ file = cl->buf;
+
+ /* coalesce the neighbouring file bufs */
+
+ file_size = ngx_chain_coalesce_file(&cl, limit - send);
+
+ send += file_size;
+
+ if (header.count == 0 && send < limit) {
+
+ /*
+ * create the trailer iovec and coalesce the neighbouring bufs
+ */
+
+ cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send,
+ c->log);
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ send += trailer.size;
+
+ } else {
+ trailer.count = 0;
+ }
+
+ /*
+ * sendfile() returns EINVAL if sf_hdtr's count is 0,
+ * but corresponding pointer is not NULL
+ */
+
+ hdtr.headers = header.count ? header.iovs : NULL;
+ hdtr.hdr_cnt = header.count;
+ hdtr.trailers = trailer.count ? trailer.iovs : NULL;
+ hdtr.trl_cnt = trailer.count;
+
+ sent = header.size + file_size;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendfile: @%O %O h:%uz",
+ file->file_pos, sent, header.size);
+
+ rc = sendfile(file->file->fd, c->fd, file->file_pos,
+ &sent, &hdtr, 0);
+
+ if (rc == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ break;
+
+ case NGX_EINTR:
+ eintr = 1;
+ break;
+
+ default:
+ wev->error = 1;
+ (void) ngx_connection_error(c, err, "sendfile() failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfile() sent only %O bytes", sent);
+ }
+
+ if (rc == 0 && sent == 0) {
+
+ /*
+ * if rc and sent equal to zero, then someone
+ * has truncated the file, so the offset became beyond
+ * the end of the file
+ */
+
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfile() reported that \"%s\" was truncated",
+ file->file->name.data);
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendfile: %d, @%O %O:%O",
+ rc, file->file_pos, sent, file_size + header.size);
+
+ } else {
+ n = ngx_writev(c, &header);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ sent = (n == NGX_AGAIN) ? 0 : n;
+ }
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+ if (eintr) {
+ send = prev_send + sent;
+ continue;
+ }
+
+ if (send - prev_send != sent) {
+ wev->ready = 0;
+ return in;
+ }
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_dlopen.c b/app/nginx/src/os/unix/ngx_dlopen.c
new file mode 100644
index 0000000..a0efc69
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_dlopen.c
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_DLOPEN)
+
+char *
+ngx_dlerror(void)
+{
+ char *err;
+
+ err = (char *) dlerror();
+
+ if (err == NULL) {
+ return "";
+ }
+
+ return err;
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_dlopen.h b/app/nginx/src/os/unix/ngx_dlopen.h
new file mode 100644
index 0000000..7a3159f
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_dlopen.h
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_DLOPEN_H_INCLUDED_
+#define _NGX_DLOPEN_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define ngx_dlopen(path) dlopen((char *) path, RTLD_NOW | RTLD_GLOBAL)
+#define ngx_dlopen_n "dlopen()"
+
+#define ngx_dlsym(handle, symbol) dlsym(handle, symbol)
+#define ngx_dlsym_n "dlsym()"
+
+#define ngx_dlclose(handle) dlclose(handle)
+#define ngx_dlclose_n "dlclose()"
+
+
+#if (NGX_HAVE_DLOPEN)
+char *ngx_dlerror(void);
+#endif
+
+
+#endif /* _NGX_DLOPEN_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_errno.c b/app/nginx/src/os/unix/ngx_errno.c
new file mode 100644
index 0000000..e787b23
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_errno.c
@@ -0,0 +1,87 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * The strerror() messages are copied because:
+ *
+ * 1) strerror() and strerror_r() functions are not Async-Signal-Safe,
+ * therefore, they cannot be used in signal handlers;
+ *
+ * 2) a direct sys_errlist[] array may be used instead of these functions,
+ * but Linux linker warns about its usage:
+ *
+ * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
+ * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
+ *
+ * causing false bug reports.
+ */
+
+
+static ngx_str_t *ngx_sys_errlist;
+static ngx_str_t ngx_unknown_error = ngx_string("Unknown error");
+
+
+u_char *
+ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
+{
+ ngx_str_t *msg;
+
+ msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]:
+ &ngx_unknown_error;
+ size = ngx_min(size, msg->len);
+
+ return ngx_cpymem(errstr, msg->data, size);
+}
+
+
+ngx_int_t
+ngx_strerror_init(void)
+{
+ char *msg;
+ u_char *p;
+ size_t len;
+ ngx_err_t err;
+
+ /*
+ * ngx_strerror() is not ready to work at this stage, therefore,
+ * malloc() is used and possible errors are logged using strerror().
+ */
+
+ len = NGX_SYS_NERR * sizeof(ngx_str_t);
+
+ ngx_sys_errlist = malloc(len);
+ if (ngx_sys_errlist == NULL) {
+ goto failed;
+ }
+
+ for (err = 0; err < NGX_SYS_NERR; err++) {
+ msg = strerror(err);
+ len = ngx_strlen(msg);
+
+ p = malloc(len);
+ if (p == NULL) {
+ goto failed;
+ }
+
+ ngx_memcpy(p, msg, len);
+ ngx_sys_errlist[err].len = len;
+ ngx_sys_errlist[err].data = p;
+ }
+
+ return NGX_OK;
+
+failed:
+
+ err = errno;
+ ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
+
+ return NGX_ERROR;
+}
diff --git a/app/nginx/src/os/unix/ngx_errno.h b/app/nginx/src/os/unix/ngx_errno.h
new file mode 100644
index 0000000..7d6ca76
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_errno.h
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ERRNO_H_INCLUDED_
+#define _NGX_ERRNO_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef int ngx_err_t;
+
+#define NGX_EPERM EPERM
+#define NGX_ENOENT ENOENT
+#define NGX_ENOPATH ENOENT
+#define NGX_ESRCH ESRCH
+#define NGX_EINTR EINTR
+#define NGX_ECHILD ECHILD
+#define NGX_ENOMEM ENOMEM
+#define NGX_EACCES EACCES
+#define NGX_EBUSY EBUSY
+#define NGX_EEXIST EEXIST
+#define NGX_EEXIST_FILE EEXIST
+#define NGX_EXDEV EXDEV
+#define NGX_ENOTDIR ENOTDIR
+#define NGX_EISDIR EISDIR
+#define NGX_EINVAL EINVAL
+#define NGX_ENFILE ENFILE
+#define NGX_EMFILE EMFILE
+#define NGX_ENOSPC ENOSPC
+#define NGX_EPIPE EPIPE
+#define NGX_EINPROGRESS EINPROGRESS
+#define NGX_ENOPROTOOPT ENOPROTOOPT
+#define NGX_EOPNOTSUPP EOPNOTSUPP
+#define NGX_EADDRINUSE EADDRINUSE
+#define NGX_ECONNABORTED ECONNABORTED
+#define NGX_ECONNRESET ECONNRESET
+#define NGX_ENOTCONN ENOTCONN
+#define NGX_ETIMEDOUT ETIMEDOUT
+#define NGX_ECONNREFUSED ECONNREFUSED
+#define NGX_ENAMETOOLONG ENAMETOOLONG
+#define NGX_ENETDOWN ENETDOWN
+#define NGX_ENETUNREACH ENETUNREACH
+#define NGX_EHOSTDOWN EHOSTDOWN
+#define NGX_EHOSTUNREACH EHOSTUNREACH
+#define NGX_ENOSYS ENOSYS
+#define NGX_ECANCELED ECANCELED
+#define NGX_EILSEQ EILSEQ
+#define NGX_ENOMOREFILES 0
+#define NGX_ELOOP ELOOP
+#define NGX_EBADF EBADF
+
+#if (NGX_HAVE_OPENAT)
+#define NGX_EMLINK EMLINK
+#endif
+
+#if (__hpux__)
+#define NGX_EAGAIN EWOULDBLOCK
+#else
+#define NGX_EAGAIN EAGAIN
+#endif
+
+
+#define ngx_errno errno
+#define ngx_socket_errno errno
+#define ngx_set_errno(err) errno = err
+#define ngx_set_socket_errno(err) errno = err
+
+
+u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size);
+ngx_int_t ngx_strerror_init(void);
+
+
+#endif /* _NGX_ERRNO_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_file_aio_read.c b/app/nginx/src/os/unix/ngx_file_aio_read.c
new file mode 100644
index 0000000..aedc3c9
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_file_aio_read.c
@@ -0,0 +1,216 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * FreeBSD file AIO features and quirks:
+ *
+ * if an asked data are already in VM cache, then aio_error() returns 0,
+ * and the data are already copied in buffer;
+ *
+ * aio_read() preread in VM cache as minimum 16K (probably BKVASIZE);
+ * the first AIO preload may be up to 128K;
+ *
+ * aio_read/aio_error() may return EINPROGRESS for just written data;
+ *
+ * kqueue EVFILT_AIO filter is level triggered only: an event repeats
+ * until aio_return() will be called;
+ *
+ * aio_cancel() cannot cancel file AIO: it returns AIO_NOTCANCELED always.
+ */
+
+
+extern int ngx_kqueue;
+
+
+static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
+ ngx_event_t *ev);
+static void ngx_file_aio_event_handler(ngx_event_t *ev);
+
+
+ngx_int_t
+ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool)
+{
+ ngx_event_aio_t *aio;
+
+ aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+ if (aio == NULL) {
+ return NGX_ERROR;
+ }
+
+ aio->file = file;
+ aio->fd = file->fd;
+ aio->event.data = aio;
+ aio->event.ready = 1;
+ aio->event.log = file->log;
+
+ file->aio = aio;
+
+ return NGX_OK;
+}
+
+
+ssize_t
+ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+ ngx_pool_t *pool)
+{
+ int n;
+ ngx_event_t *ev;
+ ngx_event_aio_t *aio;
+
+ if (!ngx_file_aio) {
+ return ngx_read_file(file, buf, size, offset);
+ }
+
+ if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ aio = file->aio;
+ ev = &aio->event;
+
+ if (!ev->ready) {
+ ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+ "second aio post for \"%V\"", &file->name);
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "aio complete:%d @%O:%uz %V",
+ ev->complete, offset, size, &file->name);
+
+ if (ev->complete) {
+ ev->complete = 0;
+ ngx_set_errno(aio->err);
+
+ if (aio->err == 0) {
+ return aio->nbytes;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "aio read \"%s\" failed", file->name.data);
+
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&aio->aiocb, sizeof(struct aiocb));
+
+ aio->aiocb.aio_fildes = file->fd;
+ aio->aiocb.aio_offset = offset;
+ aio->aiocb.aio_buf = buf;
+ aio->aiocb.aio_nbytes = size;
+#if (NGX_HAVE_KQUEUE)
+ aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
+ aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
+ aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
+#endif
+ ev->handler = ngx_file_aio_event_handler;
+
+ n = aio_read(&aio->aiocb);
+
+ if (n == -1) {
+ n = ngx_errno;
+
+ if (n == NGX_EAGAIN) {
+ return ngx_read_file(file, buf, size, offset);
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, n,
+ "aio_read(\"%V\") failed", &file->name);
+
+ if (n == NGX_ENOSYS) {
+ ngx_file_aio = 0;
+ return ngx_read_file(file, buf, size, offset);
+ }
+
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "aio_read: fd:%d %d", file->fd, n);
+
+ ev->active = 1;
+ ev->ready = 0;
+ ev->complete = 0;
+
+ return ngx_file_aio_result(aio->file, aio, ev);
+}
+
+
+static ssize_t
+ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev)
+{
+ int n;
+ ngx_err_t err;
+
+ n = aio_error(&aio->aiocb);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "aio_error: fd:%d %d", file->fd, n);
+
+ if (n == -1) {
+ err = ngx_errno;
+ aio->err = err;
+
+ ngx_log_error(NGX_LOG_ALERT, file->log, err,
+ "aio_error(\"%V\") failed", &file->name);
+ return NGX_ERROR;
+ }
+
+ if (n == NGX_EINPROGRESS) {
+ if (ev->ready) {
+ ev->ready = 0;
+ ngx_log_error(NGX_LOG_ALERT, file->log, n,
+ "aio_read(\"%V\") still in progress",
+ &file->name);
+ }
+
+ return NGX_AGAIN;
+ }
+
+ n = aio_return(&aio->aiocb);
+
+ if (n == -1) {
+ err = ngx_errno;
+ aio->err = err;
+ ev->ready = 1;
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ "aio_return(\"%V\") failed", &file->name);
+ return NGX_ERROR;
+ }
+
+ aio->err = 0;
+ aio->nbytes = n;
+ ev->ready = 1;
+ ev->active = 0;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "aio_return: fd:%d %d", file->fd, n);
+
+ return n;
+}
+
+
+static void
+ngx_file_aio_event_handler(ngx_event_t *ev)
+{
+ ngx_event_aio_t *aio;
+
+ aio = ev->data;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "aio event handler fd:%d %V", aio->fd, &aio->file->name);
+
+ if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) {
+ aio->handler(ev);
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_files.c b/app/nginx/src/os/unix/ngx_files.c
new file mode 100644
index 0000000..7fbb7c9
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_files.c
@@ -0,0 +1,906 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_THREADS)
+#include <ngx_thread_pool.h>
+static void ngx_thread_read_handler(void *data, ngx_log_t *log);
+static void ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log);
+#endif
+
+static ngx_chain_t *ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl);
+static ssize_t ngx_writev_file(ngx_file_t *file, ngx_iovec_t *vec,
+ off_t offset);
+
+
+#if (NGX_HAVE_FILE_AIO)
+
+ngx_uint_t ngx_file_aio = 1;
+
+#endif
+
+
+ssize_t
+ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
+{
+ ssize_t n;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "read: %d, %p, %uz, %O", file->fd, buf, size, offset);
+
+#if (NGX_HAVE_PREAD)
+
+ n = pread(file->fd, buf, size, offset);
+
+ if (n == -1) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "pread() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+#else
+
+ if (file->sys_offset != offset) {
+ if (lseek(file->fd, offset, SEEK_SET) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "lseek() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->sys_offset = offset;
+ }
+
+ n = read(file->fd, buf, size);
+
+ if (n == -1) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "read() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->sys_offset += n;
+
+#endif
+
+ file->offset += n;
+
+ return n;
+}
+
+
+#if (NGX_THREADS)
+
+typedef struct {
+ ngx_fd_t fd;
+ ngx_uint_t write; /* unsigned write:1; */
+
+ u_char *buf;
+ size_t size;
+ ngx_chain_t *chain;
+ off_t offset;
+
+ size_t nbytes;
+ ngx_err_t err;
+} ngx_thread_file_ctx_t;
+
+
+ssize_t
+ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+ ngx_pool_t *pool)
+{
+ ngx_thread_task_t *task;
+ ngx_thread_file_ctx_t *ctx;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "thread read: %d, %p, %uz, %O",
+ file->fd, buf, size, offset);
+
+ task = file->thread_task;
+
+ if (task == NULL) {
+ task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t));
+ if (task == NULL) {
+ return NGX_ERROR;
+ }
+
+ file->thread_task = task;
+ }
+
+ ctx = task->ctx;
+
+ if (task->event.complete) {
+ task->event.complete = 0;
+
+ if (ctx->write) {
+ ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+ "invalid thread call, read instead of write");
+ return NGX_ERROR;
+ }
+
+ if (ctx->err) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err,
+ "pread() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ return ctx->nbytes;
+ }
+
+ task->handler = ngx_thread_read_handler;
+
+ ctx->write = 0;
+
+ ctx->fd = file->fd;
+ ctx->buf = buf;
+ ctx->size = size;
+ ctx->offset = offset;
+
+ if (file->thread_handler(task, file) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ return NGX_AGAIN;
+}
+
+
+#if (NGX_HAVE_PREAD)
+
+static void
+ngx_thread_read_handler(void *data, ngx_log_t *log)
+{
+ ngx_thread_file_ctx_t *ctx = data;
+
+ ssize_t n;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread read handler");
+
+ n = pread(ctx->fd, ctx->buf, ctx->size, ctx->offset);
+
+ if (n == -1) {
+ ctx->err = ngx_errno;
+
+ } else {
+ ctx->nbytes = n;
+ ctx->err = 0;
+ }
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0,
+ "pread: %z (err: %d) of %uz @%O",
+ n, ctx->err, ctx->size, ctx->offset);
+}
+
+#else
+
+#error pread() is required!
+
+#endif
+
+#endif /* NGX_THREADS */
+
+
+ssize_t
+ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
+{
+ ssize_t n, written;
+ ngx_err_t err;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "write: %d, %p, %uz, %O", file->fd, buf, size, offset);
+
+ written = 0;
+
+#if (NGX_HAVE_PWRITE)
+
+ for ( ;; ) {
+ n = pwrite(file->fd, buf + written, size, offset);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ if (err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err,
+ "pwrite() was interrupted");
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ "pwrite() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->offset += n;
+ written += n;
+
+ if ((size_t) n == size) {
+ return written;
+ }
+
+ offset += n;
+ size -= n;
+ }
+
+#else
+
+ if (file->sys_offset != offset) {
+ if (lseek(file->fd, offset, SEEK_SET) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "lseek() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->sys_offset = offset;
+ }
+
+ for ( ;; ) {
+ n = write(file->fd, buf + written, size);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ if (err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err,
+ "write() was interrupted");
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ "write() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->sys_offset += n;
+ file->offset += n;
+ written += n;
+
+ if ((size_t) n == size) {
+ return written;
+ }
+
+ size -= n;
+ }
+#endif
+}
+
+
+ngx_fd_t
+ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
+{
+ ngx_fd_t fd;
+
+ fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR,
+ access ? access : 0600);
+
+ if (fd != -1 && !persistent) {
+ (void) unlink((const char *) name);
+ }
+
+ return fd;
+}
+
+
+ssize_t
+ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
+ ngx_pool_t *pool)
+{
+ ssize_t total, n;
+ ngx_iovec_t vec;
+ struct iovec iovs[NGX_IOVS_PREALLOCATE];
+
+ /* use pwrite() if there is the only buf in a chain */
+
+ if (cl->next == NULL) {
+ return ngx_write_file(file, cl->buf->pos,
+ (size_t) (cl->buf->last - cl->buf->pos),
+ offset);
+ }
+
+ total = 0;
+
+ vec.iovs = iovs;
+ vec.nalloc = NGX_IOVS_PREALLOCATE;
+
+ do {
+ /* create the iovec and coalesce the neighbouring bufs */
+ cl = ngx_chain_to_iovec(&vec, cl);
+
+ /* use pwrite() if there is the only iovec buffer */
+
+ if (vec.count == 1) {
+ n = ngx_write_file(file, (u_char *) iovs[0].iov_base,
+ iovs[0].iov_len, offset);
+
+ if (n == NGX_ERROR) {
+ return n;
+ }
+
+ return total + n;
+ }
+
+ n = ngx_writev_file(file, &vec, offset);
+
+ if (n == NGX_ERROR) {
+ return n;
+ }
+
+ offset += n;
+ total += n;
+
+ } while (cl);
+
+ return total;
+}
+
+
+static ngx_chain_t *
+ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl)
+{
+ size_t total, size;
+ u_char *prev;
+ ngx_uint_t n;
+ struct iovec *iov;
+
+ iov = NULL;
+ prev = NULL;
+ total = 0;
+ n = 0;
+
+ for ( /* void */ ; cl; cl = cl->next) {
+
+ if (ngx_buf_special(cl->buf)) {
+ continue;
+ }
+
+ size = cl->buf->last - cl->buf->pos;
+
+ if (prev == cl->buf->pos) {
+ iov->iov_len += size;
+
+ } else {
+ if (n == vec->nalloc) {
+ break;
+ }
+
+ iov = &vec->iovs[n++];
+
+ iov->iov_base = (void *) cl->buf->pos;
+ iov->iov_len = size;
+ }
+
+ prev = cl->buf->pos + size;
+ total += size;
+ }
+
+ vec->count = n;
+ vec->size = total;
+
+ return cl;
+}
+
+
+static ssize_t
+ngx_writev_file(ngx_file_t *file, ngx_iovec_t *vec, off_t offset)
+{
+ ssize_t n;
+ ngx_err_t err;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "writev: %d, %uz, %O", file->fd, vec->size, offset);
+
+#if (NGX_HAVE_PWRITEV)
+
+eintr:
+
+ n = pwritev(file->fd, vec->iovs, vec->count, offset);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ if (err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err,
+ "pwritev() was interrupted");
+ goto eintr;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ "pwritev() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != vec->size) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, 0,
+ "pwritev() \"%s\" has written only %z of %uz",
+ file->name.data, n, vec->size);
+ return NGX_ERROR;
+ }
+
+#else
+
+ if (file->sys_offset != offset) {
+ if (lseek(file->fd, offset, SEEK_SET) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "lseek() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->sys_offset = offset;
+ }
+
+eintr:
+
+ n = writev(file->fd, vec->iovs, vec->count);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ if (err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err,
+ "writev() was interrupted");
+ goto eintr;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ "writev() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != vec->size) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, 0,
+ "writev() \"%s\" has written only %z of %uz",
+ file->name.data, n, vec->size);
+ return NGX_ERROR;
+ }
+
+ file->sys_offset += n;
+
+#endif
+
+ file->offset += n;
+
+ return n;
+}
+
+
+#if (NGX_THREADS)
+
+ssize_t
+ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
+ ngx_pool_t *pool)
+{
+ ngx_thread_task_t *task;
+ ngx_thread_file_ctx_t *ctx;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "thread write chain: %d, %p, %O",
+ file->fd, cl, offset);
+
+ task = file->thread_task;
+
+ if (task == NULL) {
+ task = ngx_thread_task_alloc(pool,
+ sizeof(ngx_thread_file_ctx_t));
+ if (task == NULL) {
+ return NGX_ERROR;
+ }
+
+ file->thread_task = task;
+ }
+
+ ctx = task->ctx;
+
+ if (task->event.complete) {
+ task->event.complete = 0;
+
+ if (!ctx->write) {
+ ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+ "invalid thread call, write instead of read");
+ return NGX_ERROR;
+ }
+
+ if (ctx->err || ctx->nbytes == 0) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err,
+ "pwritev() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->offset += ctx->nbytes;
+ return ctx->nbytes;
+ }
+
+ task->handler = ngx_thread_write_chain_to_file_handler;
+
+ ctx->write = 1;
+
+ ctx->fd = file->fd;
+ ctx->chain = cl;
+ ctx->offset = offset;
+
+ if (file->thread_handler(task, file) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ return NGX_AGAIN;
+}
+
+
+static void
+ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log)
+{
+ ngx_thread_file_ctx_t *ctx = data;
+
+#if (NGX_HAVE_PWRITEV)
+
+ off_t offset;
+ ssize_t n;
+ ngx_err_t err;
+ ngx_chain_t *cl;
+ ngx_iovec_t vec;
+ struct iovec iovs[NGX_IOVS_PREALLOCATE];
+
+ vec.iovs = iovs;
+ vec.nalloc = NGX_IOVS_PREALLOCATE;
+
+ cl = ctx->chain;
+ offset = ctx->offset;
+
+ ctx->nbytes = 0;
+ ctx->err = 0;
+
+ do {
+ /* create the iovec and coalesce the neighbouring bufs */
+ cl = ngx_chain_to_iovec(&vec, cl);
+
+eintr:
+
+ n = pwritev(ctx->fd, iovs, vec.count, offset);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ if (err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, err,
+ "pwritev() was interrupted");
+ goto eintr;
+ }
+
+ ctx->err = err;
+ return;
+ }
+
+ if ((size_t) n != vec.size) {
+ ctx->nbytes = 0;
+ return;
+ }
+
+ ctx->nbytes += n;
+ offset += n;
+ } while (cl);
+
+#else
+
+ ctx->err = NGX_ENOSYS;
+ return;
+
+#endif
+}
+
+#endif /* NGX_THREADS */
+
+
+ngx_int_t
+ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s)
+{
+ struct timeval tv[2];
+
+ tv[0].tv_sec = ngx_time();
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = s;
+ tv[1].tv_usec = 0;
+
+ if (utimes((char *) name, tv) != -1) {
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_create_file_mapping(ngx_file_mapping_t *fm)
+{
+ fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
+ NGX_FILE_DEFAULT_ACCESS);
+ if (fm->fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", fm->name);
+ return NGX_ERROR;
+ }
+
+ if (ftruncate(fm->fd, fm->size) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "ftruncate() \"%s\" failed", fm->name);
+ goto failed;
+ }
+
+ fm->addr = mmap(NULL, fm->size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ fm->fd, 0);
+ if (fm->addr != MAP_FAILED) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "mmap(%uz) \"%s\" failed", fm->size, fm->name);
+
+failed:
+
+ if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", fm->name);
+ }
+
+ return NGX_ERROR;
+}
+
+
+void
+ngx_close_file_mapping(ngx_file_mapping_t *fm)
+{
+ if (munmap(fm->addr, fm->size) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "munmap(%uz) \"%s\" failed", fm->size, fm->name);
+ }
+
+ if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", fm->name);
+ }
+}
+
+
+ngx_int_t
+ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir)
+{
+ dir->dir = opendir((const char *) name->data);
+
+ if (dir->dir == NULL) {
+ return NGX_ERROR;
+ }
+
+ dir->valid_info = 0;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_read_dir(ngx_dir_t *dir)
+{
+ dir->de = readdir(dir->dir);
+
+ if (dir->de) {
+#if (NGX_HAVE_D_TYPE)
+ dir->type = dir->de->d_type;
+#else
+ dir->type = 0;
+#endif
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_open_glob(ngx_glob_t *gl)
+{
+ int n;
+
+ n = glob((char *) gl->pattern, 0, NULL, &gl->pglob);
+
+ if (n == 0) {
+ return NGX_OK;
+ }
+
+#ifdef GLOB_NOMATCH
+
+ if (n == GLOB_NOMATCH && gl->test) {
+ return NGX_OK;
+ }
+
+#endif
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name)
+{
+ size_t count;
+
+#ifdef GLOB_NOMATCH
+ count = (size_t) gl->pglob.gl_pathc;
+#else
+ count = (size_t) gl->pglob.gl_matchc;
+#endif
+
+ if (gl->n < count) {
+
+ name->len = (size_t) ngx_strlen(gl->pglob.gl_pathv[gl->n]);
+ name->data = (u_char *) gl->pglob.gl_pathv[gl->n];
+ gl->n++;
+
+ return NGX_OK;
+ }
+
+ return NGX_DONE;
+}
+
+
+void
+ngx_close_glob(ngx_glob_t *gl)
+{
+ globfree(&gl->pglob);
+}
+
+
+ngx_err_t
+ngx_trylock_fd(ngx_fd_t fd)
+{
+ struct flock fl;
+
+ ngx_memzero(&fl, sizeof(struct flock));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+
+ if (fcntl(fd, F_SETLK, &fl) == -1) {
+ return ngx_errno;
+ }
+
+ return 0;
+}
+
+
+ngx_err_t
+ngx_lock_fd(ngx_fd_t fd)
+{
+ struct flock fl;
+
+ ngx_memzero(&fl, sizeof(struct flock));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+
+ if (fcntl(fd, F_SETLKW, &fl) == -1) {
+ return ngx_errno;
+ }
+
+ return 0;
+}
+
+
+ngx_err_t
+ngx_unlock_fd(ngx_fd_t fd)
+{
+ struct flock fl;
+
+ ngx_memzero(&fl, sizeof(struct flock));
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+
+ if (fcntl(fd, F_SETLK, &fl) == -1) {
+ return ngx_errno;
+ }
+
+ return 0;
+}
+
+
+#if (NGX_HAVE_POSIX_FADVISE) && !(NGX_HAVE_F_READAHEAD)
+
+ngx_int_t
+ngx_read_ahead(ngx_fd_t fd, size_t n)
+{
+ int err;
+
+ err = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+
+ if (err == 0) {
+ return 0;
+ }
+
+ ngx_set_errno(err);
+ return NGX_FILE_ERROR;
+}
+
+#endif
+
+
+#if (NGX_HAVE_O_DIRECT)
+
+ngx_int_t
+ngx_directio_on(ngx_fd_t fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+
+ if (flags == -1) {
+ return NGX_FILE_ERROR;
+ }
+
+ return fcntl(fd, F_SETFL, flags | O_DIRECT);
+}
+
+
+ngx_int_t
+ngx_directio_off(ngx_fd_t fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+
+ if (flags == -1) {
+ return NGX_FILE_ERROR;
+ }
+
+ return fcntl(fd, F_SETFL, flags & ~O_DIRECT);
+}
+
+#endif
+
+
+#if (NGX_HAVE_STATFS)
+
+size_t
+ngx_fs_bsize(u_char *name)
+{
+ struct statfs fs;
+
+ if (statfs((char *) name, &fs) == -1) {
+ return 512;
+ }
+
+ if ((fs.f_bsize % 512) != 0) {
+ return 512;
+ }
+
+ return (size_t) fs.f_bsize;
+}
+
+#elif (NGX_HAVE_STATVFS)
+
+size_t
+ngx_fs_bsize(u_char *name)
+{
+ struct statvfs fs;
+
+ if (statvfs((char *) name, &fs) == -1) {
+ return 512;
+ }
+
+ if ((fs.f_frsize % 512) != 0) {
+ return 512;
+ }
+
+ return (size_t) fs.f_frsize;
+}
+
+#else
+
+size_t
+ngx_fs_bsize(u_char *name)
+{
+ return 512;
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_files.h b/app/nginx/src/os/unix/ngx_files.h
new file mode 100644
index 0000000..07872b1
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_files.h
@@ -0,0 +1,395 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_FILES_H_INCLUDED_
+#define _NGX_FILES_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef int ngx_fd_t;
+typedef struct stat ngx_file_info_t;
+typedef ino_t ngx_file_uniq_t;
+
+
+typedef struct {
+ u_char *name;
+ size_t size;
+ void *addr;
+ ngx_fd_t fd;
+ ngx_log_t *log;
+} ngx_file_mapping_t;
+
+
+typedef struct {
+ DIR *dir;
+ struct dirent *de;
+ struct stat info;
+
+ unsigned type:8;
+ unsigned valid_info:1;
+} ngx_dir_t;
+
+
+typedef struct {
+ size_t n;
+ glob_t pglob;
+ u_char *pattern;
+ ngx_log_t *log;
+ ngx_uint_t test;
+} ngx_glob_t;
+
+
+#define NGX_INVALID_FILE -1
+#define NGX_FILE_ERROR -1
+
+
+
+#ifdef __CYGWIN__
+
+#ifndef NGX_HAVE_CASELESS_FILESYSTEM
+#define NGX_HAVE_CASELESS_FILESYSTEM 1
+#endif
+
+#define ngx_open_file(name, mode, create, access) \
+ open((const char *) name, mode|create|O_BINARY, access)
+
+#else
+
+#define ngx_open_file(name, mode, create, access) \
+ open((const char *) name, mode|create, access)
+
+#endif
+
+#define ngx_open_file_n "open()"
+
+#define NGX_FILE_RDONLY O_RDONLY
+#define NGX_FILE_WRONLY O_WRONLY
+#define NGX_FILE_RDWR O_RDWR
+#define NGX_FILE_CREATE_OR_OPEN O_CREAT
+#define NGX_FILE_OPEN 0
+#define NGX_FILE_TRUNCATE (O_CREAT|O_TRUNC)
+#define NGX_FILE_APPEND (O_WRONLY|O_APPEND)
+#define NGX_FILE_NONBLOCK O_NONBLOCK
+
+#if (NGX_HAVE_OPENAT)
+#define NGX_FILE_NOFOLLOW O_NOFOLLOW
+
+#if defined(O_DIRECTORY)
+#define NGX_FILE_DIRECTORY O_DIRECTORY
+#else
+#define NGX_FILE_DIRECTORY 0
+#endif
+
+#if defined(O_SEARCH)
+#define NGX_FILE_SEARCH (O_SEARCH|NGX_FILE_DIRECTORY)
+
+#elif defined(O_EXEC)
+#define NGX_FILE_SEARCH (O_EXEC|NGX_FILE_DIRECTORY)
+
+#elif (NGX_HAVE_O_PATH)
+#define NGX_FILE_SEARCH (O_PATH|O_RDONLY|NGX_FILE_DIRECTORY)
+
+#else
+#define NGX_FILE_SEARCH (O_RDONLY|NGX_FILE_DIRECTORY)
+#endif
+
+#endif /* NGX_HAVE_OPENAT */
+
+#define NGX_FILE_DEFAULT_ACCESS 0644
+#define NGX_FILE_OWNER_ACCESS 0600
+
+
+#define ngx_close_file close
+#define ngx_close_file_n "close()"
+
+
+#define ngx_delete_file(name) unlink((const char *) name)
+#define ngx_delete_file_n "unlink()"
+
+
+ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent,
+ ngx_uint_t access);
+#define ngx_open_tempfile_n "open()"
+
+
+ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset);
+#if (NGX_HAVE_PREAD)
+#define ngx_read_file_n "pread()"
+#else
+#define ngx_read_file_n "read()"
+#endif
+
+ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size,
+ off_t offset);
+
+ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce,
+ off_t offset, ngx_pool_t *pool);
+
+
+#define ngx_read_fd read
+#define ngx_read_fd_n "read()"
+
+/*
+ * we use inlined function instead of simple #define
+ * because glibc 2.3 sets warn_unused_result attribute for write()
+ * and in this case gcc 4.3 ignores (void) cast
+ */
+static ngx_inline ssize_t
+ngx_write_fd(ngx_fd_t fd, void *buf, size_t n)
+{
+ return write(fd, buf, n);
+}
+
+#define ngx_write_fd_n "write()"
+
+
+#define ngx_write_console ngx_write_fd
+
+
+#define ngx_linefeed(p) *p++ = LF;
+#define NGX_LINEFEED_SIZE 1
+#define NGX_LINEFEED "\x0a"
+
+
+#define ngx_rename_file(o, n) rename((const char *) o, (const char *) n)
+#define ngx_rename_file_n "rename()"
+
+
+#define ngx_change_file_access(n, a) chmod((const char *) n, a)
+#define ngx_change_file_access_n "chmod()"
+
+
+ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s);
+#define ngx_set_file_time_n "utimes()"
+
+
+#define ngx_file_info(file, sb) stat((const char *) file, sb)
+#define ngx_file_info_n "stat()"
+
+#define ngx_fd_info(fd, sb) fstat(fd, sb)
+#define ngx_fd_info_n "fstat()"
+
+#define ngx_link_info(file, sb) lstat((const char *) file, sb)
+#define ngx_link_info_n "lstat()"
+
+#define ngx_is_dir(sb) (S_ISDIR((sb)->st_mode))
+#define ngx_is_file(sb) (S_ISREG((sb)->st_mode))
+#define ngx_is_link(sb) (S_ISLNK((sb)->st_mode))
+#define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR)
+#define ngx_file_access(sb) ((sb)->st_mode & 0777)
+#define ngx_file_size(sb) (sb)->st_size
+#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512)
+#define ngx_file_mtime(sb) (sb)->st_mtime
+#define ngx_file_uniq(sb) (sb)->st_ino
+
+
+ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm);
+void ngx_close_file_mapping(ngx_file_mapping_t *fm);
+
+
+#define ngx_realpath(p, r) (u_char *) realpath((char *) p, (char *) r)
+#define ngx_realpath_n "realpath()"
+#define ngx_getcwd(buf, size) (getcwd((char *) buf, size) != NULL)
+#define ngx_getcwd_n "getcwd()"
+#define ngx_path_separator(c) ((c) == '/')
+
+
+#if defined(PATH_MAX)
+
+#define NGX_HAVE_MAX_PATH 1
+#define NGX_MAX_PATH PATH_MAX
+
+#else
+
+#define NGX_MAX_PATH 4096
+
+#endif
+
+
+#define NGX_DIR_MASK_LEN 0
+
+
+ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir);
+#define ngx_open_dir_n "opendir()"
+
+
+#define ngx_close_dir(d) closedir((d)->dir)
+#define ngx_close_dir_n "closedir()"
+
+
+ngx_int_t ngx_read_dir(ngx_dir_t *dir);
+#define ngx_read_dir_n "readdir()"
+
+
+#define ngx_create_dir(name, access) mkdir((const char *) name, access)
+#define ngx_create_dir_n "mkdir()"
+
+
+#define ngx_delete_dir(name) rmdir((const char *) name)
+#define ngx_delete_dir_n "rmdir()"
+
+
+#define ngx_dir_access(a) (a | (a & 0444) >> 2)
+
+
+#define ngx_de_name(dir) ((u_char *) (dir)->de->d_name)
+#if (NGX_HAVE_D_NAMLEN)
+#define ngx_de_namelen(dir) (dir)->de->d_namlen
+#else
+#define ngx_de_namelen(dir) ngx_strlen((dir)->de->d_name)
+#endif
+
+static ngx_inline ngx_int_t
+ngx_de_info(u_char *name, ngx_dir_t *dir)
+{
+ dir->type = 0;
+ return stat((const char *) name, &dir->info);
+}
+
+#define ngx_de_info_n "stat()"
+#define ngx_de_link_info(name, dir) lstat((const char *) name, &(dir)->info)
+#define ngx_de_link_info_n "lstat()"
+
+#if (NGX_HAVE_D_TYPE)
+
+/*
+ * some file systems (e.g. XFS on Linux and CD9660 on FreeBSD)
+ * do not set dirent.d_type
+ */
+
+#define ngx_de_is_dir(dir) \
+ (((dir)->type) ? ((dir)->type == DT_DIR) : (S_ISDIR((dir)->info.st_mode)))
+#define ngx_de_is_file(dir) \
+ (((dir)->type) ? ((dir)->type == DT_REG) : (S_ISREG((dir)->info.st_mode)))
+#define ngx_de_is_link(dir) \
+ (((dir)->type) ? ((dir)->type == DT_LNK) : (S_ISLNK((dir)->info.st_mode)))
+
+#else
+
+#define ngx_de_is_dir(dir) (S_ISDIR((dir)->info.st_mode))
+#define ngx_de_is_file(dir) (S_ISREG((dir)->info.st_mode))
+#define ngx_de_is_link(dir) (S_ISLNK((dir)->info.st_mode))
+
+#endif
+
+#define ngx_de_access(dir) (((dir)->info.st_mode) & 0777)
+#define ngx_de_size(dir) (dir)->info.st_size
+#define ngx_de_fs_size(dir) \
+ ngx_max((dir)->info.st_size, (dir)->info.st_blocks * 512)
+#define ngx_de_mtime(dir) (dir)->info.st_mtime
+
+
+ngx_int_t ngx_open_glob(ngx_glob_t *gl);
+#define ngx_open_glob_n "glob()"
+ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name);
+void ngx_close_glob(ngx_glob_t *gl);
+
+
+ngx_err_t ngx_trylock_fd(ngx_fd_t fd);
+ngx_err_t ngx_lock_fd(ngx_fd_t fd);
+ngx_err_t ngx_unlock_fd(ngx_fd_t fd);
+
+#define ngx_trylock_fd_n "fcntl(F_SETLK, F_WRLCK)"
+#define ngx_lock_fd_n "fcntl(F_SETLKW, F_WRLCK)"
+#define ngx_unlock_fd_n "fcntl(F_SETLK, F_UNLCK)"
+
+
+#if (NGX_HAVE_F_READAHEAD)
+
+#define NGX_HAVE_READ_AHEAD 1
+
+#define ngx_read_ahead(fd, n) fcntl(fd, F_READAHEAD, (int) n)
+#define ngx_read_ahead_n "fcntl(fd, F_READAHEAD)"
+
+#elif (NGX_HAVE_POSIX_FADVISE)
+
+#define NGX_HAVE_READ_AHEAD 1
+
+ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n);
+#define ngx_read_ahead_n "posix_fadvise(POSIX_FADV_SEQUENTIAL)"
+
+#else
+
+#define ngx_read_ahead(fd, n) 0
+#define ngx_read_ahead_n "ngx_read_ahead_n"
+
+#endif
+
+
+#if (NGX_HAVE_O_DIRECT)
+
+ngx_int_t ngx_directio_on(ngx_fd_t fd);
+#define ngx_directio_on_n "fcntl(O_DIRECT)"
+
+ngx_int_t ngx_directio_off(ngx_fd_t fd);
+#define ngx_directio_off_n "fcntl(!O_DIRECT)"
+
+#elif (NGX_HAVE_F_NOCACHE)
+
+#define ngx_directio_on(fd) fcntl(fd, F_NOCACHE, 1)
+#define ngx_directio_on_n "fcntl(F_NOCACHE, 1)"
+
+#elif (NGX_HAVE_DIRECTIO)
+
+#define ngx_directio_on(fd) directio(fd, DIRECTIO_ON)
+#define ngx_directio_on_n "directio(DIRECTIO_ON)"
+
+#else
+
+#define ngx_directio_on(fd) 0
+#define ngx_directio_on_n "ngx_directio_on_n"
+
+#endif
+
+size_t ngx_fs_bsize(u_char *name);
+
+
+#if (NGX_HAVE_OPENAT)
+
+#define ngx_openat_file(fd, name, mode, create, access) \
+ openat(fd, (const char *) name, mode|create, access)
+
+#define ngx_openat_file_n "openat()"
+
+#define ngx_file_at_info(fd, name, sb, flag) \
+ fstatat(fd, (const char *) name, sb, flag)
+
+#define ngx_file_at_info_n "fstatat()"
+
+#define NGX_AT_FDCWD (ngx_fd_t) AT_FDCWD
+
+#endif
+
+
+#define ngx_stdout STDOUT_FILENO
+#define ngx_stderr STDERR_FILENO
+#define ngx_set_stderr(fd) dup2(fd, STDERR_FILENO)
+#define ngx_set_stderr_n "dup2(STDERR_FILENO)"
+
+
+#if (NGX_HAVE_FILE_AIO)
+
+ngx_int_t ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool);
+ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
+ off_t offset, ngx_pool_t *pool);
+
+extern ngx_uint_t ngx_file_aio;
+
+#endif
+
+#if (NGX_THREADS)
+ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size,
+ off_t offset, ngx_pool_t *pool);
+ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl,
+ off_t offset, ngx_pool_t *pool);
+#endif
+
+
+#endif /* _NGX_FILES_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_freebsd.h b/app/nginx/src/os/unix/ngx_freebsd.h
new file mode 100644
index 0000000..4f93da5
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_freebsd.h
@@ -0,0 +1,25 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_FREEBSD_H_INCLUDED_
+#define _NGX_FREEBSD_H_INCLUDED_
+
+
+void ngx_debug_init(void);
+ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+extern int ngx_freebsd_kern_osreldate;
+extern int ngx_freebsd_hw_ncpu;
+extern u_long ngx_freebsd_net_inet_tcp_sendspace;
+
+extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug;
+extern ngx_uint_t ngx_freebsd_use_tcp_nopush;
+extern ngx_uint_t ngx_debug_malloc;
+
+
+#endif /* _NGX_FREEBSD_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_freebsd_config.h b/app/nginx/src/os/unix/ngx_freebsd_config.h
new file mode 100644
index 0000000..b7da48c
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_freebsd_config.h
@@ -0,0 +1,123 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_FREEBSD_CONFIG_H_INCLUDED_
+#define _NGX_FREEBSD_CONFIG_H_INCLUDED_
+
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h> /* offsetof() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <glob.h>
+#include <time.h>
+#include <sys/param.h> /* ALIGN() */
+#include <sys/mount.h> /* statfs() */
+
+#include <sys/filio.h> /* FIONBIO */
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h> /* TCP_NODELAY, TCP_NOPUSH */
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+
+#include <libutil.h> /* setproctitle() before 4.1 */
+#include <osreldate.h>
+#include <sys/sysctl.h>
+
+#include <dlfcn.h>
+
+
+#if __FreeBSD_version < 400017
+
+/*
+ * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
+ */
+
+#undef CMSG_SPACE
+#define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
+
+#undef CMSG_LEN
+#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l))
+
+#undef CMSG_DATA
+#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
+
+#endif
+
+
+#include <ngx_auto_config.h>
+
+
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
+#if (NGX_HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (NGX_HAVE_KQUEUE)
+#include <sys/event.h>
+#endif
+
+
+#if (NGX_HAVE_FILE_AIO)
+#include <aio.h>
+typedef struct aiocb ngx_aiocb_t;
+#endif
+
+
+#define NGX_LISTEN_BACKLOG -1
+
+
+#ifdef __DragonFly__
+#define NGX_KEEPALIVE_FACTOR 1000
+#endif
+
+
+#ifndef IOV_MAX
+#define IOV_MAX 1024
+#endif
+
+
+#ifndef NGX_HAVE_INHERITED_NONBLOCK
+#define NGX_HAVE_INHERITED_NONBLOCK 1
+#endif
+
+
+#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define NGX_HAVE_DEBUG_MALLOC 1
+
+
+extern char **environ;
+extern char *malloc_options;
+
+
+#endif /* _NGX_FREEBSD_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_freebsd_init.c b/app/nginx/src/os/unix/ngx_freebsd_init.c
new file mode 100644
index 0000000..1823f02
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_freebsd_init.c
@@ -0,0 +1,262 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/* FreeBSD 3.0 at least */
+char ngx_freebsd_kern_ostype[16];
+char ngx_freebsd_kern_osrelease[128];
+int ngx_freebsd_kern_osreldate;
+int ngx_freebsd_hw_ncpu;
+int ngx_freebsd_kern_ipc_somaxconn;
+u_long ngx_freebsd_net_inet_tcp_sendspace;
+
+/* FreeBSD 4.9 */
+int ngx_freebsd_machdep_hlt_logical_cpus;
+
+
+ngx_uint_t ngx_freebsd_sendfile_nbytes_bug;
+ngx_uint_t ngx_freebsd_use_tcp_nopush;
+
+ngx_uint_t ngx_debug_malloc;
+
+
+static ngx_os_io_t ngx_freebsd_io = {
+ ngx_unix_recv,
+ ngx_readv_chain,
+ ngx_udp_unix_recv,
+ ngx_unix_send,
+ ngx_udp_unix_send,
+ ngx_udp_unix_sendmsg_chain,
+#if (NGX_HAVE_SENDFILE)
+ ngx_freebsd_sendfile_chain,
+ NGX_IO_SENDFILE
+#else
+ ngx_writev_chain,
+ 0
+#endif
+};
+
+
+typedef struct {
+ char *name;
+ void *value;
+ size_t size;
+ ngx_uint_t exists;
+} sysctl_t;
+
+
+sysctl_t sysctls[] = {
+ { "hw.ncpu",
+ &ngx_freebsd_hw_ncpu,
+ sizeof(ngx_freebsd_hw_ncpu), 0 },
+
+ { "machdep.hlt_logical_cpus",
+ &ngx_freebsd_machdep_hlt_logical_cpus,
+ sizeof(ngx_freebsd_machdep_hlt_logical_cpus), 0 },
+
+ { "net.inet.tcp.sendspace",
+ &ngx_freebsd_net_inet_tcp_sendspace,
+ sizeof(ngx_freebsd_net_inet_tcp_sendspace), 0 },
+
+ { "kern.ipc.somaxconn",
+ &ngx_freebsd_kern_ipc_somaxconn,
+ sizeof(ngx_freebsd_kern_ipc_somaxconn), 0 },
+
+ { NULL, NULL, 0, 0 }
+};
+
+
+void
+ngx_debug_init(void)
+{
+#if (NGX_DEBUG_MALLOC)
+
+#if __FreeBSD_version >= 500014 && __FreeBSD_version < 1000011
+ _malloc_options = "J";
+#elif __FreeBSD_version < 500014
+ malloc_options = "J";
+#endif
+
+ ngx_debug_malloc = 1;
+
+#else
+ char *mo;
+
+ mo = getenv("MALLOC_OPTIONS");
+
+ if (mo && ngx_strchr(mo, 'J')) {
+ ngx_debug_malloc = 1;
+ }
+#endif
+}
+
+
+ngx_int_t
+ngx_os_specific_init(ngx_log_t *log)
+{
+ int version;
+ size_t size;
+ ngx_err_t err;
+ ngx_uint_t i;
+
+ size = sizeof(ngx_freebsd_kern_ostype);
+ if (sysctlbyname("kern.ostype",
+ ngx_freebsd_kern_ostype, &size, NULL, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sysctlbyname(kern.ostype) failed");
+
+ if (ngx_errno != NGX_ENOMEM) {
+ return NGX_ERROR;
+ }
+
+ ngx_freebsd_kern_ostype[size - 1] = '\0';
+ }
+
+ size = sizeof(ngx_freebsd_kern_osrelease);
+ if (sysctlbyname("kern.osrelease",
+ ngx_freebsd_kern_osrelease, &size, NULL, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sysctlbyname(kern.osrelease) failed");
+
+ if (ngx_errno != NGX_ENOMEM) {
+ return NGX_ERROR;
+ }
+
+ ngx_freebsd_kern_osrelease[size - 1] = '\0';
+ }
+
+
+ size = sizeof(int);
+ if (sysctlbyname("kern.osreldate",
+ &ngx_freebsd_kern_osreldate, &size, NULL, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sysctlbyname(kern.osreldate) failed");
+ return NGX_ERROR;
+ }
+
+ version = ngx_freebsd_kern_osreldate;
+
+
+#if (NGX_HAVE_SENDFILE)
+
+ /*
+ * The determination of the sendfile() "nbytes bug" is complex enough.
+ * There are two sendfile() syscalls: a new #393 has no bug while
+ * an old #336 has the bug in some versions and has not in others.
+ * Besides libc_r wrapper also emulates the bug in some versions.
+ * There is no way to say exactly if syscall #336 in FreeBSD circa 4.6
+ * has the bug. We use the algorithm that is correct at least for
+ * RELEASEs and for syscalls only (not libc_r wrapper).
+ *
+ * 4.6.1-RELEASE and below have the bug
+ * 4.6.2-RELEASE and above have the new syscall
+ *
+ * We detect the new sendfile() syscall available at the compile time
+ * to allow an old binary to run correctly on an updated FreeBSD system.
+ */
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \
+ || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039
+
+ /* a new syscall without the bug */
+
+ ngx_freebsd_sendfile_nbytes_bug = 0;
+
+#else
+
+ /* an old syscall that may have the bug */
+
+ ngx_freebsd_sendfile_nbytes_bug = 1;
+
+#endif
+
+#endif /* NGX_HAVE_SENDFILE */
+
+
+ if ((version < 500000 && version >= 440003) || version >= 500017) {
+ ngx_freebsd_use_tcp_nopush = 1;
+ }
+
+
+ for (i = 0; sysctls[i].name; i++) {
+ size = sysctls[i].size;
+
+ if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0)
+ == 0)
+ {
+ sysctls[i].exists = 1;
+ continue;
+ }
+
+ err = ngx_errno;
+
+ if (err == NGX_ENOENT) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "sysctlbyname(%s) failed", sysctls[i].name);
+ return NGX_ERROR;
+ }
+
+ if (ngx_freebsd_machdep_hlt_logical_cpus) {
+ ngx_ncpu = ngx_freebsd_hw_ncpu / 2;
+
+ } else {
+ ngx_ncpu = ngx_freebsd_hw_ncpu;
+ }
+
+ if (version < 600008 && ngx_freebsd_kern_ipc_somaxconn > 32767) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "sysctl kern.ipc.somaxconn must be less than 32768");
+ return NGX_ERROR;
+ }
+
+ ngx_tcp_nodelay_and_tcp_nopush = 1;
+
+ ngx_os_io = ngx_freebsd_io;
+
+ return NGX_OK;
+}
+
+
+void
+ngx_os_specific_status(ngx_log_t *log)
+{
+ u_long value;
+ ngx_uint_t i;
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
+ ngx_freebsd_kern_ostype, ngx_freebsd_kern_osrelease);
+
+#ifdef __DragonFly_version
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "kern.osreldate: %d, built on %d",
+ ngx_freebsd_kern_osreldate, __DragonFly_version);
+#else
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "kern.osreldate: %d, built on %d",
+ ngx_freebsd_kern_osreldate, __FreeBSD_version);
+#endif
+
+ for (i = 0; sysctls[i].name; i++) {
+ if (sysctls[i].exists) {
+ if (sysctls[i].size == sizeof(long)) {
+ value = *(long *) sysctls[i].value;
+
+ } else {
+ value = *(int *) sysctls[i].value;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "%s: %l",
+ sysctls[i].name, value);
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c b/app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c
new file mode 100644
index 0000000..4822e72
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -0,0 +1,333 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * Although FreeBSD sendfile() allows to pass a header and a trailer,
+ * it cannot send a header with a part of the file in one packet until
+ * FreeBSD 5.3. Besides, over the fast ethernet connection sendfile()
+ * may send the partially filled packets, i.e. the 8 file pages may be sent
+ * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
+ * and then again the 11 full 1460-bytes packets.
+ *
+ * Therefore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
+ * to postpone the sending - it not only sends a header and the first part of
+ * the file in one packet, but also sends the file pages in the full packets.
+ *
+ * But until FreeBSD 4.5 turning TCP_NOPUSH off does not flush a pending
+ * data that less than MSS, so that data may be sent with 5 second delay.
+ * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5, although it can be used
+ * for non-keepalive HTTP connections.
+ */
+
+
+ngx_chain_t *
+ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ int rc, flags;
+ off_t send, prev_send, sent;
+ size_t file_size;
+ ssize_t n;
+ ngx_uint_t eintr, eagain;
+ ngx_err_t err;
+ ngx_buf_t *file;
+ ngx_event_t *wev;
+ ngx_chain_t *cl;
+ ngx_iovec_t header, trailer;
+ struct sf_hdtr hdtr;
+ struct iovec headers[NGX_IOVS_PREALLOCATE];
+ struct iovec trailers[NGX_IOVS_PREALLOCATE];
+#if (NGX_HAVE_AIO_SENDFILE)
+ ngx_uint_t ebusy;
+ ngx_event_aio_t *aio;
+#endif
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+#if (NGX_HAVE_KQUEUE)
+
+ if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
+ (void) ngx_connection_error(c, wev->kq_errno,
+ "kevent() reported about an closed connection");
+ wev->error = 1;
+ return NGX_CHAIN_ERROR;
+ }
+
+#endif
+
+ /* the maximum limit size is the maximum size_t value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
+ limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
+ }
+
+ send = 0;
+ eagain = 0;
+ flags = 0;
+
+#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN)
+ aio = NULL;
+ file = NULL;
+#endif
+
+ header.iovs = headers;
+ header.nalloc = NGX_IOVS_PREALLOCATE;
+
+ trailer.iovs = trailers;
+ trailer.nalloc = NGX_IOVS_PREALLOCATE;
+
+ for ( ;; ) {
+ eintr = 0;
+#if (NGX_HAVE_AIO_SENDFILE)
+ ebusy = 0;
+#endif
+ prev_send = send;
+
+ /* create the header iovec and coalesce the neighbouring bufs */
+
+ cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
+
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ send += header.size;
+
+ if (cl && cl->buf->in_file && send < limit) {
+ file = cl->buf;
+
+ /* coalesce the neighbouring file bufs */
+
+ file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send);
+
+ send += file_size;
+
+ if (send < limit) {
+
+ /*
+ * create the trailer iovec and coalesce the neighbouring bufs
+ */
+
+ cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send,
+ c->log);
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ send += trailer.size;
+
+ } else {
+ trailer.count = 0;
+ }
+
+ if (ngx_freebsd_use_tcp_nopush
+ && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET)
+ {
+ if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
+ err = ngx_socket_errno;
+
+ /*
+ * there is a tiny chance to be interrupted, however,
+ * we continue a processing without the TCP_NOPUSH
+ */
+
+ if (err != NGX_EINTR) {
+ wev->error = 1;
+ (void) ngx_connection_error(c, err,
+ ngx_tcp_nopush_n " failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ } else {
+ c->tcp_nopush = NGX_TCP_NOPUSH_SET;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "tcp_nopush");
+ }
+ }
+
+ /*
+ * sendfile() does unneeded work if sf_hdtr's count is 0,
+ * but corresponding pointer is not NULL
+ */
+
+ hdtr.headers = header.count ? header.iovs : NULL;
+ hdtr.hdr_cnt = header.count;
+ hdtr.trailers = trailer.count ? trailer.iovs : NULL;
+ hdtr.trl_cnt = trailer.count;
+
+ /*
+ * the "nbytes bug" of the old sendfile() syscall:
+ * http://bugs.freebsd.org/33771
+ */
+
+ if (!ngx_freebsd_sendfile_nbytes_bug) {
+ header.size = 0;
+ }
+
+ sent = 0;
+
+#if (NGX_HAVE_AIO_SENDFILE)
+ aio = file->file->aio;
+ flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0;
+#endif
+
+ rc = sendfile(file->file->fd, c->fd, file->file_pos,
+ file_size + header.size, &hdtr, &sent, flags);
+
+ if (rc == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ eagain = 1;
+ break;
+
+ case NGX_EINTR:
+ eintr = 1;
+ break;
+
+#if (NGX_HAVE_AIO_SENDFILE)
+ case NGX_EBUSY:
+ ebusy = 1;
+ break;
+#endif
+
+ default:
+ wev->error = 1;
+ (void) ngx_connection_error(c, err, "sendfile() failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfile() sent only %O bytes", sent);
+
+ /*
+ * sendfile() in FreeBSD 3.x-4.x may return value >= 0
+ * on success, although only 0 is documented
+ */
+
+ } else if (rc >= 0 && sent == 0) {
+
+ /*
+ * if rc is OK and sent equal to zero, then someone
+ * has truncated the file, so the offset became beyond
+ * the end of the file
+ */
+
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfile() reported that \"%s\" was truncated at %O",
+ file->file->name.data, file->file_pos);
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendfile: %d, @%O %O:%uz",
+ rc, file->file_pos, sent, file_size + header.size);
+
+ } else {
+ n = ngx_writev(c, &header);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ sent = (n == NGX_AGAIN) ? 0 : n;
+ }
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+#if (NGX_HAVE_AIO_SENDFILE)
+
+ if (ebusy) {
+ if (aio->event.active) {
+ /*
+ * tolerate duplicate calls; they can happen due to subrequests
+ * or multiple calls of the next body filter from a filter
+ */
+
+ if (sent) {
+ c->busy_count = 0;
+ }
+
+ return in;
+ }
+
+ if (sent == 0) {
+ c->busy_count++;
+
+ if (c->busy_count > 2) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfile(%V) returned busy again",
+ &file->file->name);
+
+ c->busy_count = 0;
+ aio->preload_handler = NULL;
+
+ send = prev_send;
+ continue;
+ }
+
+ } else {
+ c->busy_count = 0;
+ }
+
+ n = aio->preload_handler(file);
+
+ if (n > 0) {
+ send = prev_send + sent;
+ continue;
+ }
+
+ return in;
+ }
+
+ if (flags == SF_NODISKIO) {
+ c->busy_count = 0;
+ }
+
+#endif
+
+ if (eagain) {
+
+ /*
+ * sendfile() may return EAGAIN, even if it has sent a whole file
+ * part, it indicates that the successive sendfile() call would
+ * return EAGAIN right away and would not send anything.
+ * We use it as a hint.
+ */
+
+ wev->ready = 0;
+ return in;
+ }
+
+ if (eintr) {
+ send = prev_send + sent;
+ continue;
+ }
+
+ if (send - prev_send != sent) {
+ wev->ready = 0;
+ return in;
+ }
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h b/app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h
new file mode 100644
index 0000000..159a297
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h
@@ -0,0 +1,82 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#if (NGX_SMP)
+#define NGX_SMP_LOCK "lock;"
+#else
+#define NGX_SMP_LOCK
+#endif
+
+
+/*
+ * "cmpxchgq r, [m]":
+ *
+ * if (rax == [m]) {
+ * zf = 1;
+ * [m] = r;
+ * } else {
+ * zf = 0;
+ * rax = [m];
+ * }
+ *
+ *
+ * The "r" is any register, %rax (%r0) - %r16.
+ * The "=a" and "a" are the %rax register.
+ * Although we can return result in any register, we use "a" because it is
+ * used in cmpxchgq anyway. The result is actually in %al but not in $rax,
+ * however as the code is inlined gcc can test %al as well as %rax.
+ *
+ * The "cc" means that flags were changed.
+ */
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ u_char res;
+
+ __asm__ volatile (
+
+ NGX_SMP_LOCK
+ " cmpxchgq %3, %1; "
+ " sete %0; "
+
+ : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");
+
+ return res;
+}
+
+
+/*
+ * "xaddq r, [m]":
+ *
+ * temp = [m];
+ * [m] += r;
+ * r = temp;
+ *
+ *
+ * The "+r" is any register, %rax (%r0) - %r16.
+ * The "cc" means that flags were changed.
+ */
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ __asm__ volatile (
+
+ NGX_SMP_LOCK
+ " xaddq %0, %1; "
+
+ : "+r" (add) : "m" (*value) : "cc", "memory");
+
+ return add;
+}
+
+
+#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory")
+
+#define ngx_cpu_pause() __asm__ ("pause")
diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h b/app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h
new file mode 100644
index 0000000..45afc4b
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h
@@ -0,0 +1,155 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+/*
+ * The ppc assembler treats ";" as comment, so we have to use "\n".
+ * The minus in "bne-" is a hint for the branch prediction unit that
+ * this branch is unlikely to be taken.
+ * The "1b" means the nearest backward label "1" and the "1f" means
+ * the nearest forward label "1".
+ *
+ * The "b" means that the base registers can be used only, i.e.
+ * any register except r0. The r0 register always has a zero value and
+ * could not be used in "addi r0, r0, 1".
+ * The "=&b" means that no input registers can be used.
+ *
+ * "sync" read and write barriers
+ * "isync" read barrier, is faster than "sync"
+ * "eieio" write barrier, is faster than "sync"
+ * "lwsync" write barrier, is faster than "eieio" on ppc64
+ */
+
+#if (NGX_PTR_SIZE == 8)
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ ngx_atomic_uint_t res, temp;
+
+ __asm__ volatile (
+
+ " li %0, 0 \n" /* preset "0" to "res" */
+ " lwsync \n" /* write barrier */
+ "1: \n"
+ " ldarx %1, 0, %2 \n" /* load from [lock] into "temp" */
+ /* and store reservation */
+ " cmpd %1, %3 \n" /* compare "temp" and "old" */
+ " bne- 2f \n" /* not equal */
+ " stdcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */
+ /* is not cleared */
+ " bne- 1b \n" /* the reservation was cleared */
+ " isync \n" /* read barrier */
+ " li %0, 1 \n" /* set "1" to "res" */
+ "2: \n"
+
+ : "=&b" (res), "=&b" (temp)
+ : "b" (lock), "b" (old), "b" (set)
+ : "cc", "memory");
+
+ return res;
+}
+
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ ngx_atomic_uint_t res, temp;
+
+ __asm__ volatile (
+
+ " lwsync \n" /* write barrier */
+ "1: ldarx %0, 0, %2 \n" /* load from [value] into "res" */
+ /* and store reservation */
+ " add %1, %0, %3 \n" /* "res" + "add" store in "temp" */
+ " stdcx. %1, 0, %2 \n" /* store "temp" into [value] if reservation */
+ /* is not cleared */
+ " bne- 1b \n" /* try again if reservation was cleared */
+ " isync \n" /* read barrier */
+
+ : "=&b" (res), "=&b" (temp)
+ : "b" (value), "b" (add)
+ : "cc", "memory");
+
+ return res;
+}
+
+
+#if (NGX_SMP)
+#define ngx_memory_barrier() \
+ __asm__ volatile ("isync \n lwsync \n" ::: "memory")
+#else
+#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory")
+#endif
+
+#else
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ ngx_atomic_uint_t res, temp;
+
+ __asm__ volatile (
+
+ " li %0, 0 \n" /* preset "0" to "res" */
+ " eieio \n" /* write barrier */
+ "1: \n"
+ " lwarx %1, 0, %2 \n" /* load from [lock] into "temp" */
+ /* and store reservation */
+ " cmpw %1, %3 \n" /* compare "temp" and "old" */
+ " bne- 2f \n" /* not equal */
+ " stwcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */
+ /* is not cleared */
+ " bne- 1b \n" /* the reservation was cleared */
+ " isync \n" /* read barrier */
+ " li %0, 1 \n" /* set "1" to "res" */
+ "2: \n"
+
+ : "=&b" (res), "=&b" (temp)
+ : "b" (lock), "b" (old), "b" (set)
+ : "cc", "memory");
+
+ return res;
+}
+
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ ngx_atomic_uint_t res, temp;
+
+ __asm__ volatile (
+
+ " eieio \n" /* write barrier */
+ "1: lwarx %0, 0, %2 \n" /* load from [value] into "res" */
+ /* and store reservation */
+ " add %1, %0, %3 \n" /* "res" + "add" store in "temp" */
+ " stwcx. %1, 0, %2 \n" /* store "temp" into [value] if reservation */
+ /* is not cleared */
+ " bne- 1b \n" /* try again if reservation was cleared */
+ " isync \n" /* read barrier */
+
+ : "=&b" (res), "=&b" (temp)
+ : "b" (value), "b" (add)
+ : "cc", "memory");
+
+ return res;
+}
+
+
+#if (NGX_SMP)
+#define ngx_memory_barrier() \
+ __asm__ volatile ("isync \n eieio \n" ::: "memory")
+#else
+#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory")
+#endif
+
+#endif
+
+
+#define ngx_cpu_pause()
diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h b/app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h
new file mode 100644
index 0000000..a84db35
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h
@@ -0,0 +1,82 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+/*
+ * "casa [r1] 0x80, r2, r0" and
+ * "casxa [r1] 0x80, r2, r0" do the following:
+ *
+ * if ([r1] == r2) {
+ * swap(r0, [r1]);
+ * } else {
+ * r0 = [r1];
+ * }
+ *
+ * so "r0 == r2" means that the operation was successful.
+ *
+ *
+ * The "r" means the general register.
+ * The "+r" means the general register used for both input and output.
+ */
+
+
+#if (NGX_PTR_SIZE == 4)
+#define NGX_CASA "casa"
+#else
+#define NGX_CASA "casxa"
+#endif
+
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ __asm__ volatile (
+
+ NGX_CASA " [%1] 0x80, %2, %0"
+
+ : "+r" (set) : "r" (lock), "r" (old) : "memory");
+
+ return (set == old);
+}
+
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ ngx_atomic_uint_t old, res;
+
+ old = *value;
+
+ for ( ;; ) {
+
+ res = old + add;
+
+ __asm__ volatile (
+
+ NGX_CASA " [%1] 0x80, %2, %0"
+
+ : "+r" (res) : "r" (value), "r" (old) : "memory");
+
+ if (res == old) {
+ return res;
+ }
+
+ old = res;
+ }
+}
+
+
+#if (NGX_SMP)
+#define ngx_memory_barrier() \
+ __asm__ volatile ( \
+ "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad" \
+ ::: "memory")
+#else
+#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory")
+#endif
+
+#define ngx_cpu_pause()
diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_x86.h b/app/nginx/src/os/unix/ngx_gcc_atomic_x86.h
new file mode 100644
index 0000000..54e01ae
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_gcc_atomic_x86.h
@@ -0,0 +1,127 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#if (NGX_SMP)
+#define NGX_SMP_LOCK "lock;"
+#else
+#define NGX_SMP_LOCK
+#endif
+
+
+/*
+ * "cmpxchgl r, [m]":
+ *
+ * if (eax == [m]) {
+ * zf = 1;
+ * [m] = r;
+ * } else {
+ * zf = 0;
+ * eax = [m];
+ * }
+ *
+ *
+ * The "r" means the general register.
+ * The "=a" and "a" are the %eax register.
+ * Although we can return result in any register, we use "a" because it is
+ * used in cmpxchgl anyway. The result is actually in %al but not in %eax,
+ * however, as the code is inlined gcc can test %al as well as %eax,
+ * and icc adds "movzbl %al, %eax" by itself.
+ *
+ * The "cc" means that flags were changed.
+ */
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ u_char res;
+
+ __asm__ volatile (
+
+ NGX_SMP_LOCK
+ " cmpxchgl %3, %1; "
+ " sete %0; "
+
+ : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");
+
+ return res;
+}
+
+
+/*
+ * "xaddl r, [m]":
+ *
+ * temp = [m];
+ * [m] += r;
+ * r = temp;
+ *
+ *
+ * The "+r" means the general register.
+ * The "cc" means that flags were changed.
+ */
+
+
+#if !(( __GNUC__ == 2 && __GNUC_MINOR__ <= 7 ) || ( __INTEL_COMPILER >= 800 ))
+
+/*
+ * icc 8.1 and 9.0 compile broken code with -march=pentium4 option:
+ * ngx_atomic_fetch_add() always return the input "add" value,
+ * so we use the gcc 2.7 version.
+ *
+ * icc 8.1 and 9.0 with -march=pentiumpro option or icc 7.1 compile
+ * correct code.
+ */
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ __asm__ volatile (
+
+ NGX_SMP_LOCK
+ " xaddl %0, %1; "
+
+ : "+r" (add) : "m" (*value) : "cc", "memory");
+
+ return add;
+}
+
+
+#else
+
+/*
+ * gcc 2.7 does not support "+r", so we have to use the fixed
+ * %eax ("=a" and "a") and this adds two superfluous instructions in the end
+ * of code, something like this: "mov %eax, %edx / mov %edx, %eax".
+ */
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ ngx_atomic_uint_t old;
+
+ __asm__ volatile (
+
+ NGX_SMP_LOCK
+ " xaddl %2, %1; "
+
+ : "=a" (old) : "m" (*value), "a" (add) : "cc", "memory");
+
+ return old;
+}
+
+#endif
+
+
+/*
+ * on x86 the write operations go in a program order, so we need only
+ * to disable the gcc reorder optimizations
+ */
+
+#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory")
+
+/* old "as" does not support "pause" opcode */
+#define ngx_cpu_pause() __asm__ (".byte 0xf3, 0x90")
diff --git a/app/nginx/src/os/unix/ngx_linux.h b/app/nginx/src/os/unix/ngx_linux.h
new file mode 100644
index 0000000..13d654e
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_linux.h
@@ -0,0 +1,16 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_LINUX_H_INCLUDED_
+#define _NGX_LINUX_H_INCLUDED_
+
+
+ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+
+#endif /* _NGX_LINUX_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_linux_aio_read.c b/app/nginx/src/os/unix/ngx_linux_aio_read.c
new file mode 100644
index 0000000..9f0a6c1
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_linux_aio_read.c
@@ -0,0 +1,148 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+extern int ngx_eventfd;
+extern aio_context_t ngx_aio_ctx;
+
+
+static void ngx_file_aio_event_handler(ngx_event_t *ev);
+
+
+static int
+io_submit(aio_context_t ctx, long n, struct iocb **paiocb)
+{
+ return syscall(SYS_io_submit, ctx, n, paiocb);
+}
+
+
+ngx_int_t
+ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool)
+{
+ ngx_event_aio_t *aio;
+
+ aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+ if (aio == NULL) {
+ return NGX_ERROR;
+ }
+
+ aio->file = file;
+ aio->fd = file->fd;
+ aio->event.data = aio;
+ aio->event.ready = 1;
+ aio->event.log = file->log;
+
+ file->aio = aio;
+
+ return NGX_OK;
+}
+
+
+ssize_t
+ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
+ ngx_pool_t *pool)
+{
+ ngx_err_t err;
+ struct iocb *piocb[1];
+ ngx_event_t *ev;
+ ngx_event_aio_t *aio;
+
+ if (!ngx_file_aio) {
+ return ngx_read_file(file, buf, size, offset);
+ }
+
+ if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ aio = file->aio;
+ ev = &aio->event;
+
+ if (!ev->ready) {
+ ngx_log_error(NGX_LOG_ALERT, file->log, 0,
+ "second aio post for \"%V\"", &file->name);
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "aio complete:%d @%O:%uz %V",
+ ev->complete, offset, size, &file->name);
+
+ if (ev->complete) {
+ ev->active = 0;
+ ev->complete = 0;
+
+ if (aio->res >= 0) {
+ ngx_set_errno(0);
+ return aio->res;
+ }
+
+ ngx_set_errno(-aio->res);
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+ "aio read \"%s\" failed", file->name.data);
+
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&aio->aiocb, sizeof(struct iocb));
+
+ aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev;
+ aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ aio->aiocb.aio_fildes = file->fd;
+ aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf;
+ aio->aiocb.aio_nbytes = size;
+ aio->aiocb.aio_offset = offset;
+ aio->aiocb.aio_flags = IOCB_FLAG_RESFD;
+ aio->aiocb.aio_resfd = ngx_eventfd;
+
+ ev->handler = ngx_file_aio_event_handler;
+
+ piocb[0] = &aio->aiocb;
+
+ if (io_submit(ngx_aio_ctx, 1, piocb) == 1) {
+ ev->active = 1;
+ ev->ready = 0;
+ ev->complete = 0;
+
+ return NGX_AGAIN;
+ }
+
+ err = ngx_errno;
+
+ if (err == NGX_EAGAIN) {
+ return ngx_read_file(file, buf, size, offset);
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ "io_submit(\"%V\") failed", &file->name);
+
+ if (err == NGX_ENOSYS) {
+ ngx_file_aio = 0;
+ return ngx_read_file(file, buf, size, offset);
+ }
+
+ return NGX_ERROR;
+}
+
+
+static void
+ngx_file_aio_event_handler(ngx_event_t *ev)
+{
+ ngx_event_aio_t *aio;
+
+ aio = ev->data;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "aio event handler fd:%d %V", aio->fd, &aio->file->name);
+
+ aio->handler(ev);
+}
diff --git a/app/nginx/src/os/unix/ngx_linux_config.h b/app/nginx/src/os/unix/ngx_linux_config.h
new file mode 100644
index 0000000..2f6129d
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_linux_config.h
@@ -0,0 +1,123 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_LINUX_CONFIG_H_INCLUDED_
+#define _NGX_LINUX_CONFIG_H_INCLUDED_
+
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* pread(), pwrite(), gethostname() */
+#endif
+
+#define _FILE_OFFSET_BITS 64
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h> /* offsetof() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <glob.h>
+#include <sys/vfs.h> /* statfs() */
+
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h> /* TCP_NODELAY, TCP_CORK */
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+
+#include <time.h> /* tzset() */
+#include <malloc.h> /* memalign() */
+#include <limits.h> /* IOV_MAX */
+#include <sys/ioctl.h>
+#include <crypt.h>
+#include <sys/utsname.h> /* uname() */
+
+#include <dlfcn.h>
+
+
+#include <ngx_auto_config.h>
+
+
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
+#if (NGX_HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h>
+#endif
+
+
+#if (NGX_HAVE_SENDFILE64)
+#include <sys/sendfile.h>
+#else
+extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
+#define NGX_SENDFILE_LIMIT 0x80000000
+#endif
+
+
+#if (NGX_HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (NGX_HAVE_EPOLL)
+#include <sys/epoll.h>
+#endif
+
+
+#if (NGX_HAVE_SYS_EVENTFD_H)
+#include <sys/eventfd.h>
+#endif
+#include <sys/syscall.h>
+#if (NGX_HAVE_FILE_AIO)
+#include <linux/aio_abi.h>
+typedef struct iocb ngx_aiocb_t;
+#endif
+
+
+#define NGX_LISTEN_BACKLOG 511
+
+
+#ifndef NGX_HAVE_SO_SNDLOWAT
+/* setsockopt(SO_SNDLOWAT) returns ENOPROTOOPT */
+#define NGX_HAVE_SO_SNDLOWAT 0
+#endif
+
+
+#ifndef NGX_HAVE_INHERITED_NONBLOCK
+#define NGX_HAVE_INHERITED_NONBLOCK 0
+#endif
+
+
+#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define ngx_debug_init()
+
+
+extern char **environ;
+
+
+#endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_linux_init.c b/app/nginx/src/os/unix/ngx_linux_init.c
new file mode 100644
index 0000000..a8cf6a0
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_linux_init.c
@@ -0,0 +1,60 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+u_char ngx_linux_kern_ostype[50];
+u_char ngx_linux_kern_osrelease[50];
+
+
+static ngx_os_io_t ngx_linux_io = {
+ ngx_unix_recv,
+ ngx_readv_chain,
+ ngx_udp_unix_recv,
+ ngx_unix_send,
+ ngx_udp_unix_send,
+ ngx_udp_unix_sendmsg_chain,
+#if (NGX_HAVE_SENDFILE)
+ ngx_linux_sendfile_chain,
+ NGX_IO_SENDFILE
+#else
+ ngx_writev_chain,
+ 0
+#endif
+};
+
+
+ngx_int_t
+ngx_os_specific_init(ngx_log_t *log)
+{
+ struct utsname u;
+
+ if (uname(&u) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "uname() failed");
+ return NGX_ERROR;
+ }
+
+ (void) ngx_cpystrn(ngx_linux_kern_ostype, (u_char *) u.sysname,
+ sizeof(ngx_linux_kern_ostype));
+
+ (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release,
+ sizeof(ngx_linux_kern_osrelease));
+
+ ngx_os_io = ngx_linux_io;
+
+ return NGX_OK;
+}
+
+
+void
+ngx_os_specific_status(ngx_log_t *log)
+{
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
+ ngx_linux_kern_ostype, ngx_linux_kern_osrelease);
+}
diff --git a/app/nginx/src/os/unix/ngx_linux_sendfile_chain.c b/app/nginx/src/os/unix/ngx_linux_sendfile_chain.c
new file mode 100644
index 0000000..b44724c
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_linux_sendfile_chain.c
@@ -0,0 +1,442 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ssize_t ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file,
+ size_t size);
+
+#if (NGX_THREADS)
+#include <ngx_thread_pool.h>
+
+#if !(NGX_HAVE_SENDFILE64)
+#error sendfile64() is required!
+#endif
+
+static ssize_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file,
+ size_t size);
+static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log);
+#endif
+
+
+/*
+ * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
+ * offsets only, and the including <sys/sendfile.h> breaks the compiling,
+ * if off_t is 64 bit wide. So we use own sendfile() definition, where offset
+ * parameter is int32_t, and use sendfile() for the file parts below 2G only,
+ * see src/os/unix/ngx_linux_config.h
+ *
+ * Linux 2.4.21 has the new sendfile64() syscall #239.
+ *
+ * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter
+ * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL,
+ * so we limit it to 2G-1 bytes.
+ */
+
+#define NGX_SENDFILE_MAXSIZE 2147483647L
+
+
+ngx_chain_t *
+ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ int tcp_nodelay;
+ off_t send, prev_send;
+ size_t file_size, sent;
+ ssize_t n;
+ ngx_err_t err;
+ ngx_buf_t *file;
+ ngx_event_t *wev;
+ ngx_chain_t *cl;
+ ngx_iovec_t header;
+ struct iovec headers[NGX_IOVS_PREALLOCATE];
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+
+ /* the maximum limit size is 2G-1 - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) {
+ limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize;
+ }
+
+
+ send = 0;
+
+ header.iovs = headers;
+ header.nalloc = NGX_IOVS_PREALLOCATE;
+
+ for ( ;; ) {
+ prev_send = send;
+
+ /* create the iovec and coalesce the neighbouring bufs */
+
+ cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
+
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ send += header.size;
+
+ /* set TCP_CORK if there is a header before a file */
+
+ if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET
+ && header.count != 0
+ && cl
+ && cl->buf->in_file)
+ {
+ /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
+
+ if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) {
+
+ tcp_nodelay = 0;
+
+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+ (const void *) &tcp_nodelay, sizeof(int)) == -1)
+ {
+ err = ngx_socket_errno;
+
+ /*
+ * there is a tiny chance to be interrupted, however,
+ * we continue a processing with the TCP_NODELAY
+ * and without the TCP_CORK
+ */
+
+ if (err != NGX_EINTR) {
+ wev->error = 1;
+ ngx_connection_error(c, err,
+ "setsockopt(TCP_NODELAY) failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ } else {
+ c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "no tcp_nodelay");
+ }
+ }
+
+ if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
+
+ if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
+ err = ngx_socket_errno;
+
+ /*
+ * there is a tiny chance to be interrupted, however,
+ * we continue a processing without the TCP_CORK
+ */
+
+ if (err != NGX_EINTR) {
+ wev->error = 1;
+ ngx_connection_error(c, err,
+ ngx_tcp_nopush_n " failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ } else {
+ c->tcp_nopush = NGX_TCP_NOPUSH_SET;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "tcp_nopush");
+ }
+ }
+ }
+
+ /* get the file buf */
+
+ if (header.count == 0 && cl && cl->buf->in_file && send < limit) {
+ file = cl->buf;
+
+ /* coalesce the neighbouring file bufs */
+
+ file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send);
+
+ send += file_size;
+#if 1
+ if (file_size == 0) {
+ ngx_debug_point();
+ return NGX_CHAIN_ERROR;
+ }
+#endif
+
+ n = ngx_linux_sendfile(c, file, file_size);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (n == NGX_DONE) {
+ /* thread task posted */
+ return in;
+ }
+
+ sent = (n == NGX_AGAIN) ? 0 : n;
+
+ } else {
+ n = ngx_writev(c, &header);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ sent = (n == NGX_AGAIN) ? 0 : n;
+ }
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+ if (n == NGX_AGAIN) {
+ wev->ready = 0;
+ return in;
+ }
+
+ if ((size_t) (send - prev_send) != sent) {
+
+ /*
+ * sendfile() on Linux 4.3+ might be interrupted at any time,
+ * and provides no indication if it was interrupted or not,
+ * so we have to retry till an explicit EAGAIN
+ *
+ * sendfile() in threads can also report less bytes written
+ * than we are prepared to send now, since it was started in
+ * some point in the past, so we again have to retry
+ */
+
+ send = prev_send + sent;
+ continue;
+ }
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
+
+
+static ssize_t
+ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size)
+{
+#if (NGX_HAVE_SENDFILE64)
+ off_t offset;
+#else
+ int32_t offset;
+#endif
+ ssize_t n;
+ ngx_err_t err;
+
+#if (NGX_THREADS)
+
+ if (file->file->thread_handler) {
+ return ngx_linux_sendfile_thread(c, file, size);
+ }
+
+#endif
+
+#if (NGX_HAVE_SENDFILE64)
+ offset = file->file_pos;
+#else
+ offset = (int32_t) file->file_pos;
+#endif
+
+eintr:
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendfile: @%O %uz", file->file_pos, size);
+
+ n = sendfile(c->fd, file->file->fd, &offset, size);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfile() is not ready");
+ return NGX_AGAIN;
+
+ case NGX_EINTR:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfile() was interrupted");
+ goto eintr;
+
+ default:
+ c->write->error = 1;
+ ngx_connection_error(c, err, "sendfile() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ if (n == 0) {
+ /*
+ * if sendfile returns zero, then someone has truncated the file,
+ * so the offset became beyond the end of the file
+ */
+
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfile() reported that \"%s\" was truncated at %O",
+ file->file->name.data, file->file_pos);
+
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O",
+ n, size, file->file_pos);
+
+ return n;
+}
+
+
+#if (NGX_THREADS)
+
+typedef struct {
+ ngx_buf_t *file;
+ ngx_socket_t socket;
+ size_t size;
+
+ size_t sent;
+ ngx_err_t err;
+} ngx_linux_sendfile_ctx_t;
+
+
+static ssize_t
+ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size)
+{
+ ngx_event_t *wev;
+ ngx_thread_task_t *task;
+ ngx_linux_sendfile_ctx_t *ctx;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "linux sendfile thread: %d, %uz, %O",
+ file->file->fd, size, file->file_pos);
+
+ task = c->sendfile_task;
+
+ if (task == NULL) {
+ task = ngx_thread_task_alloc(c->pool, sizeof(ngx_linux_sendfile_ctx_t));
+ if (task == NULL) {
+ return NGX_ERROR;
+ }
+
+ task->handler = ngx_linux_sendfile_thread_handler;
+
+ c->sendfile_task = task;
+ }
+
+ ctx = task->ctx;
+ wev = c->write;
+
+ if (task->event.complete) {
+ task->event.complete = 0;
+
+ if (ctx->err == NGX_EAGAIN) {
+ /*
+ * if wev->complete is set, this means that a write event
+ * happened while we were waiting for the thread task, so
+ * we have to retry sending even on EAGAIN
+ */
+
+ if (wev->complete) {
+ return 0;
+ }
+
+ return NGX_AGAIN;
+ }
+
+ if (ctx->err) {
+ wev->error = 1;
+ ngx_connection_error(c, ctx->err, "sendfile() failed");
+ return NGX_ERROR;
+ }
+
+ if (ctx->sent == 0) {
+ /*
+ * if sendfile returns zero, then someone has truncated the file,
+ * so the offset became beyond the end of the file
+ */
+
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfile() reported that \"%s\" was truncated at %O",
+ file->file->name.data, file->file_pos);
+
+ return NGX_ERROR;
+ }
+
+ return ctx->sent;
+ }
+
+ if (task->event.active && ctx->file == file) {
+ /*
+ * tolerate duplicate calls; they can happen due to subrequests
+ * or multiple calls of the next body filter from a filter
+ */
+
+ return NGX_DONE;
+ }
+
+ ctx->file = file;
+ ctx->socket = c->fd;
+ ctx->size = size;
+
+ wev->complete = 0;
+
+ if (file->file->thread_handler(task, file->file) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ return NGX_DONE;
+}
+
+
+static void
+ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log)
+{
+ ngx_linux_sendfile_ctx_t *ctx = data;
+
+ off_t offset;
+ ssize_t n;
+ ngx_buf_t *file;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "linux sendfile thread handler");
+
+ file = ctx->file;
+ offset = file->file_pos;
+
+again:
+
+ n = sendfile(ctx->socket, file->file->fd, &offset, ctx->size);
+
+ if (n == -1) {
+ ctx->err = ngx_errno;
+
+ } else {
+ ctx->sent = n;
+ ctx->err = 0;
+ }
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
+ "sendfile: %z (err: %d) of %uz @%O",
+ n, ctx->err, ctx->size, file->file_pos);
+
+ if (ctx->err == NGX_EINTR) {
+ goto again;
+ }
+}
+
+#endif /* NGX_THREADS */
diff --git a/app/nginx/src/os/unix/ngx_os.h b/app/nginx/src/os/unix/ngx_os.h
new file mode 100644
index 0000000..3b32819
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_os.h
@@ -0,0 +1,102 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_OS_H_INCLUDED_
+#define _NGX_OS_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_IO_SENDFILE 1
+
+
+typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);
+typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size);
+typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+typedef struct {
+ ngx_recv_pt recv;
+ ngx_recv_chain_pt recv_chain;
+ ngx_recv_pt udp_recv;
+ ngx_send_pt send;
+ ngx_send_pt udp_send;
+ ngx_send_chain_pt udp_send_chain;
+ ngx_send_chain_pt send_chain;
+ ngx_uint_t flags;
+} ngx_os_io_t;
+
+
+ngx_int_t ngx_os_init(ngx_log_t *log);
+void ngx_os_status(ngx_log_t *log);
+ngx_int_t ngx_os_specific_init(ngx_log_t *log);
+void ngx_os_specific_status(ngx_log_t *log);
+ngx_int_t ngx_daemon(ngx_log_t *log);
+ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid);
+
+
+ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry, off_t limit);
+ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size);
+ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+ssize_t ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size);
+ngx_chain_t *ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+
+#if (IOV_MAX > 64)
+#define NGX_IOVS_PREALLOCATE 64
+#else
+#define NGX_IOVS_PREALLOCATE IOV_MAX
+#endif
+
+
+typedef struct {
+ struct iovec *iovs;
+ ngx_uint_t count;
+ size_t size;
+ ngx_uint_t nalloc;
+} ngx_iovec_t;
+
+ngx_chain_t *ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in,
+ size_t limit, ngx_log_t *log);
+
+
+ssize_t ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec);
+
+
+extern ngx_os_io_t ngx_os_io;
+extern ngx_int_t ngx_ncpu;
+extern ngx_int_t ngx_max_sockets;
+extern ngx_uint_t ngx_inherited_nonblocking;
+extern ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush;
+
+
+#if (NGX_FREEBSD)
+#include <ngx_freebsd.h>
+
+
+#elif (NGX_LINUX)
+#include <ngx_linux.h>
+
+
+#elif (NGX_SOLARIS)
+#include <ngx_solaris.h>
+
+
+#elif (NGX_DARWIN)
+#include <ngx_darwin.h>
+#endif
+
+
+#endif /* _NGX_OS_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_posix_config.h b/app/nginx/src/os/unix/ngx_posix_config.h
new file mode 100644
index 0000000..5d1358e
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_posix_config.h
@@ -0,0 +1,171 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_POSIX_CONFIG_H_INCLUDED_
+#define _NGX_POSIX_CONFIG_H_INCLUDED_
+
+
+#if (NGX_HPUX)
+#define _XOPEN_SOURCE
+#define _XOPEN_SOURCE_EXTENDED 1
+#define _HPUX_ALT_XOPEN_SOCKET_API
+#endif
+
+
+#if (NGX_TRU64)
+#define _REENTRANT
+#endif
+
+
+#if (NGX_GNU_HURD)
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* accept4() */
+#endif
+#define _FILE_OFFSET_BITS 64
+#endif
+
+
+#ifdef __CYGWIN__
+#define timezonevar /* timezone is variable */
+#define NGX_BROKEN_SCM_RIGHTS 1
+#endif
+
+
+#include <sys/types.h>
+#include <sys/time.h>
+#if (NGX_HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#if (NGX_HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#include <stdarg.h>
+#include <stddef.h> /* offsetof() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <glob.h>
+#include <time.h>
+#if (NGX_HAVE_SYS_PARAM_H)
+#include <sys/param.h> /* statfs() */
+#endif
+#if (NGX_HAVE_SYS_MOUNT_H)
+#include <sys/mount.h> /* statfs() */
+#endif
+#if (NGX_HAVE_SYS_STATVFS_H)
+#include <sys/statvfs.h> /* statvfs() */
+#endif
+
+#if (NGX_HAVE_SYS_FILIO_H)
+#include <sys/filio.h> /* FIONBIO */
+#endif
+#include <sys/ioctl.h> /* FIONBIO */
+
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h> /* TCP_NODELAY */
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+
+#if (NGX_HAVE_LIMITS_H)
+#include <limits.h> /* IOV_MAX */
+#endif
+
+#ifdef __CYGWIN__
+#include <malloc.h> /* memalign() */
+#endif
+
+#if (NGX_HAVE_CRYPT_H)
+#include <crypt.h>
+#endif
+
+
+#ifndef IOV_MAX
+#define IOV_MAX 16
+#endif
+
+
+#include <ngx_auto_config.h>
+
+
+#if (NGX_HAVE_DLOPEN)
+#include <dlfcn.h>
+#endif
+
+
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
+#if (NGX_HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (NGX_HAVE_KQUEUE)
+#include <sys/event.h>
+#endif
+
+
+#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL)
+#include <sys/ioctl.h>
+#include <sys/devpoll.h>
+#endif
+
+
+#if (NGX_HAVE_FILE_AIO)
+#include <aio.h>
+typedef struct aiocb ngx_aiocb_t;
+#endif
+
+
+#define NGX_LISTEN_BACKLOG 511
+
+#define ngx_debug_init()
+
+
+#if (__FreeBSD__) && (__FreeBSD_version < 400017)
+
+#include <sys/param.h> /* ALIGN() */
+
+/*
+ * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
+ */
+
+#undef CMSG_SPACE
+#define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
+
+#undef CMSG_LEN
+#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l))
+
+#undef CMSG_DATA
+#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
+
+#endif
+
+
+extern char **environ;
+
+
+#endif /* _NGX_POSIX_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_posix_init.c b/app/nginx/src/os/unix/ngx_posix_init.c
new file mode 100644
index 0000000..583ea4f
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_posix_init.c
@@ -0,0 +1,134 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <nginx.h>
+
+
+ngx_int_t ngx_ncpu;
+ngx_int_t ngx_max_sockets;
+ngx_uint_t ngx_inherited_nonblocking;
+ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush;
+
+
+struct rlimit rlmt;
+
+
+ngx_os_io_t ngx_os_io = {
+ ngx_unix_recv,
+ ngx_readv_chain,
+ ngx_udp_unix_recv,
+ ngx_unix_send,
+ ngx_udp_unix_send,
+ ngx_udp_unix_sendmsg_chain,
+ ngx_writev_chain,
+ 0
+};
+
+
+ngx_int_t
+ngx_os_init(ngx_log_t *log)
+{
+ ngx_time_t *tp;
+ ngx_uint_t n;
+
+#if (NGX_HAVE_OS_SPECIFIC_INIT)
+ if (ngx_os_specific_init(log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+#endif
+
+ if (ngx_init_setproctitle(log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_pagesize = getpagesize();
+ ngx_cacheline_size = NGX_CPU_CACHE_LINE;
+
+ for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }
+
+#if (NGX_HAVE_SC_NPROCESSORS_ONLN)
+ if (ngx_ncpu == 0) {
+ ngx_ncpu = sysconf(_SC_NPROCESSORS_ONLN);
+ }
+#endif
+
+ if (ngx_ncpu < 1) {
+ ngx_ncpu = 1;
+ }
+
+ ngx_cpuinfo();
+
+ if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, errno,
+ "getrlimit(RLIMIT_NOFILE) failed");
+ return NGX_ERROR;
+ }
+
+ ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur;
+
+#if (NGX_HAVE_INHERITED_NONBLOCK || NGX_HAVE_ACCEPT4)
+ ngx_inherited_nonblocking = 1;
+#else
+ ngx_inherited_nonblocking = 0;
+#endif
+
+ tp = ngx_timeofday();
+ srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec);
+
+ return NGX_OK;
+}
+
+
+void
+ngx_os_status(ngx_log_t *log)
+{
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD);
+
+#ifdef NGX_COMPILER
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "built by " NGX_COMPILER);
+#endif
+
+#if (NGX_HAVE_OS_SPECIFIC_INIT)
+ ngx_os_specific_status(log);
+#endif
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "getrlimit(RLIMIT_NOFILE): %r:%r",
+ rlmt.rlim_cur, rlmt.rlim_max);
+}
+
+
+#if 0
+
+ngx_int_t
+ngx_posix_post_conf_init(ngx_log_t *log)
+{
+ ngx_fd_t pp[2];
+
+ if (pipe(pp) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "pipe() failed");
+ return NGX_ERROR;
+ }
+
+ if (dup2(pp[1], STDERR_FILENO) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDERR) failed");
+ return NGX_ERROR;
+ }
+
+ if (pp[1] > STDERR_FILENO) {
+ if (close(pp[1]) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, errno, "close() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_process.c b/app/nginx/src/os/unix/ngx_process.c
new file mode 100644
index 0000000..2d37e21
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_process.c
@@ -0,0 +1,630 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_channel.h>
+
+
+typedef struct {
+ int signo;
+ char *signame;
+ char *name;
+ void (*handler)(int signo);
+} ngx_signal_t;
+
+
+
+static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
+static void ngx_signal_handler(int signo);
+static void ngx_process_get_status(void);
+static void ngx_unlock_mutexes(ngx_pid_t pid);
+
+
+int ngx_argc;
+char **ngx_argv;
+char **ngx_os_argv;
+
+ngx_int_t ngx_process_slot;
+ngx_socket_t ngx_channel;
+ngx_int_t ngx_last_process;
+ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
+
+
+ngx_signal_t signals[] = {
+ { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
+ "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
+ "reload",
+ ngx_signal_handler },
+
+ { ngx_signal_value(NGX_REOPEN_SIGNAL),
+ "SIG" ngx_value(NGX_REOPEN_SIGNAL),
+ "reopen",
+ ngx_signal_handler },
+
+ { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
+ "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
+ "",
+ ngx_signal_handler },
+
+ { ngx_signal_value(NGX_TERMINATE_SIGNAL),
+ "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
+ "stop",
+ ngx_signal_handler },
+
+ { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
+ "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
+ "quit",
+ ngx_signal_handler },
+
+ { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
+ "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
+ "",
+ ngx_signal_handler },
+
+ { SIGALRM, "SIGALRM", "", ngx_signal_handler },
+
+ { SIGINT, "SIGINT", "", ngx_signal_handler },
+
+ { SIGIO, "SIGIO", "", ngx_signal_handler },
+
+ { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
+
+ { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
+
+ { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
+
+ { 0, NULL, "", NULL }
+};
+
+
+ngx_pid_t
+ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
+ char *name, ngx_int_t respawn)
+{
+ u_long on;
+ ngx_pid_t pid;
+ ngx_int_t s;
+
+ if (respawn >= 0) {
+ s = respawn;
+
+ } else {
+ for (s = 0; s < ngx_last_process; s++) {
+ if (ngx_processes[s].pid == -1) {
+ break;
+ }
+ }
+
+ if (s == NGX_MAX_PROCESSES) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "no more than %d processes can be spawned",
+ NGX_MAX_PROCESSES);
+ return NGX_INVALID_PID;
+ }
+ }
+
+
+ if (respawn != NGX_PROCESS_DETACHED) {
+
+ /* Solaris 9 still has no AF_LOCAL */
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "socketpair() failed while spawning \"%s\"", name);
+ return NGX_INVALID_PID;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "channel %d:%d",
+ ngx_processes[s].channel[0],
+ ngx_processes[s].channel[1]);
+
+ if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_nonblocking_n " failed while spawning \"%s\"",
+ name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+ }
+
+ if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_nonblocking_n " failed while spawning \"%s\"",
+ name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+ }
+
+ on = 1;
+ if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+ }
+
+ if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+ }
+
+ if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
+ name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+ }
+
+ if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
+ name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+ }
+
+ ngx_channel = ngx_processes[s].channel[1];
+
+ } else {
+ ngx_processes[s].channel[0] = -1;
+ ngx_processes[s].channel[1] = -1;
+ }
+
+ ngx_process_slot = s;
+
+
+ pid = fork();
+
+ switch (pid) {
+
+ case -1:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "fork() failed while spawning \"%s\"", name);
+ ngx_close_channel(ngx_processes[s].channel, cycle->log);
+ return NGX_INVALID_PID;
+
+ case 0:
+ ngx_pid = ngx_getpid();
+ proc(cycle, data);
+ break;
+
+ default:
+ break;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
+
+ ngx_processes[s].pid = pid;
+ ngx_processes[s].exited = 0;
+
+ if (respawn >= 0) {
+ return pid;
+ }
+
+ ngx_processes[s].proc = proc;
+ ngx_processes[s].data = data;
+ ngx_processes[s].name = name;
+ ngx_processes[s].exiting = 0;
+
+ switch (respawn) {
+
+ case NGX_PROCESS_NORESPAWN:
+ ngx_processes[s].respawn = 0;
+ ngx_processes[s].just_spawn = 0;
+ ngx_processes[s].detached = 0;
+ break;
+
+ case NGX_PROCESS_JUST_SPAWN:
+ ngx_processes[s].respawn = 0;
+ ngx_processes[s].just_spawn = 1;
+ ngx_processes[s].detached = 0;
+ break;
+
+ case NGX_PROCESS_RESPAWN:
+ ngx_processes[s].respawn = 1;
+ ngx_processes[s].just_spawn = 0;
+ ngx_processes[s].detached = 0;
+ break;
+
+ case NGX_PROCESS_JUST_RESPAWN:
+ ngx_processes[s].respawn = 1;
+ ngx_processes[s].just_spawn = 1;
+ ngx_processes[s].detached = 0;
+ break;
+
+ case NGX_PROCESS_DETACHED:
+ ngx_processes[s].respawn = 0;
+ ngx_processes[s].just_spawn = 0;
+ ngx_processes[s].detached = 1;
+ break;
+ }
+
+ if (s == ngx_last_process) {
+ ngx_last_process++;
+ }
+
+ return pid;
+}
+
+
+ngx_pid_t
+ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
+{
+ return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
+ NGX_PROCESS_DETACHED);
+}
+
+
+static void
+ngx_execute_proc(ngx_cycle_t *cycle, void *data)
+{
+ ngx_exec_ctx_t *ctx = data;
+
+ if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "execve() failed while executing %s \"%s\"",
+ ctx->name, ctx->path);
+ }
+
+ exit(1);
+}
+
+
+ngx_int_t
+ngx_init_signals(ngx_log_t *log)
+{
+ ngx_signal_t *sig;
+ struct sigaction sa;
+
+ for (sig = signals; sig->signo != 0; sig++) {
+ ngx_memzero(&sa, sizeof(struct sigaction));
+ sa.sa_handler = sig->handler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(sig->signo, &sa, NULL) == -1) {
+#if (NGX_VALGRIND)
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sigaction(%s) failed, ignored", sig->signame);
+#else
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "sigaction(%s) failed", sig->signame);
+ return NGX_ERROR;
+#endif
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_signal_handler(int signo)
+{
+ char *action;
+ ngx_int_t ignore;
+ ngx_err_t err;
+ ngx_signal_t *sig;
+
+ ignore = 0;
+
+ err = ngx_errno;
+
+ for (sig = signals; sig->signo != 0; sig++) {
+ if (sig->signo == signo) {
+ break;
+ }
+ }
+
+ ngx_time_sigsafe_update();
+
+ action = "";
+
+ switch (ngx_process) {
+
+ case NGX_PROCESS_MASTER:
+ case NGX_PROCESS_SINGLE:
+ switch (signo) {
+
+ case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
+ ngx_quit = 1;
+ action = ", shutting down";
+ break;
+
+ case ngx_signal_value(NGX_TERMINATE_SIGNAL):
+ case SIGINT:
+ ngx_terminate = 1;
+ action = ", exiting";
+ break;
+
+ case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
+ if (ngx_daemonized) {
+ ngx_noaccept = 1;
+ action = ", stop accepting connections";
+ }
+ break;
+
+ case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
+ ngx_reconfigure = 1;
+ action = ", reconfiguring";
+ break;
+
+ case ngx_signal_value(NGX_REOPEN_SIGNAL):
+ ngx_reopen = 1;
+ action = ", reopening logs";
+ break;
+
+ case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
+ if (getppid() > 1 || ngx_new_binary > 0) {
+
+ /*
+ * Ignore the signal in the new binary if its parent is
+ * not the init process, i.e. the old binary's process
+ * is still running. Or ignore the signal in the old binary's
+ * process if the new binary's process is already running.
+ */
+
+ action = ", ignoring";
+ ignore = 1;
+ break;
+ }
+
+ ngx_change_binary = 1;
+ action = ", changing binary";
+ break;
+
+ case SIGALRM:
+ ngx_sigalrm = 1;
+ break;
+
+ case SIGIO:
+ ngx_sigio = 1;
+ break;
+
+ case SIGCHLD:
+ ngx_reap = 1;
+ break;
+ }
+
+ break;
+
+ case NGX_PROCESS_WORKER:
+ case NGX_PROCESS_HELPER:
+ switch (signo) {
+
+ case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
+ if (!ngx_daemonized) {
+ break;
+ }
+ ngx_debug_quit = 1;
+ case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
+ ngx_quit = 1;
+ action = ", shutting down";
+ break;
+
+ case ngx_signal_value(NGX_TERMINATE_SIGNAL):
+ case SIGINT:
+ ngx_terminate = 1;
+ action = ", exiting";
+ break;
+
+ case ngx_signal_value(NGX_REOPEN_SIGNAL):
+ ngx_reopen = 1;
+ action = ", reopening logs";
+ break;
+
+ case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
+ case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
+ case SIGIO:
+ action = ", ignoring";
+ break;
+ }
+
+ break;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+ "signal %d (%s) received%s", signo, sig->signame, action);
+
+ if (ignore) {
+ ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
+ "the changing binary signal is ignored: "
+ "you should shutdown or terminate "
+ "before either old or new binary's process");
+ }
+
+ if (signo == SIGCHLD) {
+ ngx_process_get_status();
+ }
+
+ ngx_set_errno(err);
+}
+
+
+static void
+ngx_process_get_status(void)
+{
+ int status;
+ char *process;
+ ngx_pid_t pid;
+ ngx_err_t err;
+ ngx_int_t i;
+ ngx_uint_t one;
+
+ one = 0;
+
+ for ( ;; ) {
+ pid = waitpid(-1, &status, WNOHANG);
+
+ if (pid == 0) {
+ return;
+ }
+
+ if (pid == -1) {
+ err = ngx_errno;
+
+ if (err == NGX_EINTR) {
+ continue;
+ }
+
+ if (err == NGX_ECHILD && one) {
+ return;
+ }
+
+ /*
+ * Solaris always calls the signal handler for each exited process
+ * despite waitpid() may be already called for this process.
+ *
+ * When several processes exit at the same time FreeBSD may
+ * erroneously call the signal handler for exited process
+ * despite waitpid() may be already called for this process.
+ */
+
+ if (err == NGX_ECHILD) {
+ ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
+ "waitpid() failed");
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
+ "waitpid() failed");
+ return;
+ }
+
+
+ one = 1;
+ process = "unknown process";
+
+ for (i = 0; i < ngx_last_process; i++) {
+ if (ngx_processes[i].pid == pid) {
+ ngx_processes[i].status = status;
+ ngx_processes[i].exited = 1;
+ process = ngx_processes[i].name;
+ break;
+ }
+ }
+
+ if (WTERMSIG(status)) {
+#ifdef WCOREDUMP
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "%s %P exited on signal %d%s",
+ process, pid, WTERMSIG(status),
+ WCOREDUMP(status) ? " (core dumped)" : "");
+#else
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "%s %P exited on signal %d",
+ process, pid, WTERMSIG(status));
+#endif
+
+ } else {
+ ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+ "%s %P exited with code %d",
+ process, pid, WEXITSTATUS(status));
+ }
+
+ if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "%s %P exited with fatal code %d "
+ "and cannot be respawned",
+ process, pid, WEXITSTATUS(status));
+ ngx_processes[i].respawn = 0;
+ }
+
+ ngx_unlock_mutexes(pid);
+ }
+}
+
+
+static void
+ngx_unlock_mutexes(ngx_pid_t pid)
+{
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+ ngx_list_part_t *part;
+ ngx_slab_pool_t *sp;
+
+ /*
+ * unlock the accept mutex if the abnormally exited process
+ * held it
+ */
+
+ if (ngx_accept_mutex_ptr) {
+ (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
+ }
+
+ /*
+ * unlock shared memory mutexes if held by the abnormally exited
+ * process
+ */
+
+ part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ i = 0;
+ }
+
+ sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
+
+ if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "shared memory zone \"%V\" was locked by %P",
+ &shm_zone[i].shm.name, pid);
+ }
+ }
+}
+
+
+void
+ngx_debug_point(void)
+{
+ ngx_core_conf_t *ccf;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
+ ngx_core_module);
+
+ switch (ccf->debug_points) {
+
+ case NGX_DEBUG_POINTS_STOP:
+ raise(SIGSTOP);
+ break;
+
+ case NGX_DEBUG_POINTS_ABORT:
+ ngx_abort();
+ }
+}
+
+
+ngx_int_t
+ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid)
+{
+ ngx_signal_t *sig;
+
+ for (sig = signals; sig->signo != 0; sig++) {
+ if (ngx_strcmp(name, sig->name) == 0) {
+ if (kill(pid, sig->signo) != -1) {
+ return 0;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "kill(%P, %d) failed", pid, sig->signo);
+ }
+ }
+
+ return 1;
+}
diff --git a/app/nginx/src/os/unix/ngx_process.h b/app/nginx/src/os/unix/ngx_process.h
new file mode 100644
index 0000000..7b5e8c0
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_process.h
@@ -0,0 +1,88 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PROCESS_H_INCLUDED_
+#define _NGX_PROCESS_H_INCLUDED_
+
+
+#include <ngx_setaffinity.h>
+#include <ngx_setproctitle.h>
+
+
+typedef pid_t ngx_pid_t;
+
+#define NGX_INVALID_PID -1
+
+typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data);
+
+typedef struct {
+ ngx_pid_t pid;
+ int status;
+ ngx_socket_t channel[2];
+
+ ngx_spawn_proc_pt proc;
+ void *data;
+ char *name;
+
+ unsigned respawn:1;
+ unsigned just_spawn:1;
+ unsigned detached:1;
+ unsigned exiting:1;
+ unsigned exited:1;
+} ngx_process_t;
+
+
+typedef struct {
+ char *path;
+ char *name;
+ char *const *argv;
+ char *const *envp;
+} ngx_exec_ctx_t;
+
+
+#define NGX_MAX_PROCESSES 1024
+
+#define NGX_PROCESS_NORESPAWN -1
+#define NGX_PROCESS_JUST_SPAWN -2
+#define NGX_PROCESS_RESPAWN -3
+#define NGX_PROCESS_JUST_RESPAWN -4
+#define NGX_PROCESS_DETACHED -5
+
+
+#define ngx_getpid getpid
+
+#ifndef ngx_log_pid
+#define ngx_log_pid ngx_pid
+#endif
+
+
+ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle,
+ ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn);
+ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx);
+ngx_int_t ngx_init_signals(ngx_log_t *log);
+void ngx_debug_point(void);
+
+
+#if (NGX_HAVE_SCHED_YIELD)
+#define ngx_sched_yield() sched_yield()
+#else
+#define ngx_sched_yield() usleep(1)
+#endif
+
+
+extern int ngx_argc;
+extern char **ngx_argv;
+extern char **ngx_os_argv;
+
+extern ngx_pid_t ngx_pid;
+extern ngx_socket_t ngx_channel;
+extern ngx_int_t ngx_process_slot;
+extern ngx_int_t ngx_last_process;
+extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
+
+
+#endif /* _NGX_PROCESS_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_process_cycle.c b/app/nginx/src/os/unix/ngx_process_cycle.c
new file mode 100644
index 0000000..1710ea8
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_process_cycle.c
@@ -0,0 +1,1196 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_channel.h>
+
+
+static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n,
+ ngx_int_t type);
+static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle,
+ ngx_uint_t respawn);
+static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch);
+static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
+static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle);
+static void ngx_master_process_exit(ngx_cycle_t *cycle);
+static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
+static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker);
+static void ngx_worker_process_exit(ngx_cycle_t *cycle);
+static void ngx_channel_handler(ngx_event_t *ev);
+static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data);
+static void ngx_cache_manager_process_handler(ngx_event_t *ev);
+static void ngx_cache_loader_process_handler(ngx_event_t *ev);
+
+
+ngx_uint_t ngx_process;
+ngx_uint_t ngx_worker;
+ngx_pid_t ngx_pid;
+
+sig_atomic_t ngx_reap;
+sig_atomic_t ngx_sigio;
+sig_atomic_t ngx_sigalrm;
+sig_atomic_t ngx_terminate;
+sig_atomic_t ngx_quit;
+sig_atomic_t ngx_debug_quit;
+ngx_uint_t ngx_exiting;
+sig_atomic_t ngx_reconfigure;
+sig_atomic_t ngx_reopen;
+
+sig_atomic_t ngx_change_binary;
+ngx_pid_t ngx_new_binary;
+ngx_uint_t ngx_inherited;
+ngx_uint_t ngx_daemonized;
+
+sig_atomic_t ngx_noaccept;
+ngx_uint_t ngx_noaccepting;
+ngx_uint_t ngx_restart;
+
+
+static u_char master_process[] = "master process";
+
+
+static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = {
+ ngx_cache_manager_process_handler, "cache manager process", 0
+};
+
+static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = {
+ ngx_cache_loader_process_handler, "cache loader process", 60000
+};
+
+
+static ngx_cycle_t ngx_exit_cycle;
+static ngx_log_t ngx_exit_log;
+static ngx_open_file_t ngx_exit_log_file;
+
+
+void
+ngx_master_process_cycle(ngx_cycle_t *cycle)
+{
+ char *title;
+ u_char *p;
+ size_t size;
+ ngx_int_t i;
+ ngx_uint_t n, sigio;
+ sigset_t set;
+ struct itimerval itv;
+ ngx_uint_t live;
+ ngx_msec_t delay;
+ ngx_listening_t *ls;
+ ngx_core_conf_t *ccf;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
+ sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
+ sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
+ sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
+ sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
+ sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
+
+ if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "sigprocmask() failed");
+ }
+
+ sigemptyset(&set);
+
+
+ size = sizeof(master_process);
+
+ for (i = 0; i < ngx_argc; i++) {
+ size += ngx_strlen(ngx_argv[i]) + 1;
+ }
+
+ title = ngx_pnalloc(cycle->pool, size);
+ if (title == NULL) {
+ /* fatal */
+ exit(2);
+ }
+
+ p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
+ for (i = 0; i < ngx_argc; i++) {
+ *p++ = ' ';
+ p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
+ }
+
+ ngx_setproctitle(title);
+
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ ngx_start_worker_processes(cycle, ccf->worker_processes,
+ NGX_PROCESS_RESPAWN);
+ ngx_start_cache_manager_processes(cycle, 0);
+
+ ngx_new_binary = 0;
+ delay = 0;
+ sigio = 0;
+ live = 1;
+
+ for ( ;; ) {
+ if (delay) {
+ if (ngx_sigalrm) {
+ sigio = 0;
+ delay *= 2;
+ ngx_sigalrm = 0;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "termination cycle: %M", delay);
+
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 0;
+ itv.it_value.tv_sec = delay / 1000;
+ itv.it_value.tv_usec = (delay % 1000 ) * 1000;
+
+ if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "setitimer() failed");
+ }
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");
+
+ sigsuspend(&set);
+
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "wake up, sigio %i", sigio);
+
+ if (ngx_reap) {
+ ngx_reap = 0;
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
+
+ live = ngx_reap_children(cycle);
+ }
+
+ if (!live && (ngx_terminate || ngx_quit)) {
+ ngx_master_process_exit(cycle);
+ }
+
+ if (ngx_terminate) {
+ if (delay == 0) {
+ delay = 50;
+ }
+
+ if (sigio) {
+ sigio--;
+ continue;
+ }
+
+ sigio = ccf->worker_processes + 2 /* cache processes */;
+
+ if (delay > 1000) {
+ ngx_signal_worker_processes(cycle, SIGKILL);
+ } else {
+ ngx_signal_worker_processes(cycle,
+ ngx_signal_value(NGX_TERMINATE_SIGNAL));
+ }
+
+ continue;
+ }
+
+ if (ngx_quit) {
+ ngx_signal_worker_processes(cycle,
+ ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
+
+ ls = cycle->listening.elts;
+ for (n = 0; n < cycle->listening.nelts; n++) {
+ if (ngx_close_socket(ls[n].fd) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[n].addr_text);
+ }
+ }
+ cycle->listening.nelts = 0;
+
+ continue;
+ }
+
+ if (ngx_reconfigure) {
+ ngx_reconfigure = 0;
+
+ if (ngx_new_binary) {
+ ngx_start_worker_processes(cycle, ccf->worker_processes,
+ NGX_PROCESS_RESPAWN);
+ ngx_start_cache_manager_processes(cycle, 0);
+ ngx_noaccepting = 0;
+
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
+
+ cycle = ngx_init_cycle(cycle);
+ if (cycle == NULL) {
+ cycle = (ngx_cycle_t *) ngx_cycle;
+ continue;
+ }
+
+ ngx_cycle = cycle;
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_core_module);
+ ngx_start_worker_processes(cycle, ccf->worker_processes,
+ NGX_PROCESS_JUST_RESPAWN);
+ ngx_start_cache_manager_processes(cycle, 1);
+
+ /* allow new processes to start */
+ ngx_msleep(100);
+
+ live = 1;
+ ngx_signal_worker_processes(cycle,
+ ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
+ }
+
+ if (ngx_restart) {
+ ngx_restart = 0;
+ ngx_start_worker_processes(cycle, ccf->worker_processes,
+ NGX_PROCESS_RESPAWN);
+ ngx_start_cache_manager_processes(cycle, 0);
+ live = 1;
+ }
+
+ if (ngx_reopen) {
+ ngx_reopen = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
+ ngx_reopen_files(cycle, ccf->user);
+ ngx_signal_worker_processes(cycle,
+ ngx_signal_value(NGX_REOPEN_SIGNAL));
+ }
+
+ if (ngx_change_binary) {
+ ngx_change_binary = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
+ ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
+ }
+
+ if (ngx_noaccept) {
+ ngx_noaccept = 0;
+ ngx_noaccepting = 1;
+ ngx_signal_worker_processes(cycle,
+ ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
+ }
+ }
+}
+
+
+void
+ngx_single_process_cycle(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+
+ if (ngx_set_environment(cycle, NULL) == NULL) {
+ /* fatal */
+ exit(2);
+ }
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->init_process) {
+ if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {
+ /* fatal */
+ exit(2);
+ }
+ }
+ }
+
+ for ( ;; ) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
+
+ ngx_process_events_and_timers(cycle);
+
+ if (ngx_terminate || ngx_quit) {
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->exit_process) {
+ cycle->modules[i]->exit_process(cycle);
+ }
+ }
+
+ ngx_master_process_exit(cycle);
+ }
+
+ if (ngx_reconfigure) {
+ ngx_reconfigure = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
+
+ cycle = ngx_init_cycle(cycle);
+ if (cycle == NULL) {
+ cycle = (ngx_cycle_t *) ngx_cycle;
+ continue;
+ }
+
+ ngx_cycle = cycle;
+ }
+
+ if (ngx_reopen) {
+ ngx_reopen = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
+ ngx_reopen_files(cycle, (ngx_uid_t) -1);
+ }
+ }
+}
+
+
+static void
+ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
+{
+ ngx_int_t i;
+ ngx_channel_t ch;
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
+
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
+ ch.command = NGX_CMD_OPEN_CHANNEL;
+
+ for (i = 0; i < n; i++) {
+
+ ngx_spawn_process(cycle, ngx_worker_process_cycle,
+ (void *) (intptr_t) i, "worker process", type);
+
+ ch.pid = ngx_processes[ngx_process_slot].pid;
+ ch.slot = ngx_process_slot;
+ ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+ ngx_pass_open_channel(cycle, &ch);
+ }
+}
+
+
+static void
+ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn)
+{
+ ngx_uint_t i, manager, loader;
+ ngx_path_t **path;
+ ngx_channel_t ch;
+
+ manager = 0;
+ loader = 0;
+
+ path = ngx_cycle->paths.elts;
+ for (i = 0; i < ngx_cycle->paths.nelts; i++) {
+
+ if (path[i]->manager) {
+ manager = 1;
+ }
+
+ if (path[i]->loader) {
+ loader = 1;
+ }
+ }
+
+ if (manager == 0) {
+ return;
+ }
+
+ ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
+ &ngx_cache_manager_ctx, "cache manager process",
+ respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);
+
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
+ ch.command = NGX_CMD_OPEN_CHANNEL;
+ ch.pid = ngx_processes[ngx_process_slot].pid;
+ ch.slot = ngx_process_slot;
+ ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+ ngx_pass_open_channel(cycle, &ch);
+
+ if (loader == 0) {
+ return;
+ }
+
+ ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
+ &ngx_cache_loader_ctx, "cache loader process",
+ respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);
+
+ ch.command = NGX_CMD_OPEN_CHANNEL;
+ ch.pid = ngx_processes[ngx_process_slot].pid;
+ ch.slot = ngx_process_slot;
+ ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+ ngx_pass_open_channel(cycle, &ch);
+}
+
+
+static void
+ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch)
+{
+ ngx_int_t i;
+
+ for (i = 0; i < ngx_last_process; i++) {
+
+ if (i == ngx_process_slot
+ || ngx_processes[i].pid == -1
+ || ngx_processes[i].channel[0] == -1)
+ {
+ continue;
+ }
+
+ ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "pass channel s:%i pid:%P fd:%d to s:%i pid:%P fd:%d",
+ ch->slot, ch->pid, ch->fd,
+ i, ngx_processes[i].pid,
+ ngx_processes[i].channel[0]);
+
+ /* TODO: NGX_AGAIN */
+
+ ngx_write_channel(ngx_processes[i].channel[0],
+ ch, sizeof(ngx_channel_t), cycle->log);
+ }
+}
+
+
+static void
+ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo)
+{
+ ngx_int_t i;
+ ngx_err_t err;
+ ngx_channel_t ch;
+
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
+#if (NGX_BROKEN_SCM_RIGHTS)
+
+ ch.command = 0;
+
+#else
+
+ switch (signo) {
+
+ case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
+ ch.command = NGX_CMD_QUIT;
+ break;
+
+ case ngx_signal_value(NGX_TERMINATE_SIGNAL):
+ ch.command = NGX_CMD_TERMINATE;
+ break;
+
+ case ngx_signal_value(NGX_REOPEN_SIGNAL):
+ ch.command = NGX_CMD_REOPEN;
+ break;
+
+ default:
+ ch.command = 0;
+ }
+
+#endif
+
+ ch.fd = -1;
+
+
+ for (i = 0; i < ngx_last_process; i++) {
+
+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "child: %i %P e:%d t:%d d:%d r:%d j:%d",
+ i,
+ ngx_processes[i].pid,
+ ngx_processes[i].exiting,
+ ngx_processes[i].exited,
+ ngx_processes[i].detached,
+ ngx_processes[i].respawn,
+ ngx_processes[i].just_spawn);
+
+ if (ngx_processes[i].detached || ngx_processes[i].pid == -1) {
+ continue;
+ }
+
+ if (ngx_processes[i].just_spawn) {
+ ngx_processes[i].just_spawn = 0;
+ continue;
+ }
+
+ if (ngx_processes[i].exiting
+ && signo == ngx_signal_value(NGX_SHUTDOWN_SIGNAL))
+ {
+ continue;
+ }
+
+ if (ch.command) {
+ if (ngx_write_channel(ngx_processes[i].channel[0],
+ &ch, sizeof(ngx_channel_t), cycle->log)
+ == NGX_OK)
+ {
+ if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) {
+ ngx_processes[i].exiting = 1;
+ }
+
+ continue;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "kill (%P, %d)", ngx_processes[i].pid, signo);
+
+ if (kill(ngx_processes[i].pid, signo) == -1) {
+ err = ngx_errno;
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "kill(%P, %d) failed", ngx_processes[i].pid, signo);
+
+ if (err == NGX_ESRCH) {
+ ngx_processes[i].exited = 1;
+ ngx_processes[i].exiting = 0;
+ ngx_reap = 1;
+ }
+
+ continue;
+ }
+
+ if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) {
+ ngx_processes[i].exiting = 1;
+ }
+ }
+}
+
+
+static ngx_uint_t
+ngx_reap_children(ngx_cycle_t *cycle)
+{
+ ngx_int_t i, n;
+ ngx_uint_t live;
+ ngx_channel_t ch;
+ ngx_core_conf_t *ccf;
+
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
+ ch.command = NGX_CMD_CLOSE_CHANNEL;
+ ch.fd = -1;
+
+ live = 0;
+ for (i = 0; i < ngx_last_process; i++) {
+
+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "child: %i %P e:%d t:%d d:%d r:%d j:%d",
+ i,
+ ngx_processes[i].pid,
+ ngx_processes[i].exiting,
+ ngx_processes[i].exited,
+ ngx_processes[i].detached,
+ ngx_processes[i].respawn,
+ ngx_processes[i].just_spawn);
+
+ if (ngx_processes[i].pid == -1) {
+ continue;
+ }
+
+ if (ngx_processes[i].exited) {
+
+ if (!ngx_processes[i].detached) {
+ ngx_close_channel(ngx_processes[i].channel, cycle->log);
+
+ ngx_processes[i].channel[0] = -1;
+ ngx_processes[i].channel[1] = -1;
+
+ ch.pid = ngx_processes[i].pid;
+ ch.slot = i;
+
+ for (n = 0; n < ngx_last_process; n++) {
+ if (ngx_processes[n].exited
+ || ngx_processes[n].pid == -1
+ || ngx_processes[n].channel[0] == -1)
+ {
+ continue;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "pass close channel s:%i pid:%P to:%P",
+ ch.slot, ch.pid, ngx_processes[n].pid);
+
+ /* TODO: NGX_AGAIN */
+
+ ngx_write_channel(ngx_processes[n].channel[0],
+ &ch, sizeof(ngx_channel_t), cycle->log);
+ }
+ }
+
+ if (ngx_processes[i].respawn
+ && !ngx_processes[i].exiting
+ && !ngx_terminate
+ && !ngx_quit)
+ {
+ if (ngx_spawn_process(cycle, ngx_processes[i].proc,
+ ngx_processes[i].data,
+ ngx_processes[i].name, i)
+ == NGX_INVALID_PID)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "could not respawn %s",
+ ngx_processes[i].name);
+ continue;
+ }
+
+
+ ch.command = NGX_CMD_OPEN_CHANNEL;
+ ch.pid = ngx_processes[ngx_process_slot].pid;
+ ch.slot = ngx_process_slot;
+ ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+ ngx_pass_open_channel(cycle, &ch);
+
+ live = 1;
+
+ continue;
+ }
+
+ if (ngx_processes[i].pid == ngx_new_binary) {
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_core_module);
+
+ if (ngx_rename_file((char *) ccf->oldpid.data,
+ (char *) ccf->pid.data)
+ == NGX_FILE_ERROR)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_rename_file_n " %s back to %s failed "
+ "after the new binary process \"%s\" exited",
+ ccf->oldpid.data, ccf->pid.data, ngx_argv[0]);
+ }
+
+ ngx_new_binary = 0;
+ if (ngx_noaccepting) {
+ ngx_restart = 1;
+ ngx_noaccepting = 0;
+ }
+ }
+
+ if (i == ngx_last_process - 1) {
+ ngx_last_process--;
+
+ } else {
+ ngx_processes[i].pid = -1;
+ }
+
+ } else if (ngx_processes[i].exiting || !ngx_processes[i].detached) {
+ live = 1;
+ }
+ }
+
+ return live;
+}
+
+
+static void
+ngx_master_process_exit(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+
+ ngx_delete_pidfile(cycle);
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit");
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->exit_master) {
+ cycle->modules[i]->exit_master(cycle);
+ }
+ }
+
+ ngx_close_listening_sockets(cycle);
+
+ /*
+ * Copy ngx_cycle->log related data to the special static exit cycle,
+ * log, and log file structures enough to allow a signal handler to log.
+ * The handler may be called when standard ngx_cycle->log allocated from
+ * ngx_cycle->pool is already destroyed.
+ */
+
+
+ ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log);
+
+ ngx_exit_log_file.fd = ngx_exit_log.file->fd;
+ ngx_exit_log.file = &ngx_exit_log_file;
+ ngx_exit_log.next = NULL;
+ ngx_exit_log.writer = NULL;
+
+ ngx_exit_cycle.log = &ngx_exit_log;
+ ngx_exit_cycle.files = ngx_cycle->files;
+ ngx_exit_cycle.files_n = ngx_cycle->files_n;
+ ngx_cycle = &ngx_exit_cycle;
+
+ ngx_destroy_pool(cycle->pool);
+
+ exit(0);
+}
+
+
+static void
+ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
+{
+ ngx_int_t worker = (intptr_t) data;
+
+ ngx_process = NGX_PROCESS_WORKER;
+ ngx_worker = worker;
+
+ ngx_worker_process_init(cycle, worker);
+
+ ngx_setproctitle("worker process");
+
+ for ( ;; ) {
+
+ if (ngx_exiting) {
+ if (ngx_event_no_timers_left() == NGX_OK) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+ ngx_worker_process_exit(cycle);
+ }
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
+
+ ngx_process_events_and_timers(cycle);
+
+ if (ngx_terminate) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+ ngx_worker_process_exit(cycle);
+ }
+
+ if (ngx_quit) {
+ ngx_quit = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
+ "gracefully shutting down");
+ ngx_setproctitle("worker process is shutting down");
+
+ if (!ngx_exiting) {
+ ngx_exiting = 1;
+ ngx_set_shutdown_timer(cycle);
+ ngx_close_listening_sockets(cycle);
+ ngx_close_idle_connections(cycle);
+ }
+ }
+
+ if (ngx_reopen) {
+ ngx_reopen = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
+ ngx_reopen_files(cycle, -1);
+ }
+ }
+}
+
+
+static void
+ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
+{
+ sigset_t set;
+ ngx_int_t n;
+ ngx_time_t *tp;
+ ngx_uint_t i;
+ ngx_cpuset_t *cpu_affinity;
+ struct rlimit rlmt;
+ ngx_core_conf_t *ccf;
+ ngx_listening_t *ls;
+
+ if (ngx_set_environment(cycle, NULL) == NULL) {
+ /* fatal */
+ exit(2);
+ }
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ if (worker >= 0 && ccf->priority != 0) {
+ if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "setpriority(%d) failed", ccf->priority);
+ }
+ }
+
+ if (ccf->rlimit_nofile != NGX_CONF_UNSET) {
+ rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile;
+ rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile;
+
+ if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "setrlimit(RLIMIT_NOFILE, %i) failed",
+ ccf->rlimit_nofile);
+ }
+ }
+
+ if (ccf->rlimit_core != NGX_CONF_UNSET) {
+ rlmt.rlim_cur = (rlim_t) ccf->rlimit_core;
+ rlmt.rlim_max = (rlim_t) ccf->rlimit_core;
+
+ if (setrlimit(RLIMIT_CORE, &rlmt) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "setrlimit(RLIMIT_CORE, %O) failed",
+ ccf->rlimit_core);
+ }
+ }
+
+ if (geteuid() == 0) {
+ if (setgid(ccf->group) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "setgid(%d) failed", ccf->group);
+ /* fatal */
+ exit(2);
+ }
+
+ if (initgroups(ccf->username, ccf->group) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "initgroups(%s, %d) failed",
+ ccf->username, ccf->group);
+ }
+
+ if (setuid(ccf->user) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "setuid(%d) failed", ccf->user);
+ /* fatal */
+ exit(2);
+ }
+ }
+
+ if (worker >= 0) {
+ cpu_affinity = ngx_get_cpu_affinity(worker);
+
+ if (cpu_affinity) {
+ ngx_setaffinity(cpu_affinity, cycle->log);
+ }
+ }
+
+#if (NGX_HAVE_PR_SET_DUMPABLE)
+
+ /* allow coredump after setuid() in Linux 2.4.x */
+
+ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "prctl(PR_SET_DUMPABLE) failed");
+ }
+
+#endif
+
+ if (ccf->working_directory.len) {
+ if (chdir((char *) ccf->working_directory.data) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "chdir(\"%s\") failed", ccf->working_directory.data);
+ /* fatal */
+ exit(2);
+ }
+ }
+
+ sigemptyset(&set);
+
+ if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "sigprocmask() failed");
+ }
+
+ tp = ngx_timeofday();
+ srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec);
+
+ /*
+ * disable deleting previous events for the listening sockets because
+ * in the worker processes there are no events at all at this point
+ */
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+ ls[i].previous = NULL;
+ }
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->init_process) {
+ if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {
+ /* fatal */
+ exit(2);
+ }
+ }
+ }
+
+ for (n = 0; n < ngx_last_process; n++) {
+
+ if (ngx_processes[n].pid == -1) {
+ continue;
+ }
+
+ if (n == ngx_process_slot) {
+ continue;
+ }
+
+ if (ngx_processes[n].channel[1] == -1) {
+ continue;
+ }
+
+ if (close(ngx_processes[n].channel[1]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close() channel failed");
+ }
+ }
+
+ if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close() channel failed");
+ }
+
+#if 0
+ ngx_last_process = 0;
+#endif
+
+ if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
+ ngx_channel_handler)
+ == NGX_ERROR)
+ {
+ /* fatal */
+ exit(2);
+ }
+}
+
+
+static void
+ngx_worker_process_exit(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_connection_t *c;
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->exit_process) {
+ cycle->modules[i]->exit_process(cycle);
+ }
+ }
+
+ if (ngx_exiting) {
+ c = cycle->connections;
+ for (i = 0; i < cycle->connection_n; i++) {
+ if (c[i].fd != -1
+ && c[i].read
+ && !c[i].read->accept
+ && !c[i].read->channel
+ && !c[i].read->resolver)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "*%uA open socket #%d left in connection %ui",
+ c[i].number, c[i].fd, i);
+ ngx_debug_quit = 1;
+ }
+ }
+
+ if (ngx_debug_quit) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
+ ngx_debug_point();
+ }
+ }
+
+ /*
+ * Copy ngx_cycle->log related data to the special static exit cycle,
+ * log, and log file structures enough to allow a signal handler to log.
+ * The handler may be called when standard ngx_cycle->log allocated from
+ * ngx_cycle->pool is already destroyed.
+ */
+
+ ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log);
+
+ ngx_exit_log_file.fd = ngx_exit_log.file->fd;
+ ngx_exit_log.file = &ngx_exit_log_file;
+ ngx_exit_log.next = NULL;
+ ngx_exit_log.writer = NULL;
+
+ ngx_exit_cycle.log = &ngx_exit_log;
+ ngx_exit_cycle.files = ngx_cycle->files;
+ ngx_exit_cycle.files_n = ngx_cycle->files_n;
+ ngx_cycle = &ngx_exit_cycle;
+
+ ngx_destroy_pool(cycle->pool);
+
+ ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, "exit");
+
+ exit(0);
+}
+
+
+static void
+ngx_channel_handler(ngx_event_t *ev)
+{
+ ngx_int_t n;
+ ngx_channel_t ch;
+ ngx_connection_t *c;
+
+ if (ev->timedout) {
+ ev->timedout = 0;
+ return;
+ }
+
+ c = ev->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler");
+
+ for ( ;; ) {
+
+ n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
+
+ if (n == NGX_ERROR) {
+
+ if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+ ngx_del_conn(c, 0);
+ }
+
+ ngx_close_connection(c);
+ return;
+ }
+
+ if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
+ if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+ return;
+ }
+ }
+
+ if (n == NGX_AGAIN) {
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "channel command: %ui", ch.command);
+
+ switch (ch.command) {
+
+ case NGX_CMD_QUIT:
+ ngx_quit = 1;
+ break;
+
+ case NGX_CMD_TERMINATE:
+ ngx_terminate = 1;
+ break;
+
+ case NGX_CMD_REOPEN:
+ ngx_reopen = 1;
+ break;
+
+ case NGX_CMD_OPEN_CHANNEL:
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "get channel s:%i pid:%P fd:%d",
+ ch.slot, ch.pid, ch.fd);
+
+ ngx_processes[ch.slot].pid = ch.pid;
+ ngx_processes[ch.slot].channel[0] = ch.fd;
+ break;
+
+ case NGX_CMD_CLOSE_CHANNEL:
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "close channel s:%i pid:%P our:%P fd:%d",
+ ch.slot, ch.pid, ngx_processes[ch.slot].pid,
+ ngx_processes[ch.slot].channel[0]);
+
+ if (close(ngx_processes[ch.slot].channel[0]) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+ "close() channel failed");
+ }
+
+ ngx_processes[ch.slot].channel[0] = -1;
+ break;
+ }
+ }
+}
+
+
+static void
+ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
+{
+ ngx_cache_manager_ctx_t *ctx = data;
+
+ void *ident[4];
+ ngx_event_t ev;
+
+ /*
+ * Set correct process type since closing listening Unix domain socket
+ * in a master process also removes the Unix domain socket file.
+ */
+ ngx_process = NGX_PROCESS_HELPER;
+
+ ngx_close_listening_sockets(cycle);
+
+ /* Set a moderate number of connections for a helper process. */
+ cycle->connection_n = 512;
+
+ ngx_worker_process_init(cycle, -1);
+
+ ngx_memzero(&ev, sizeof(ngx_event_t));
+ ev.handler = ctx->handler;
+ ev.data = ident;
+ ev.log = cycle->log;
+ ident[3] = (void *) -1;
+
+ ngx_use_accept_mutex = 0;
+
+ ngx_setproctitle(ctx->name);
+
+ ngx_add_timer(&ev, ctx->delay);
+
+ for ( ;; ) {
+
+ if (ngx_terminate || ngx_quit) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+ exit(0);
+ }
+
+ if (ngx_reopen) {
+ ngx_reopen = 0;
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
+ ngx_reopen_files(cycle, -1);
+ }
+
+ ngx_process_events_and_timers(cycle);
+ }
+}
+
+
+static void
+ngx_cache_manager_process_handler(ngx_event_t *ev)
+{
+ ngx_uint_t i;
+ ngx_msec_t next, n;
+ ngx_path_t **path;
+
+ next = 60 * 60 * 1000;
+
+ path = ngx_cycle->paths.elts;
+ for (i = 0; i < ngx_cycle->paths.nelts; i++) {
+
+ if (path[i]->manager) {
+ n = path[i]->manager(path[i]->data);
+
+ next = (n <= next) ? n : next;
+
+ ngx_time_update();
+ }
+ }
+
+ if (next == 0) {
+ next = 1;
+ }
+
+ ngx_add_timer(ev, next);
+}
+
+
+static void
+ngx_cache_loader_process_handler(ngx_event_t *ev)
+{
+ ngx_uint_t i;
+ ngx_path_t **path;
+ ngx_cycle_t *cycle;
+
+ cycle = (ngx_cycle_t *) ngx_cycle;
+
+ path = cycle->paths.elts;
+ for (i = 0; i < cycle->paths.nelts; i++) {
+
+ if (ngx_terminate || ngx_quit) {
+ break;
+ }
+
+ if (path[i]->loader) {
+ path[i]->loader(path[i]->data);
+ ngx_time_update();
+ }
+ }
+
+ exit(0);
+}
diff --git a/app/nginx/src/os/unix/ngx_process_cycle.h b/app/nginx/src/os/unix/ngx_process_cycle.h
new file mode 100644
index 0000000..69495d5
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_process_cycle.h
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_
+#define _NGX_PROCESS_CYCLE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_CMD_OPEN_CHANNEL 1
+#define NGX_CMD_CLOSE_CHANNEL 2
+#define NGX_CMD_QUIT 3
+#define NGX_CMD_TERMINATE 4
+#define NGX_CMD_REOPEN 5
+
+
+#define NGX_PROCESS_SINGLE 0
+#define NGX_PROCESS_MASTER 1
+#define NGX_PROCESS_SIGNALLER 2
+#define NGX_PROCESS_WORKER 3
+#define NGX_PROCESS_HELPER 4
+
+
+typedef struct {
+ ngx_event_handler_pt handler;
+ char *name;
+ ngx_msec_t delay;
+} ngx_cache_manager_ctx_t;
+
+
+void ngx_master_process_cycle(ngx_cycle_t *cycle);
+void ngx_single_process_cycle(ngx_cycle_t *cycle);
+
+
+extern ngx_uint_t ngx_process;
+extern ngx_uint_t ngx_worker;
+extern ngx_pid_t ngx_pid;
+extern ngx_pid_t ngx_new_binary;
+extern ngx_uint_t ngx_inherited;
+extern ngx_uint_t ngx_daemonized;
+extern ngx_uint_t ngx_exiting;
+
+extern sig_atomic_t ngx_reap;
+extern sig_atomic_t ngx_sigio;
+extern sig_atomic_t ngx_sigalrm;
+extern sig_atomic_t ngx_quit;
+extern sig_atomic_t ngx_debug_quit;
+extern sig_atomic_t ngx_terminate;
+extern sig_atomic_t ngx_noaccept;
+extern sig_atomic_t ngx_reconfigure;
+extern sig_atomic_t ngx_reopen;
+extern sig_atomic_t ngx_change_binary;
+
+
+#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_readv_chain.c b/app/nginx/src/os/unix/ngx_readv_chain.c
new file mode 100644
index 0000000..454cfdc
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_readv_chain.c
@@ -0,0 +1,214 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
+{
+ u_char *prev;
+ ssize_t n, size;
+ ngx_err_t err;
+ ngx_array_t vec;
+ ngx_event_t *rev;
+ struct iovec *iov, iovs[NGX_IOVS_PREALLOCATE];
+
+ rev = c->read;
+
+#if (NGX_HAVE_KQUEUE)
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "readv: eof:%d, avail:%d, err:%d",
+ rev->pending_eof, rev->available, rev->kq_errno);
+
+ if (rev->available == 0) {
+ if (rev->pending_eof) {
+ rev->ready = 0;
+ rev->eof = 1;
+
+ ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
+ "kevent() reported about an closed connection");
+
+ if (rev->kq_errno) {
+ rev->error = 1;
+ ngx_set_socket_errno(rev->kq_errno);
+ return NGX_ERROR;
+ }
+
+ return 0;
+
+ } else {
+ return NGX_AGAIN;
+ }
+ }
+ }
+
+#endif
+
+#if (NGX_HAVE_EPOLLRDHUP)
+
+ if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "readv: eof:%d, avail:%d",
+ rev->pending_eof, rev->available);
+
+ if (!rev->available && !rev->pending_eof) {
+ return NGX_AGAIN;
+ }
+ }
+
+#endif
+
+ prev = NULL;
+ iov = NULL;
+ size = 0;
+
+ vec.elts = iovs;
+ vec.nelts = 0;
+ vec.size = sizeof(struct iovec);
+ vec.nalloc = NGX_IOVS_PREALLOCATE;
+ vec.pool = c->pool;
+
+ /* coalesce the neighbouring bufs */
+
+ while (chain) {
+ n = chain->buf->end - chain->buf->last;
+
+ if (limit) {
+ if (size >= limit) {
+ break;
+ }
+
+ if (size + n > limit) {
+ n = (ssize_t) (limit - size);
+ }
+ }
+
+ if (prev == chain->buf->last) {
+ iov->iov_len += n;
+
+ } else {
+ if (vec.nelts >= IOV_MAX) {
+ break;
+ }
+
+ iov = ngx_array_push(&vec);
+ if (iov == NULL) {
+ return NGX_ERROR;
+ }
+
+ iov->iov_base = (void *) chain->buf->last;
+ iov->iov_len = n;
+ }
+
+ size += n;
+ prev = chain->buf->end;
+ chain = chain->next;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "readv: %ui, last:%uz", vec.nelts, iov->iov_len);
+
+ do {
+ n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);
+
+ if (n == 0) {
+ rev->ready = 0;
+ rev->eof = 1;
+
+#if (NGX_HAVE_KQUEUE)
+
+ /*
+ * on FreeBSD readv() may return 0 on closed socket
+ * even if kqueue reported about available data
+ */
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ rev->available = 0;
+ }
+
+#endif
+
+ return 0;
+ }
+
+ if (n > 0) {
+
+#if (NGX_HAVE_KQUEUE)
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ rev->available -= n;
+
+ /*
+ * rev->available may be negative here because some additional
+ * bytes may be received between kevent() and readv()
+ */
+
+ if (rev->available <= 0) {
+ if (!rev->pending_eof) {
+ rev->ready = 0;
+ }
+
+ rev->available = 0;
+ }
+
+ return n;
+ }
+
+#endif
+
+#if (NGX_HAVE_EPOLLRDHUP)
+
+ if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
+ && ngx_use_epoll_rdhup)
+ {
+ if (n < size) {
+ if (!rev->pending_eof) {
+ rev->ready = 0;
+ }
+
+ rev->available = 0;
+ }
+
+ return n;
+ }
+
+#endif
+
+ if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
+ rev->ready = 0;
+ }
+
+ return n;
+ }
+
+ err = ngx_socket_errno;
+
+ if (err == NGX_EAGAIN || err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "readv() not ready");
+ n = NGX_AGAIN;
+
+ } else {
+ n = ngx_connection_error(c, err, "readv() failed");
+ break;
+ }
+
+ } while (err == NGX_EINTR);
+
+ rev->ready = 0;
+
+ if (n == NGX_ERROR) {
+ c->read->error = 1;
+ }
+
+ return n;
+}
diff --git a/app/nginx/src/os/unix/ngx_recv.c b/app/nginx/src/os/unix/ngx_recv.c
new file mode 100644
index 0000000..c85fd45
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_recv.c
@@ -0,0 +1,167 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_event_t *rev;
+
+ rev = c->read;
+
+#if (NGX_HAVE_KQUEUE)
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "recv: eof:%d, avail:%d, err:%d",
+ rev->pending_eof, rev->available, rev->kq_errno);
+
+ if (rev->available == 0) {
+ if (rev->pending_eof) {
+ rev->ready = 0;
+ rev->eof = 1;
+
+ if (rev->kq_errno) {
+ rev->error = 1;
+ ngx_set_socket_errno(rev->kq_errno);
+
+ return ngx_connection_error(c, rev->kq_errno,
+ "kevent() reported about an closed connection");
+ }
+
+ return 0;
+
+ } else {
+ rev->ready = 0;
+ return NGX_AGAIN;
+ }
+ }
+ }
+
+#endif
+
+#if (NGX_HAVE_EPOLLRDHUP)
+
+ if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "recv: eof:%d, avail:%d",
+ rev->pending_eof, rev->available);
+
+ if (!rev->available && !rev->pending_eof) {
+ rev->ready = 0;
+ return NGX_AGAIN;
+ }
+ }
+
+#endif
+
+ do {
+ n = recv(c->fd, buf, size, 0);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "recv: fd:%d %z of %uz", c->fd, n, size);
+
+ if (n == 0) {
+ rev->ready = 0;
+ rev->eof = 1;
+
+#if (NGX_HAVE_KQUEUE)
+
+ /*
+ * on FreeBSD recv() may return 0 on closed socket
+ * even if kqueue reported about available data
+ */
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ rev->available = 0;
+ }
+
+#endif
+
+ return 0;
+ }
+
+ if (n > 0) {
+
+#if (NGX_HAVE_KQUEUE)
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ rev->available -= n;
+
+ /*
+ * rev->available may be negative here because some additional
+ * bytes may be received between kevent() and recv()
+ */
+
+ if (rev->available <= 0) {
+ if (!rev->pending_eof) {
+ rev->ready = 0;
+ }
+
+ rev->available = 0;
+ }
+
+ return n;
+ }
+
+#endif
+
+#if (NGX_HAVE_EPOLLRDHUP)
+
+ if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
+ && ngx_use_epoll_rdhup)
+ {
+ if ((size_t) n < size) {
+ if (!rev->pending_eof) {
+ rev->ready = 0;
+ }
+
+ rev->available = 0;
+ }
+
+ return n;
+ }
+
+#endif
+
+ if ((size_t) n < size
+ && !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
+ {
+ rev->ready = 0;
+ }
+
+ return n;
+ }
+
+ err = ngx_socket_errno;
+
+ if (err == NGX_EAGAIN || err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "recv() not ready");
+ n = NGX_AGAIN;
+
+ } else {
+ n = ngx_connection_error(c, err, "recv() failed");
+ break;
+ }
+
+ } while (err == NGX_EINTR);
+
+ rev->ready = 0;
+
+ if (n == NGX_ERROR) {
+ rev->error = 1;
+ }
+
+ return n;
+}
diff --git a/app/nginx/src/os/unix/ngx_send.c b/app/nginx/src/os/unix/ngx_send.c
new file mode 100644
index 0000000..61ea202
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_send.c
@@ -0,0 +1,73 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_event_t *wev;
+
+ wev = c->write;
+
+#if (NGX_HAVE_KQUEUE)
+
+ if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
+ (void) ngx_connection_error(c, wev->kq_errno,
+ "kevent() reported about an closed connection");
+ wev->error = 1;
+ return NGX_ERROR;
+ }
+
+#endif
+
+ for ( ;; ) {
+ n = send(c->fd, buf, size, 0);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "send: fd:%d %z of %uz", c->fd, n, size);
+
+ if (n > 0) {
+ if (n < (ssize_t) size) {
+ wev->ready = 0;
+ }
+
+ c->sent += n;
+
+ return n;
+ }
+
+ err = ngx_socket_errno;
+
+ if (n == 0) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, err, "send() returned zero");
+ wev->ready = 0;
+ return n;
+ }
+
+ if (err == NGX_EAGAIN || err == NGX_EINTR) {
+ wev->ready = 0;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "send() not ready");
+
+ if (err == NGX_EAGAIN) {
+ return NGX_AGAIN;
+ }
+
+ } else {
+ wev->error = 1;
+ (void) ngx_connection_error(c, err, "send() failed");
+ return NGX_ERROR;
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_setaffinity.c b/app/nginx/src/os/unix/ngx_setaffinity.c
new file mode 100644
index 0000000..34ec390
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_setaffinity.c
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_CPUSET_SETAFFINITY)
+
+void
+ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log)
+{
+ ngx_uint_t i;
+
+ for (i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, cpu_affinity)) {
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "cpuset_setaffinity(): using cpu #%ui", i);
+ }
+ }
+
+ if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
+ sizeof(cpuset_t), cpu_affinity) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "cpuset_setaffinity() failed");
+ }
+}
+
+#elif (NGX_HAVE_SCHED_SETAFFINITY)
+
+void
+ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log)
+{
+ ngx_uint_t i;
+
+ for (i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, cpu_affinity)) {
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "sched_setaffinity(): using cpu #%ui", i);
+ }
+ }
+
+ if (sched_setaffinity(0, sizeof(cpu_set_t), cpu_affinity) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sched_setaffinity() failed");
+ }
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_setaffinity.h b/app/nginx/src/os/unix/ngx_setaffinity.h
new file mode 100644
index 0000000..a4139ed
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_setaffinity.h
@@ -0,0 +1,37 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+#ifndef _NGX_SETAFFINITY_H_INCLUDED_
+#define _NGX_SETAFFINITY_H_INCLUDED_
+
+
+#if (NGX_HAVE_SCHED_SETAFFINITY || NGX_HAVE_CPUSET_SETAFFINITY)
+
+#define NGX_HAVE_CPU_AFFINITY 1
+
+#if (NGX_HAVE_SCHED_SETAFFINITY)
+
+typedef cpu_set_t ngx_cpuset_t;
+
+#elif (NGX_HAVE_CPUSET_SETAFFINITY)
+
+#include <sys/cpuset.h>
+
+typedef cpuset_t ngx_cpuset_t;
+
+#endif
+
+void ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log);
+
+#else
+
+#define ngx_setaffinity(cpu_affinity, log)
+
+typedef uint64_t ngx_cpuset_t;
+
+#endif
+
+
+#endif /* _NGX_SETAFFINITY_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_setproctitle.c b/app/nginx/src/os/unix/ngx_setproctitle.c
new file mode 100644
index 0000000..91afa51
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_setproctitle.c
@@ -0,0 +1,135 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_SETPROCTITLE_USES_ENV)
+
+/*
+ * To change the process title in Linux and Solaris we have to set argv[1]
+ * to NULL and to copy the title to the same place where the argv[0] points to.
+ * However, argv[0] may be too small to hold a new title. Fortunately, Linux
+ * and Solaris store argv[] and environ[] one after another. So we should
+ * ensure that is the continuous memory and then we allocate the new memory
+ * for environ[] and copy it. After this we could use the memory starting
+ * from argv[0] for our process title.
+ *
+ * The Solaris's standard /bin/ps does not show the changed process title.
+ * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps does not
+ * show a new title if its length less than the origin command line length.
+ * To avoid it we append to a new title the origin command line in the
+ * parenthesis.
+ */
+
+extern char **environ;
+
+static char *ngx_os_argv_last;
+
+ngx_int_t
+ngx_init_setproctitle(ngx_log_t *log)
+{
+ u_char *p;
+ size_t size;
+ ngx_uint_t i;
+
+ size = 0;
+
+ for (i = 0; environ[i]; i++) {
+ size += ngx_strlen(environ[i]) + 1;
+ }
+
+ p = ngx_alloc(size, log);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_os_argv_last = ngx_os_argv[0];
+
+ for (i = 0; ngx_os_argv[i]; i++) {
+ if (ngx_os_argv_last == ngx_os_argv[i]) {
+ ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1;
+ }
+ }
+
+ for (i = 0; environ[i]; i++) {
+ if (ngx_os_argv_last == environ[i]) {
+
+ size = ngx_strlen(environ[i]) + 1;
+ ngx_os_argv_last = environ[i] + size;
+
+ ngx_cpystrn(p, (u_char *) environ[i], size);
+ environ[i] = (char *) p;
+ p += size;
+ }
+ }
+
+ ngx_os_argv_last--;
+
+ return NGX_OK;
+}
+
+
+void
+ngx_setproctitle(char *title)
+{
+ u_char *p;
+
+#if (NGX_SOLARIS)
+
+ ngx_int_t i;
+ size_t size;
+
+#endif
+
+ ngx_os_argv[1] = NULL;
+
+ p = ngx_cpystrn((u_char *) ngx_os_argv[0], (u_char *) "nginx: ",
+ ngx_os_argv_last - ngx_os_argv[0]);
+
+ p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p);
+
+#if (NGX_SOLARIS)
+
+ size = 0;
+
+ for (i = 0; i < ngx_argc; i++) {
+ size += ngx_strlen(ngx_argv[i]) + 1;
+ }
+
+ if (size > (size_t) ((char *) p - ngx_os_argv[0])) {
+
+ /*
+ * ngx_setproctitle() is too rare operation so we use
+ * the non-optimized copies
+ */
+
+ p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p);
+
+ for (i = 0; i < ngx_argc; i++) {
+ p = ngx_cpystrn(p, (u_char *) ngx_argv[i],
+ ngx_os_argv_last - (char *) p);
+ p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p);
+ }
+
+ if (*(p - 1) == ' ') {
+ *(p - 1) = ')';
+ }
+ }
+
+#endif
+
+ if (ngx_os_argv_last - (char *) p) {
+ ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p);
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "setproctitle: \"%s\"", ngx_os_argv[0]);
+}
+
+#endif /* NGX_SETPROCTITLE_USES_ENV */
diff --git a/app/nginx/src/os/unix/ngx_setproctitle.h b/app/nginx/src/os/unix/ngx_setproctitle.h
new file mode 100644
index 0000000..c363662
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_setproctitle.h
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SETPROCTITLE_H_INCLUDED_
+#define _NGX_SETPROCTITLE_H_INCLUDED_
+
+
+#if (NGX_HAVE_SETPROCTITLE)
+
+/* FreeBSD, NetBSD, OpenBSD */
+
+#define ngx_init_setproctitle(log) NGX_OK
+#define ngx_setproctitle(title) setproctitle("%s", title)
+
+
+#else /* !NGX_HAVE_SETPROCTITLE */
+
+#if !defined NGX_SETPROCTITLE_USES_ENV
+
+#if (NGX_SOLARIS)
+
+#define NGX_SETPROCTITLE_USES_ENV 1
+#define NGX_SETPROCTITLE_PAD ' '
+
+ngx_int_t ngx_init_setproctitle(ngx_log_t *log);
+void ngx_setproctitle(char *title);
+
+#elif (NGX_LINUX) || (NGX_DARWIN)
+
+#define NGX_SETPROCTITLE_USES_ENV 1
+#define NGX_SETPROCTITLE_PAD '\0'
+
+ngx_int_t ngx_init_setproctitle(ngx_log_t *log);
+void ngx_setproctitle(char *title);
+
+#else
+
+#define ngx_init_setproctitle(log) NGX_OK
+#define ngx_setproctitle(title)
+
+#endif /* OSes */
+
+#endif /* NGX_SETPROCTITLE_USES_ENV */
+
+#endif /* NGX_HAVE_SETPROCTITLE */
+
+
+#endif /* _NGX_SETPROCTITLE_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_shmem.c b/app/nginx/src/os/unix/ngx_shmem.c
new file mode 100644
index 0000000..3ec7cbf
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_shmem.c
@@ -0,0 +1,126 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_MAP_ANON)
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+ shm->addr = (u_char *) mmap(NULL, shm->size,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_SHARED, -1, 0);
+
+ if (shm->addr == MAP_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+ if (munmap((void *) shm->addr, shm->size) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "munmap(%p, %uz) failed", shm->addr, shm->size);
+ }
+}
+
+#elif (NGX_HAVE_MAP_DEVZERO)
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+ ngx_fd_t fd;
+
+ fd = open("/dev/zero", O_RDWR);
+
+ if (fd == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "open(\"/dev/zero\") failed");
+ return NGX_ERROR;
+ }
+
+ shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0);
+
+ if (shm->addr == MAP_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "mmap(/dev/zero, MAP_SHARED, %uz) failed", shm->size);
+ }
+
+ if (close(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "close(\"/dev/zero\") failed");
+ }
+
+ return (shm->addr == MAP_FAILED) ? NGX_ERROR : NGX_OK;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+ if (munmap((void *) shm->addr, shm->size) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "munmap(%p, %uz) failed", shm->addr, shm->size);
+ }
+}
+
+#elif (NGX_HAVE_SYSVSHM)
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+ int id;
+
+ id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT));
+
+ if (id == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "shmget(%uz) failed", shm->size);
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, shm->log, 0, "shmget id: %d", id);
+
+ shm->addr = shmat(id, NULL, 0);
+
+ if (shm->addr == (void *) -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");
+ }
+
+ if (shmctl(id, IPC_RMID, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "shmctl(IPC_RMID) failed");
+ }
+
+ return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+ if (shmdt(shm->addr) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "shmdt(%p) failed", shm->addr);
+ }
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_shmem.h b/app/nginx/src/os/unix/ngx_shmem.h
new file mode 100644
index 0000000..566a7d3
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_shmem.h
@@ -0,0 +1,29 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SHMEM_H_INCLUDED_
+#define _NGX_SHMEM_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ u_char *addr;
+ size_t size;
+ ngx_str_t name;
+ ngx_log_t *log;
+ ngx_uint_t exists; /* unsigned exists:1; */
+} ngx_shm_t;
+
+
+ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
+void ngx_shm_free(ngx_shm_t *shm);
+
+
+#endif /* _NGX_SHMEM_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_socket.c b/app/nginx/src/os/unix/ngx_socket.c
new file mode 100644
index 0000000..3978f65
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_socket.c
@@ -0,0 +1,116 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * ioctl(FIONBIO) sets a non-blocking mode with the single syscall
+ * while fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state
+ * using fcntl(F_GETFL).
+ *
+ * ioctl() and fcntl() are syscalls at least in FreeBSD 2.x, Linux 2.2
+ * and Solaris 7.
+ *
+ * ioctl() in Linux 2.4 and 2.6 uses BKL, however, fcntl(F_SETFL) uses it too.
+ */
+
+
+#if (NGX_HAVE_FIONBIO)
+
+int
+ngx_nonblocking(ngx_socket_t s)
+{
+ int nb;
+
+ nb = 1;
+
+ return ioctl(s, FIONBIO, &nb);
+}
+
+
+int
+ngx_blocking(ngx_socket_t s)
+{
+ int nb;
+
+ nb = 0;
+
+ return ioctl(s, FIONBIO, &nb);
+}
+
+#endif
+
+
+#if (NGX_FREEBSD)
+
+int
+ngx_tcp_nopush(ngx_socket_t s)
+{
+ int tcp_nopush;
+
+ tcp_nopush = 1;
+
+ return setsockopt(s, IPPROTO_TCP, TCP_NOPUSH,
+ (const void *) &tcp_nopush, sizeof(int));
+}
+
+
+int
+ngx_tcp_push(ngx_socket_t s)
+{
+ int tcp_nopush;
+
+ tcp_nopush = 0;
+
+ return setsockopt(s, IPPROTO_TCP, TCP_NOPUSH,
+ (const void *) &tcp_nopush, sizeof(int));
+}
+
+#elif (NGX_LINUX)
+
+
+int
+ngx_tcp_nopush(ngx_socket_t s)
+{
+ int cork;
+
+ cork = 1;
+
+ return setsockopt(s, IPPROTO_TCP, TCP_CORK,
+ (const void *) &cork, sizeof(int));
+}
+
+
+int
+ngx_tcp_push(ngx_socket_t s)
+{
+ int cork;
+
+ cork = 0;
+
+ return setsockopt(s, IPPROTO_TCP, TCP_CORK,
+ (const void *) &cork, sizeof(int));
+}
+
+#else
+
+int
+ngx_tcp_nopush(ngx_socket_t s)
+{
+ return 0;
+}
+
+
+int
+ngx_tcp_push(ngx_socket_t s)
+{
+ return 0;
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_socket.h b/app/nginx/src/os/unix/ngx_socket.h
new file mode 100644
index 0000000..fcc5153
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_socket.h
@@ -0,0 +1,64 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SOCKET_H_INCLUDED_
+#define _NGX_SOCKET_H_INCLUDED_
+
+
+#include <ngx_config.h>
+
+
+#define NGX_WRITE_SHUTDOWN SHUT_WR
+
+typedef int ngx_socket_t;
+
+#define ngx_socket socket
+#define ngx_socket_n "socket()"
+
+
+#if (NGX_HAVE_FIONBIO)
+
+int ngx_nonblocking(ngx_socket_t s);
+int ngx_blocking(ngx_socket_t s);
+
+#define ngx_nonblocking_n "ioctl(FIONBIO)"
+#define ngx_blocking_n "ioctl(!FIONBIO)"
+
+#else
+
+#define ngx_nonblocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK)
+#define ngx_nonblocking_n "fcntl(O_NONBLOCK)"
+
+#define ngx_blocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK)
+#define ngx_blocking_n "fcntl(!O_NONBLOCK)"
+
+#endif
+
+int ngx_tcp_nopush(ngx_socket_t s);
+int ngx_tcp_push(ngx_socket_t s);
+
+#if (NGX_LINUX)
+
+#define ngx_tcp_nopush_n "setsockopt(TCP_CORK)"
+#define ngx_tcp_push_n "setsockopt(!TCP_CORK)"
+
+#else
+
+#define ngx_tcp_nopush_n "setsockopt(TCP_NOPUSH)"
+#define ngx_tcp_push_n "setsockopt(!TCP_NOPUSH)"
+
+#endif
+
+
+#define ngx_shutdown_socket shutdown
+#define ngx_shutdown_socket_n "shutdown()"
+
+#define ngx_close_socket close
+#define ngx_close_socket_n "close() socket"
+
+
+#endif /* _NGX_SOCKET_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_solaris.h b/app/nginx/src/os/unix/ngx_solaris.h
new file mode 100644
index 0000000..7b167d8
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_solaris.h
@@ -0,0 +1,16 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SOLARIS_H_INCLUDED_
+#define _NGX_SOLARIS_H_INCLUDED_
+
+
+ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+
+#endif /* _NGX_SOLARIS_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_solaris_config.h b/app/nginx/src/os/unix/ngx_solaris_config.h
new file mode 100644
index 0000000..ffa01c8
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_solaris_config.h
@@ -0,0 +1,112 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SOLARIS_CONFIG_H_INCLUDED_
+#define _NGX_SOLARIS_CONFIG_H_INCLUDED_
+
+
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+
+#define _FILE_OFFSET_BITS 64 /* must be before <sys/types.h> */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h> /* offsetof() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <glob.h>
+#include <time.h>
+#include <sys/statvfs.h> /* statvfs() */
+
+#include <sys/filio.h> /* FIONBIO */
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h> /* TCP_NODELAY */
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+
+#include <sys/systeminfo.h>
+#include <limits.h> /* IOV_MAX */
+#include <inttypes.h>
+#include <crypt.h>
+
+#include <dlfcn.h>
+
+#define NGX_ALIGNMENT _MAX_ALIGNMENT
+
+#include <ngx_auto_config.h>
+
+
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
+#if (NGX_HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (NGX_HAVE_DEVPOLL)
+#include <sys/ioctl.h>
+#include <sys/devpoll.h>
+#endif
+
+
+#if (NGX_HAVE_EVENTPORT)
+#include <port.h>
+#endif
+
+
+#if (NGX_HAVE_SENDFILE)
+#include <sys/sendfile.h>
+#endif
+
+
+#define NGX_LISTEN_BACKLOG 511
+
+
+#ifndef NGX_HAVE_INHERITED_NONBLOCK
+#define NGX_HAVE_INHERITED_NONBLOCK 1
+#endif
+
+
+#ifndef NGX_HAVE_SO_SNDLOWAT
+/* setsockopt(SO_SNDLOWAT) returns ENOPROTOOPT */
+#define NGX_HAVE_SO_SNDLOWAT 0
+#endif
+
+
+#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define ngx_debug_init()
+
+
+extern char **environ;
+
+
+#endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_solaris_init.c b/app/nginx/src/os/unix/ngx_solaris_init.c
new file mode 100644
index 0000000..65d7875
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_solaris_init.c
@@ -0,0 +1,77 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+char ngx_solaris_sysname[20];
+char ngx_solaris_release[10];
+char ngx_solaris_version[50];
+
+
+static ngx_os_io_t ngx_solaris_io = {
+ ngx_unix_recv,
+ ngx_readv_chain,
+ ngx_udp_unix_recv,
+ ngx_unix_send,
+ ngx_udp_unix_send,
+ ngx_udp_unix_sendmsg_chain,
+#if (NGX_HAVE_SENDFILE)
+ ngx_solaris_sendfilev_chain,
+ NGX_IO_SENDFILE
+#else
+ ngx_writev_chain,
+ 0
+#endif
+};
+
+
+ngx_int_t
+ngx_os_specific_init(ngx_log_t *log)
+{
+ if (sysinfo(SI_SYSNAME, ngx_solaris_sysname, sizeof(ngx_solaris_sysname))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sysinfo(SI_SYSNAME) failed");
+ return NGX_ERROR;
+ }
+
+ if (sysinfo(SI_RELEASE, ngx_solaris_release, sizeof(ngx_solaris_release))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sysinfo(SI_RELEASE) failed");
+ return NGX_ERROR;
+ }
+
+ if (sysinfo(SI_VERSION, ngx_solaris_version, sizeof(ngx_solaris_version))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sysinfo(SI_SYSNAME) failed");
+ return NGX_ERROR;
+ }
+
+
+ ngx_os_io = ngx_solaris_io;
+
+ return NGX_OK;
+}
+
+
+void
+ngx_os_specific_status(ngx_log_t *log)
+{
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
+ ngx_solaris_sysname, ngx_solaris_release);
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "version: %s",
+ ngx_solaris_version);
+}
diff --git a/app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c b/app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c
new file mode 100644
index 0000000..39bcafa
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -0,0 +1,228 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#if (NGX_TEST_BUILD_SOLARIS_SENDFILEV)
+
+/* Solaris declarations */
+
+typedef struct sendfilevec {
+ int sfv_fd;
+ u_int sfv_flag;
+ off_t sfv_off;
+ size_t sfv_len;
+} sendfilevec_t;
+
+#define SFV_FD_SELF -2
+
+static ssize_t sendfilev(int fd, const struct sendfilevec *vec,
+ int sfvcnt, size_t *xferred)
+{
+ return -1;
+}
+
+ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+#endif
+
+
+#define NGX_SENDFILEVECS NGX_IOVS_PREALLOCATE
+
+
+ngx_chain_t *
+ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ int fd;
+ u_char *prev;
+ off_t size, send, prev_send, aligned, fprev;
+ size_t sent;
+ ssize_t n;
+ ngx_int_t eintr;
+ ngx_err_t err;
+ ngx_buf_t *file;
+ ngx_uint_t nsfv;
+ sendfilevec_t *sfv, sfvs[NGX_SENDFILEVECS];
+ ngx_event_t *wev;
+ ngx_chain_t *cl;
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+ if (!c->sendfile) {
+ return ngx_writev_chain(c, in, limit);
+ }
+
+
+ /* the maximum limit size is the maximum size_t value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
+ limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
+ }
+
+
+ send = 0;
+
+ for ( ;; ) {
+ fd = SFV_FD_SELF;
+ prev = NULL;
+ fprev = 0;
+ file = NULL;
+ sfv = NULL;
+ eintr = 0;
+ sent = 0;
+ prev_send = send;
+
+ nsfv = 0;
+
+ /* create the sendfilevec and coalesce the neighbouring bufs */
+
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
+ if (ngx_buf_special(cl->buf)) {
+ continue;
+ }
+
+ if (ngx_buf_in_memory_only(cl->buf)) {
+ fd = SFV_FD_SELF;
+
+ size = cl->buf->last - cl->buf->pos;
+
+ if (send + size > limit) {
+ size = limit - send;
+ }
+
+ if (prev == cl->buf->pos) {
+ sfv->sfv_len += (size_t) size;
+
+ } else {
+ if (nsfv == NGX_SENDFILEVECS) {
+ break;
+ }
+
+ sfv = &sfvs[nsfv++];
+
+ sfv->sfv_fd = SFV_FD_SELF;
+ sfv->sfv_flag = 0;
+ sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos;
+ sfv->sfv_len = (size_t) size;
+ }
+
+ prev = cl->buf->pos + (size_t) size;
+ send += size;
+
+ } else {
+ prev = NULL;
+
+ size = cl->buf->file_last - cl->buf->file_pos;
+
+ if (send + size > limit) {
+ size = limit - send;
+
+ aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
+ & ~((off_t) ngx_pagesize - 1);
+
+ if (aligned <= cl->buf->file_last) {
+ size = aligned - cl->buf->file_pos;
+ }
+ }
+
+ if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) {
+ sfv->sfv_len += (size_t) size;
+
+ } else {
+ if (nsfv == NGX_SENDFILEVECS) {
+ break;
+ }
+
+ sfv = &sfvs[nsfv++];
+
+ fd = cl->buf->file->fd;
+ sfv->sfv_fd = fd;
+ sfv->sfv_flag = 0;
+ sfv->sfv_off = cl->buf->file_pos;
+ sfv->sfv_len = (size_t) size;
+ }
+
+ file = cl->buf;
+ fprev = cl->buf->file_pos + size;
+ send += size;
+ }
+ }
+
+ n = sendfilev(c->fd, sfvs, nsfv, &sent);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ break;
+
+ case NGX_EINTR:
+ eintr = 1;
+ break;
+
+ default:
+ wev->error = 1;
+ ngx_connection_error(c, err, "sendfilev() failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfilev() sent only %uz bytes", sent);
+
+ } else if (n == 0 && sent == 0) {
+
+ /*
+ * sendfilev() is documented to return -1 with errno
+ * set to EINVAL if svf_len is greater than the file size,
+ * but at least Solaris 11 returns 0 instead
+ */
+
+ if (file) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfilev() reported that \"%s\" was truncated at %O",
+ file->file->name.data, file->file_pos);
+
+ } else {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfilev() returned 0 with memory buffers");
+ }
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendfilev: %z %z", n, sent);
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+ if (eintr) {
+ send = prev_send + sent;
+ continue;
+ }
+
+ if (send - prev_send != (off_t) sent) {
+ wev->ready = 0;
+ return in;
+ }
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_sunpro_amd64.il b/app/nginx/src/os/unix/ngx_sunpro_amd64.il
new file mode 100644
index 0000000..07f3210
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_sunpro_amd64.il
@@ -0,0 +1,43 @@
+/
+/ Copyright (C) Igor Sysoev
+/ Copyright (C) Nginx, Inc.
+/
+
+/ ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock,
+/ ngx_atomic_uint_t old, ngx_atomic_uint_t set);
+/
+/ the arguments are passed in %rdi, %rsi, %rdx
+/ the result is returned in the %rax
+
+ .inline ngx_atomic_cmp_set,0
+ movq %rsi, %rax
+ lock
+ cmpxchgq %rdx, (%rdi)
+ setz %al
+ movzbq %al, %rax
+ .end
+
+
+/ ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value,
+/ ngx_atomic_int_t add);
+/
+/ the arguments are passed in %rdi, %rsi
+/ the result is returned in the %rax
+
+ .inline ngx_atomic_fetch_add,0
+ movq %rsi, %rax
+ lock
+ xaddq %rax, (%rdi)
+ .end
+
+
+/ ngx_cpu_pause()
+/
+/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware
+/ capability added by linker because Solaris/amd64 does not know about it:
+/
+/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ]
+
+ .inline ngx_cpu_pause,0
+ rep; nop
+ .end
diff --git a/app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h b/app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h
new file mode 100644
index 0000000..5f28055
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#if (NGX_PTR_SIZE == 4)
+#define NGX_CASA ngx_casa
+#else
+#define NGX_CASA ngx_casxa
+#endif
+
+
+ngx_atomic_uint_t
+ngx_casa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, ngx_atomic_t *lock);
+
+ngx_atomic_uint_t
+ngx_casxa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, ngx_atomic_t *lock);
+
+/* the code in src/os/unix/ngx_sunpro_sparc64.il */
+
+
+static ngx_inline ngx_atomic_uint_t
+ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
+ ngx_atomic_uint_t set)
+{
+ set = NGX_CASA(set, old, lock);
+
+ return (set == old);
+}
+
+
+static ngx_inline ngx_atomic_int_t
+ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
+{
+ ngx_atomic_uint_t old, res;
+
+ old = *value;
+
+ for ( ;; ) {
+
+ res = old + add;
+
+ res = NGX_CASA(res, old, value);
+
+ if (res == old) {
+ return res;
+ }
+
+ old = res;
+ }
+}
+
+
+#define ngx_memory_barrier() \
+ __asm (".volatile"); \
+ __asm ("membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad"); \
+ __asm (".nonvolatile")
+
+#define ngx_cpu_pause()
diff --git a/app/nginx/src/os/unix/ngx_sunpro_sparc64.il b/app/nginx/src/os/unix/ngx_sunpro_sparc64.il
new file mode 100644
index 0000000..bdeef61
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_sunpro_sparc64.il
@@ -0,0 +1,36 @@
+/
+/ Copyright (C) Igor Sysoev
+/ Copyright (C) Nginx, Inc.
+/
+
+
+/ "casa [%o2] 0x80, %o1, %o0" and
+/ "casxa [%o2] 0x80, %o1, %o0" do the following:
+/
+/ if ([%o2] == %o1) {
+/ swap(%o0, [%o2]);
+/ } else {
+/ %o0 = [%o2];
+/ }
+
+
+/ ngx_atomic_uint_t ngx_casa(ngx_atomic_uint_t set, ngx_atomic_uint_t old,
+/ ngx_atomic_t *lock);
+/
+/ the arguments are passed in the %o0, %o1, %o2
+/ the result is returned in the %o0
+
+ .inline ngx_casa,0
+ casa [%o2] 0x80, %o1, %o0
+ .end
+
+
+/ ngx_atomic_uint_t ngx_casxa(ngx_atomic_uint_t set, ngx_atomic_uint_t old,
+/ ngx_atomic_t *lock);
+/
+/ the arguments are passed in the %o0, %o1, %o2
+/ the result is returned in the %o0
+
+ .inline ngx_casxa,0
+ casxa [%o2] 0x80, %o1, %o0
+ .end
diff --git a/app/nginx/src/os/unix/ngx_sunpro_x86.il b/app/nginx/src/os/unix/ngx_sunpro_x86.il
new file mode 100644
index 0000000..d7e127c
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_sunpro_x86.il
@@ -0,0 +1,44 @@
+/
+/ Copyright (C) Igor Sysoev
+/ Copyright (C) Nginx, Inc.
+/
+
+/ ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock,
+/ ngx_atomic_uint_t old, ngx_atomic_uint_t set);
+/
+/ the arguments are passed on stack (%esp), 4(%esp), 8(%esp)
+
+ .inline ngx_atomic_cmp_set,0
+ movl (%esp), %ecx
+ movl 4(%esp), %eax
+ movl 8(%esp), %edx
+ lock
+ cmpxchgl %edx, (%ecx)
+ setz %al
+ movzbl %al, %eax
+ .end
+
+
+/ ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value,
+/ ngx_atomic_int_t add);
+/
+/ the arguments are passed on stack (%esp), 4(%esp)
+
+ .inline ngx_atomic_fetch_add,0
+ movl (%esp), %ecx
+ movl 4(%esp), %eax
+ lock
+ xaddl %eax, (%ecx)
+ .end
+
+
+/ ngx_cpu_pause()
+/
+/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware
+/ capability added by linker because Solaris/i386 does not know about it:
+/
+/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ]
+
+ .inline ngx_cpu_pause,0
+ rep; nop
+ .end
diff --git a/app/nginx/src/os/unix/ngx_thread.h b/app/nginx/src/os/unix/ngx_thread.h
new file mode 100644
index 0000000..1b52dd7
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_thread.h
@@ -0,0 +1,71 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_THREAD_H_INCLUDED_
+#define _NGX_THREAD_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+#if (NGX_THREADS)
+
+#include <pthread.h>
+
+
+typedef pthread_mutex_t ngx_thread_mutex_t;
+
+ngx_int_t ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+ngx_int_t ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+ngx_int_t ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+ngx_int_t ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+
+
+typedef pthread_cond_t ngx_thread_cond_t;
+
+ngx_int_t ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log);
+ngx_int_t ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log);
+ngx_int_t ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log);
+ngx_int_t ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx,
+ ngx_log_t *log);
+
+
+#if (NGX_LINUX)
+
+typedef pid_t ngx_tid_t;
+#define NGX_TID_T_FMT "%P"
+
+#elif (NGX_FREEBSD)
+
+typedef uint32_t ngx_tid_t;
+#define NGX_TID_T_FMT "%uD"
+
+#elif (NGX_DARWIN)
+
+typedef uint64_t ngx_tid_t;
+#define NGX_TID_T_FMT "%uA"
+
+#else
+
+typedef uint64_t ngx_tid_t;
+#define NGX_TID_T_FMT "%uA"
+
+#endif
+
+ngx_tid_t ngx_thread_tid(void);
+
+#define ngx_log_tid ngx_thread_tid()
+
+#else
+
+#define ngx_log_tid 0
+#define NGX_TID_T_FMT "%d"
+
+#endif
+
+
+#endif /* _NGX_THREAD_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_thread_cond.c b/app/nginx/src/os/unix/ngx_thread_cond.c
new file mode 100644
index 0000000..2ad51b8
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_thread_cond.c
@@ -0,0 +1,76 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_int_t
+ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_init(cond, NULL);
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_init() failed");
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_destroy(cond);
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_destroy() failed");
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_signal(cond);
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_signal() failed");
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx,
+ ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_wait(cond, mtx);
+
+#if 0
+ ngx_time_update();
+#endif
+
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_cond_wait() failed");
+
+ return NGX_ERROR;
+}
diff --git a/app/nginx/src/os/unix/ngx_thread_id.c b/app/nginx/src/os/unix/ngx_thread_id.c
new file mode 100644
index 0000000..5174f1a
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_thread_id.c
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_thread_pool.h>
+
+
+#if (NGX_LINUX)
+
+/*
+ * Linux thread id is a pid of thread created by clone(2),
+ * glibc does not provide a wrapper for gettid().
+ */
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ return syscall(SYS_gettid);
+}
+
+#elif (NGX_FREEBSD) && (__FreeBSD_version >= 900031)
+
+#include <pthread_np.h>
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ return pthread_getthreadid_np();
+}
+
+#elif (NGX_DARWIN)
+
+/*
+ * MacOSX thread has two thread ids:
+ *
+ * 1) MacOSX 10.6 (Snow Leoprad) has pthread_threadid_np() returning
+ * an uint64_t value, which is obtained using the __thread_selfid()
+ * syscall. It is a number above 300,000.
+ */
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ uint64_t tid;
+
+ (void) pthread_threadid_np(NULL, &tid);
+ return tid;
+}
+
+/*
+ * 2) Kernel thread mach_port_t returned by pthread_mach_thread_np().
+ * It is a number in range 100-100,000.
+ *
+ * return pthread_mach_thread_np(pthread_self());
+ */
+
+#else
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ return (uint64_t) (uintptr_t) pthread_self();
+}
+
+#endif
diff --git a/app/nginx/src/os/unix/ngx_thread_mutex.c b/app/nginx/src/os/unix/ngx_thread_mutex.c
new file mode 100644
index 0000000..4886f49
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_thread_mutex.c
@@ -0,0 +1,165 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * All modern pthread mutex implementations try to acquire a lock
+ * atomically in userland before going to sleep in kernel. Some
+ * spins before the sleeping.
+ *
+ * In Solaris since version 8 all mutex types spin before sleeping.
+ * The default spin count is 1000. It can be overridden using
+ * _THREAD_ADAPTIVE_SPIN=100 environment variable.
+ *
+ * In MacOSX all mutex types spin to acquire a lock protecting a mutex's
+ * internals. If the mutex is busy, thread calls Mach semaphore_wait().
+ *
+ *
+ * PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest
+ * mutex type.
+ *
+ * Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP
+ * remains from the times when pthread_mutex_timedlock() was
+ * non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP.
+ * FreeBSD: No spinning.
+ *
+ *
+ * PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL
+ * yet has lightweight deadlock detection.
+ *
+ * Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP.
+ * FreeBSD: No spinning.
+ *
+ *
+ * PTHREAD_MUTEX_RECURSIVE allows recursive locking.
+ *
+ * Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP.
+ * FreeBSD: No spinning.
+ *
+ *
+ * PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping.
+ *
+ * Linux: No deadlock detection. Dynamically changes a spin count
+ * for each mutex from 10 to 100 based on spin count taken
+ * previously.
+ * FreeBSD: Deadlock detection. The default spin count is 2000.
+ * It can be overridden using LIBPTHREAD_SPINLOOPS environment
+ * variable or by pthread_mutex_setspinloops_np(). If a lock
+ * is still busy, sched_yield() can be called on both UP and
+ * SMP systems. The default yield loop count is zero, but
+ * it can be set by LIBPTHREAD_YIELDLOOPS environment
+ * variable or by pthread_mutex_setyieldloops_np().
+ * Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP.
+ * MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP.
+ *
+ *
+ * PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using
+ * Intel Restricted Transactional Memory. It is the most suitable for
+ * rwlock pattern access because it allows simultaneous reads without lock.
+ * Supported since glibc 2.18.
+ *
+ *
+ * PTHREAD_MUTEX_DEFAULT is default mutex type.
+ *
+ * Linux: PTHREAD_MUTEX_NORMAL.
+ * FreeBSD: PTHREAD_MUTEX_ERRORCHECK.
+ * Solaris: PTHREAD_MUTEX_NORMAL.
+ * MacOSX: PTHREAD_MUTEX_NORMAL.
+ */
+
+
+ngx_int_t
+ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+ pthread_mutexattr_t attr;
+
+ err = pthread_mutexattr_init(&attr);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "pthread_mutexattr_init() failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "pthread_mutexattr_settype"
+ "(PTHREAD_MUTEX_ERRORCHECK) failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_mutex_init(mtx, &attr);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "pthread_mutex_init() failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_mutexattr_destroy(&attr);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_mutexattr_destroy() failed");
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_mutex_destroy(mtx);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_mutex_destroy() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_mutex_lock(mtx);
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_lock() failed");
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_mutex_unlock(mtx);
+
+#if 0
+ ngx_time_update();
+#endif
+
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_unlock() failed");
+
+ return NGX_ERROR;
+}
diff --git a/app/nginx/src/os/unix/ngx_time.c b/app/nginx/src/os/unix/ngx_time.c
new file mode 100644
index 0000000..cc760b2
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_time.c
@@ -0,0 +1,104 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * FreeBSD does not test /etc/localtime change, however, we can workaround it
+ * by calling tzset() with TZ and then without TZ to update timezone.
+ * The trick should work since FreeBSD 2.1.0.
+ *
+ * Linux does not test /etc/localtime change in localtime(),
+ * but may stat("/etc/localtime") several times in every strftime(),
+ * therefore we use it to update timezone.
+ *
+ * Solaris does not test /etc/TIMEZONE change too and no workaround available.
+ */
+
+void
+ngx_timezone_update(void)
+{
+#if (NGX_FREEBSD)
+
+ if (getenv("TZ")) {
+ return;
+ }
+
+ putenv("TZ=UTC");
+
+ tzset();
+
+ unsetenv("TZ");
+
+ tzset();
+
+#elif (NGX_LINUX)
+ time_t s;
+ struct tm *t;
+ char buf[4];
+
+ s = time(0);
+
+ t = localtime(&s);
+
+ strftime(buf, 4, "%H", t);
+
+#endif
+}
+
+
+void
+ngx_localtime(time_t s, ngx_tm_t *tm)
+{
+#if (NGX_HAVE_LOCALTIME_R)
+ (void) localtime_r(&s, tm);
+
+#else
+ ngx_tm_t *t;
+
+ t = localtime(&s);
+ *tm = *t;
+
+#endif
+
+ tm->ngx_tm_mon++;
+ tm->ngx_tm_year += 1900;
+}
+
+
+void
+ngx_libc_localtime(time_t s, struct tm *tm)
+{
+#if (NGX_HAVE_LOCALTIME_R)
+ (void) localtime_r(&s, tm);
+
+#else
+ struct tm *t;
+
+ t = localtime(&s);
+ *tm = *t;
+
+#endif
+}
+
+
+void
+ngx_libc_gmtime(time_t s, struct tm *tm)
+{
+#if (NGX_HAVE_LOCALTIME_R)
+ (void) gmtime_r(&s, tm);
+
+#else
+ struct tm *t;
+
+ t = gmtime(&s);
+ *tm = *t;
+
+#endif
+}
diff --git a/app/nginx/src/os/unix/ngx_time.h b/app/nginx/src/os/unix/ngx_time.h
new file mode 100644
index 0000000..c128c9a
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_time.h
@@ -0,0 +1,66 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_TIME_H_INCLUDED_
+#define _NGX_TIME_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef ngx_rbtree_key_t ngx_msec_t;
+typedef ngx_rbtree_key_int_t ngx_msec_int_t;
+
+typedef struct tm ngx_tm_t;
+
+#define ngx_tm_sec tm_sec
+#define ngx_tm_min tm_min
+#define ngx_tm_hour tm_hour
+#define ngx_tm_mday tm_mday
+#define ngx_tm_mon tm_mon
+#define ngx_tm_year tm_year
+#define ngx_tm_wday tm_wday
+#define ngx_tm_isdst tm_isdst
+
+#define ngx_tm_sec_t int
+#define ngx_tm_min_t int
+#define ngx_tm_hour_t int
+#define ngx_tm_mday_t int
+#define ngx_tm_mon_t int
+#define ngx_tm_year_t int
+#define ngx_tm_wday_t int
+
+
+#if (NGX_HAVE_GMTOFF)
+#define ngx_tm_gmtoff tm_gmtoff
+#define ngx_tm_zone tm_zone
+#endif
+
+
+#if (NGX_SOLARIS)
+
+#define ngx_timezone(isdst) (- (isdst ? altzone : timezone) / 60)
+
+#else
+
+#define ngx_timezone(isdst) (- (isdst ? timezone + 3600 : timezone) / 60)
+
+#endif
+
+
+void ngx_timezone_update(void);
+void ngx_localtime(time_t s, ngx_tm_t *tm);
+void ngx_libc_localtime(time_t s, struct tm *tm);
+void ngx_libc_gmtime(time_t s, struct tm *tm);
+
+#define ngx_gettimeofday(tp) (void) gettimeofday(tp, NULL);
+#define ngx_msleep(ms) (void) usleep(ms * 1000)
+#define ngx_sleep(s) (void) sleep(s)
+
+
+#endif /* _NGX_TIME_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_udp_recv.c b/app/nginx/src/os/unix/ngx_udp_recv.c
new file mode 100644
index 0000000..6d544c2
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_udp_recv.c
@@ -0,0 +1,72 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_event_t *rev;
+
+ rev = c->read;
+
+ do {
+ n = recv(c->fd, buf, size, 0);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "recv: fd:%d %z of %uz", c->fd, n, size);
+
+ if (n >= 0) {
+
+#if (NGX_HAVE_KQUEUE)
+
+ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+ rev->available -= n;
+
+ /*
+ * rev->available may be negative here because some additional
+ * bytes may be received between kevent() and recv()
+ */
+
+ if (rev->available <= 0) {
+ rev->ready = 0;
+ rev->available = 0;
+ }
+ }
+
+#endif
+
+ return n;
+ }
+
+ err = ngx_socket_errno;
+
+ if (err == NGX_EAGAIN || err == NGX_EINTR) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "recv() not ready");
+ n = NGX_AGAIN;
+
+ } else {
+ n = ngx_connection_error(c, err, "recv() failed");
+ break;
+ }
+
+ } while (err == NGX_EINTR);
+
+ rev->ready = 0;
+
+ if (n == NGX_ERROR) {
+ rev->error = 1;
+ }
+
+ return n;
+}
diff --git a/app/nginx/src/os/unix/ngx_udp_send.c b/app/nginx/src/os/unix/ngx_udp_send.c
new file mode 100644
index 0000000..aabbc8e
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_udp_send.c
@@ -0,0 +1,56 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_event_t *wev;
+
+ wev = c->write;
+
+ for ( ;; ) {
+ n = sendto(c->fd, buf, size, 0, c->sockaddr, c->socklen);
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendto: fd:%d %z of %uz to \"%V\"",
+ c->fd, n, size, &c->addr_text);
+
+ if (n >= 0) {
+ if ((size_t) n != size) {
+ wev->error = 1;
+ (void) ngx_connection_error(c, 0, "sendto() incomplete");
+ return NGX_ERROR;
+ }
+
+ c->sent += n;
+
+ return n;
+ }
+
+ err = ngx_socket_errno;
+
+ if (err == NGX_EAGAIN) {
+ wev->ready = 0;
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, NGX_EAGAIN,
+ "sendto() not ready");
+ return NGX_AGAIN;
+ }
+
+ if (err != NGX_EINTR) {
+ wev->error = 1;
+ (void) ngx_connection_error(c, err, "sendto() failed");
+ return NGX_ERROR;
+ }
+ }
+}
diff --git a/app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c b/app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c
new file mode 100644
index 0000000..65bde6f
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c
@@ -0,0 +1,245 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec,
+ ngx_chain_t *in, ngx_log_t *log);
+static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec);
+
+
+ngx_chain_t *
+ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ ssize_t n;
+ off_t send;
+ ngx_chain_t *cl;
+ ngx_event_t *wev;
+ ngx_iovec_t vec;
+ struct iovec iovs[NGX_IOVS_PREALLOCATE];
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+#if (NGX_HAVE_KQUEUE)
+
+ if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
+ (void) ngx_connection_error(c, wev->kq_errno,
+ "kevent() reported about an closed connection");
+ wev->error = 1;
+ return NGX_CHAIN_ERROR;
+ }
+
+#endif
+
+ /* the maximum limit size is the maximum size_t value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
+ limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
+ }
+
+ send = 0;
+
+ vec.iovs = iovs;
+ vec.nalloc = NGX_IOVS_PREALLOCATE;
+
+ for ( ;; ) {
+
+ /* create the iovec and coalesce the neighbouring bufs */
+
+ cl = ngx_udp_output_chain_to_iovec(&vec, in, c->log);
+
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (cl && cl->buf->in_file) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "file buf in sendmsg "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ cl->buf->temporary,
+ cl->buf->recycled,
+ cl->buf->in_file,
+ cl->buf->start,
+ cl->buf->pos,
+ cl->buf->last,
+ cl->buf->file,
+ cl->buf->file_pos,
+ cl->buf->file_last);
+
+ ngx_debug_point();
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (cl == in) {
+ return in;
+ }
+
+ send += vec.size;
+
+ n = ngx_sendmsg(c, &vec);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (n == NGX_AGAIN) {
+ wev->ready = 0;
+ return in;
+ }
+
+ c->sent += n;
+
+ in = ngx_chain_update_sent(in, n);
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
+
+
+static ngx_chain_t *
+ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log)
+{
+ size_t total, size;
+ u_char *prev;
+ ngx_uint_t n, flush;
+ ngx_chain_t *cl;
+ struct iovec *iov;
+
+ cl = in;
+ iov = NULL;
+ prev = NULL;
+ total = 0;
+ n = 0;
+ flush = 0;
+
+ for ( /* void */ ; in && !flush; in = in->next) {
+
+ if (in->buf->flush || in->buf->last_buf) {
+ flush = 1;
+ }
+
+ if (ngx_buf_special(in->buf)) {
+ continue;
+ }
+
+ if (in->buf->in_file) {
+ break;
+ }
+
+ if (!ngx_buf_in_memory(in->buf)) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "bad buf in output chain "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ in->buf->temporary,
+ in->buf->recycled,
+ in->buf->in_file,
+ in->buf->start,
+ in->buf->pos,
+ in->buf->last,
+ in->buf->file,
+ in->buf->file_pos,
+ in->buf->file_last);
+
+ ngx_debug_point();
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ size = in->buf->last - in->buf->pos;
+
+ if (prev == in->buf->pos) {
+ iov->iov_len += size;
+
+ } else {
+ if (n == vec->nalloc) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "too many parts in a datagram");
+ return NGX_CHAIN_ERROR;
+ }
+
+ iov = &vec->iovs[n++];
+
+ iov->iov_base = (void *) in->buf->pos;
+ iov->iov_len = size;
+ }
+
+ prev = in->buf->pos + size;
+ total += size;
+ }
+
+ if (!flush) {
+#if (NGX_SUPPRESS_WARN)
+ vec->size = 0;
+ vec->count = 0;
+#endif
+ return cl;
+ }
+
+ vec->count = n;
+ vec->size = total;
+
+ return in;
+}
+
+
+static ssize_t
+ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec)
+{
+ ssize_t n;
+ ngx_err_t err;
+ struct msghdr msg;
+
+ ngx_memzero(&msg, sizeof(struct msghdr));
+
+ if (c->socklen) {
+ msg.msg_name = c->sockaddr;
+ msg.msg_namelen = c->socklen;
+ }
+
+ msg.msg_iov = vec->iovs;
+ msg.msg_iovlen = vec->count;
+
+eintr:
+
+ n = sendmsg(c->fd, &msg, 0);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendmsg: %z of %uz", n, vec->size);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendmsg() not ready");
+ return NGX_AGAIN;
+
+ case NGX_EINTR:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendmsg() was interrupted");
+ goto eintr;
+
+ default:
+ c->write->error = 1;
+ ngx_connection_error(c, err, "sendmsg() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ return n;
+}
diff --git a/app/nginx/src/os/unix/ngx_user.c b/app/nginx/src/os/unix/ngx_user.c
new file mode 100644
index 0000000..27c76ef
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_user.c
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * Solaris has thread-safe crypt()
+ * Linux has crypt_r(); "struct crypt_data" is more than 128K
+ * FreeBSD needs the mutex to protect crypt()
+ *
+ * TODO:
+ * ngx_crypt_init() to init mutex
+ */
+
+
+#if (NGX_CRYPT)
+
+#if (NGX_HAVE_GNU_CRYPT_R)
+
+ngx_int_t
+ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ char *value;
+ size_t len;
+ struct crypt_data cd;
+
+ cd.initialized = 0;
+#ifdef __GLIBC__
+ /* work around the glibc bug */
+ cd.current_salt[0] = ~salt[0];
+#endif
+
+ value = crypt_r((char *) key, (char *) salt, &cd);
+
+ if (value) {
+ len = ngx_strlen(value) + 1;
+
+ *encrypted = ngx_pnalloc(pool, len);
+ if (*encrypted == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(*encrypted, value, len);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, "crypt_r() failed");
+
+ return NGX_ERROR;
+}
+
+#else
+
+ngx_int_t
+ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ char *value;
+ size_t len;
+ ngx_err_t err;
+
+ value = crypt((char *) key, (char *) salt);
+
+ if (value) {
+ len = ngx_strlen(value) + 1;
+
+ *encrypted = ngx_pnalloc(pool, len);
+ if (*encrypted == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(*encrypted, value, len);
+ return NGX_OK;
+ }
+
+ err = ngx_errno;
+
+ ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed");
+
+ return NGX_ERROR;
+}
+
+#endif
+
+#endif /* NGX_CRYPT */
diff --git a/app/nginx/src/os/unix/ngx_user.h b/app/nginx/src/os/unix/ngx_user.h
new file mode 100644
index 0000000..6e82204
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_user.h
@@ -0,0 +1,24 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_USER_H_INCLUDED_
+#define _NGX_USER_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef uid_t ngx_uid_t;
+typedef gid_t ngx_gid_t;
+
+
+ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+
+
+#endif /* _NGX_USER_H_INCLUDED_ */
diff --git a/app/nginx/src/os/unix/ngx_writev_chain.c b/app/nginx/src/os/unix/ngx_writev_chain.c
new file mode 100644
index 0000000..e38a3aa
--- /dev/null
+++ b/app/nginx/src/os/unix/ngx_writev_chain.c
@@ -0,0 +1,216 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ngx_chain_t *
+ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ ssize_t n, sent;
+ off_t send, prev_send;
+ ngx_chain_t *cl;
+ ngx_event_t *wev;
+ ngx_iovec_t vec;
+ struct iovec iovs[NGX_IOVS_PREALLOCATE];
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+#if (NGX_HAVE_KQUEUE)
+
+ if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
+ (void) ngx_connection_error(c, wev->kq_errno,
+ "kevent() reported about an closed connection");
+ wev->error = 1;
+ return NGX_CHAIN_ERROR;
+ }
+
+#endif
+
+ /* the maximum limit size is the maximum size_t value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
+ limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
+ }
+
+ send = 0;
+
+ vec.iovs = iovs;
+ vec.nalloc = NGX_IOVS_PREALLOCATE;
+
+ for ( ;; ) {
+ prev_send = send;
+
+ /* create the iovec and coalesce the neighbouring bufs */
+
+ cl = ngx_output_chain_to_iovec(&vec, in, limit - send, c->log);
+
+ if (cl == NGX_CHAIN_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (cl && cl->buf->in_file) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "file buf in writev "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ cl->buf->temporary,
+ cl->buf->recycled,
+ cl->buf->in_file,
+ cl->buf->start,
+ cl->buf->pos,
+ cl->buf->last,
+ cl->buf->file,
+ cl->buf->file_pos,
+ cl->buf->file_last);
+
+ ngx_debug_point();
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ send += vec.size;
+
+ n = ngx_writev(c, &vec);
+
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ sent = (n == NGX_AGAIN) ? 0 : n;
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+ if (send - prev_send != sent) {
+ wev->ready = 0;
+ return in;
+ }
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
+
+
+ngx_chain_t *
+ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, size_t limit,
+ ngx_log_t *log)
+{
+ size_t total, size;
+ u_char *prev;
+ ngx_uint_t n;
+ struct iovec *iov;
+
+ iov = NULL;
+ prev = NULL;
+ total = 0;
+ n = 0;
+
+ for ( /* void */ ; in && total < limit; in = in->next) {
+
+ if (ngx_buf_special(in->buf)) {
+ continue;
+ }
+
+ if (in->buf->in_file) {
+ break;
+ }
+
+ if (!ngx_buf_in_memory(in->buf)) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "bad buf in output chain "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ in->buf->temporary,
+ in->buf->recycled,
+ in->buf->in_file,
+ in->buf->start,
+ in->buf->pos,
+ in->buf->last,
+ in->buf->file,
+ in->buf->file_pos,
+ in->buf->file_last);
+
+ ngx_debug_point();
+
+ return NGX_CHAIN_ERROR;
+ }
+
+ size = in->buf->last - in->buf->pos;
+
+ if (size > limit - total) {
+ size = limit - total;
+ }
+
+ if (prev == in->buf->pos) {
+ iov->iov_len += size;
+
+ } else {
+ if (n == vec->nalloc) {
+ break;
+ }
+
+ iov = &vec->iovs[n++];
+
+ iov->iov_base = (void *) in->buf->pos;
+ iov->iov_len = size;
+ }
+
+ prev = in->buf->pos + size;
+ total += size;
+ }
+
+ vec->count = n;
+ vec->size = total;
+
+ return in;
+}
+
+
+ssize_t
+ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec)
+{
+ ssize_t n;
+ ngx_err_t err;
+
+eintr:
+
+ n = writev(c->fd, vec->iovs, vec->count);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "writev: %z of %uz", n, vec->size);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "writev() not ready");
+ return NGX_AGAIN;
+
+ case NGX_EINTR:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "writev() was interrupted");
+ goto eintr;
+
+ default:
+ c->write->error = 1;
+ ngx_connection_error(c, err, "writev() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ return n;
+}
diff --git a/app/nginx/src/os/win32/nginx.ico b/app/nginx/src/os/win32/nginx.ico
new file mode 100644
index 0000000..70f79db
--- /dev/null
+++ b/app/nginx/src/os/win32/nginx.ico
Binary files differ
diff --git a/app/nginx/src/os/win32/nginx.rc b/app/nginx/src/os/win32/nginx.rc
new file mode 100644
index 0000000..dc8b7ab
--- /dev/null
+++ b/app/nginx/src/os/win32/nginx.rc
@@ -0,0 +1,6 @@
+
+// Copyright (C) Igor Sysoev
+// Copyright (C) Nginx, Inc.
+
+
+nginx icon discardable "src\\os\\win32\\nginx.ico"
diff --git a/app/nginx/src/os/win32/nginx_icon16.xpm b/app/nginx/src/os/win32/nginx_icon16.xpm
new file mode 100644
index 0000000..45e4bad
--- /dev/null
+++ b/app/nginx/src/os/win32/nginx_icon16.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * nginx_xpm[] = {
+"16 16 2 2",
+/* colors */
+" c none",
+"GG c #009900",
+/* pixels */
+" ",
+" GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGG ",
+" GGGGGG GGGGGG ",
+" GGGGGG GGGGGG ",
+" GGGGGG ",
+" GGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGG GGGGGGGGGGGGGGGGGG ",
+" GGGGGG GGGGGGGGGGGGGG ",
+" GGGGGG GGGGGG ",
+" GGGGGG GGGGGG ",
+" GGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG ",
+" "
+};
diff --git a/app/nginx/src/os/win32/nginx_icon32.xpm b/app/nginx/src/os/win32/nginx_icon32.xpm
new file mode 100644
index 0000000..eb26638
--- /dev/null
+++ b/app/nginx/src/os/win32/nginx_icon32.xpm
@@ -0,0 +1,39 @@
+/* XPM */
+static char * nginx_xpm[] = {
+"32 32 2 2",
+/* colors */
+" c none",
+"GG c #009900",
+/* pixels */
+" ",
+" ",
+" ",
+" ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGG ",
+" GGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGG GGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" ",
+" ",
+" ",
+" "
diff --git a/app/nginx/src/os/win32/nginx_icon48.xpm b/app/nginx/src/os/win32/nginx_icon48.xpm
new file mode 100644
index 0000000..c25ba0f
--- /dev/null
+++ b/app/nginx/src/os/win32/nginx_icon48.xpm
@@ -0,0 +1,55 @@
+/* XPM */
+static char * nginx_xpm[] = {
+"48 48 2 2",
+/* colors */
+" c none",
+"GG c #009900",
+/* pixels */
+" ",
+" ",
+" ",
+" ",
+" ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ",
+" ",
+" ",
+" ",
+" ",
+" ",
diff --git a/app/nginx/src/os/win32/ngx_alloc.c b/app/nginx/src/os/win32/ngx_alloc.c
new file mode 100644
index 0000000..0c0ef30
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_alloc.c
@@ -0,0 +1,44 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_uint_t ngx_pagesize;
+ngx_uint_t ngx_pagesize_shift;
+ngx_uint_t ngx_cacheline_size;
+
+
+void *ngx_alloc(size_t size, ngx_log_t *log)
+{
+ void *p;
+
+ p = malloc(size);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "malloc(%uz) failed", size);
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);
+
+ return p;
+}
+
+
+void *ngx_calloc(size_t size, ngx_log_t *log)
+{
+ void *p;
+
+ p = ngx_alloc(size, log);
+
+ if (p) {
+ ngx_memzero(p, size);
+ }
+
+ return p;
+}
diff --git a/app/nginx/src/os/win32/ngx_alloc.h b/app/nginx/src/os/win32/ngx_alloc.h
new file mode 100644
index 0000000..5a0fa3f
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_alloc.h
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ALLOC_H_INCLUDED_
+#define _NGX_ALLOC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void *ngx_alloc(size_t size, ngx_log_t *log);
+void *ngx_calloc(size_t size, ngx_log_t *log);
+
+#define ngx_free free
+#define ngx_memalign(alignment, size, log) ngx_alloc(size, log)
+
+extern ngx_uint_t ngx_pagesize;
+extern ngx_uint_t ngx_pagesize_shift;
+extern ngx_uint_t ngx_cacheline_size;
+
+
+#endif /* _NGX_ALLOC_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_atomic.h b/app/nginx/src/os/win32/ngx_atomic.h
new file mode 100644
index 0000000..113f561
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_atomic.h
@@ -0,0 +1,69 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ATOMIC_H_INCLUDED_
+#define _NGX_ATOMIC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_HAVE_ATOMIC_OPS 1
+
+typedef int32_t ngx_atomic_int_t;
+typedef uint32_t ngx_atomic_uint_t;
+typedef volatile ngx_atomic_uint_t ngx_atomic_t;
+#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)
+
+
+#if defined( __WATCOMC__ ) || defined( __BORLANDC__ ) || defined(__GNUC__) \
+ || ( _MSC_VER >= 1300 )
+
+/* the new SDK headers */
+
+#define ngx_atomic_cmp_set(lock, old, set) \
+ ((ngx_atomic_uint_t) InterlockedCompareExchange((long *) lock, set, old) \
+ == old)
+
+#else
+
+/* the old MS VC6.0SP2 SDK headers */
+
+#define ngx_atomic_cmp_set(lock, old, set) \
+ (InterlockedCompareExchange((void **) lock, (void *) set, (void *) old) \
+ == (void *) old)
+
+#endif
+
+
+#define ngx_atomic_fetch_add(p, add) InterlockedExchangeAdd((long *) p, add)
+
+
+#define ngx_memory_barrier()
+
+
+#if defined( __BORLANDC__ ) || ( __WATCOMC__ < 1230 )
+
+/*
+ * Borland C++ 5.5 (tasm32) and Open Watcom C prior to 1.3
+ * do not understand the "pause" instruction
+ */
+
+#define ngx_cpu_pause()
+#else
+#define ngx_cpu_pause() __asm { pause }
+#endif
+
+
+void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin);
+
+#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))
+#define ngx_unlock(lock) *(lock) = 0
+
+
+#endif /* _NGX_ATOMIC_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_dlopen.c b/app/nginx/src/os/win32/ngx_dlopen.c
new file mode 100644
index 0000000..804f49d
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_dlopen.c
@@ -0,0 +1,22 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+char *
+ngx_dlerror(void)
+{
+ u_char *p;
+ static u_char errstr[NGX_MAX_ERROR_STR];
+
+ p = ngx_strerror(ngx_errno, errstr, NGX_MAX_ERROR_STR);
+ *p = '\0';
+
+ return (char *) errstr;
+}
diff --git a/app/nginx/src/os/win32/ngx_dlopen.h b/app/nginx/src/os/win32/ngx_dlopen.h
new file mode 100644
index 0000000..0d6b405
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_dlopen.h
@@ -0,0 +1,32 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_DLOPEN_H_INCLUDED_
+#define _NGX_DLOPEN_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_HAVE_DLOPEN 1
+
+
+#define ngx_dlopen(path) LoadLibrary((char *) path)
+#define ngx_dlopen_n "LoadLibrary()"
+
+#define ngx_dlsym(handle, symbol) (void *) GetProcAddress(handle, symbol)
+#define ngx_dlsym_n "GetProcAddress()"
+
+#define ngx_dlclose(handle) (FreeLibrary(handle) ? 0 : -1)
+#define ngx_dlclose_n "FreeLibrary()"
+
+
+char *ngx_dlerror(void);
+
+
+#endif /* _NGX_DLOPEN_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_errno.c b/app/nginx/src/os/win32/ngx_errno.c
new file mode 100644
index 0000000..b732bf4
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_errno.c
@@ -0,0 +1,60 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+u_char *
+ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
+{
+ u_int len;
+ static u_long lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
+
+ if (size == 0) {
+ return errstr;
+ }
+
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err, lang, (char *) errstr, size, NULL);
+
+ if (len == 0 && lang && GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND) {
+
+ /*
+ * Try to use English messages first and fallback to a language,
+ * based on locale: non-English Windows have no English messages
+ * at all. This way allows to use English messages at least on
+ * Windows with MUI.
+ */
+
+ lang = 0;
+
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err, lang, (char *) errstr, size, NULL);
+ }
+
+ if (len == 0) {
+ return ngx_snprintf(errstr, size,
+ "FormatMessage() error:(%d)", GetLastError());
+ }
+
+ /* remove ".\r\n\0" */
+ while (errstr[len] == '\0' || errstr[len] == CR
+ || errstr[len] == LF || errstr[len] == '.')
+ {
+ --len;
+ }
+
+ return &errstr[++len];
+}
+
+
+ngx_int_t
+ngx_strerror_init(void)
+{
+ return NGX_OK;
+}
diff --git a/app/nginx/src/os/win32/ngx_errno.h b/app/nginx/src/os/win32/ngx_errno.h
new file mode 100644
index 0000000..255a39d
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_errno.h
@@ -0,0 +1,71 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ERRNO_H_INCLUDED_
+#define _NGX_ERRNO_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef DWORD ngx_err_t;
+
+#define ngx_errno GetLastError()
+#define ngx_set_errno(err) SetLastError(err)
+#define ngx_socket_errno WSAGetLastError()
+#define ngx_set_socket_errno(err) WSASetLastError(err)
+
+#define NGX_EPERM ERROR_ACCESS_DENIED
+#define NGX_ENOENT ERROR_FILE_NOT_FOUND
+#define NGX_ENOPATH ERROR_PATH_NOT_FOUND
+#define NGX_ENOMEM ERROR_NOT_ENOUGH_MEMORY
+#define NGX_EACCES ERROR_ACCESS_DENIED
+/*
+ * there are two EEXIST error codes:
+ * ERROR_FILE_EXISTS used by CreateFile(CREATE_NEW),
+ * and ERROR_ALREADY_EXISTS used by CreateDirectory();
+ * MoveFile() uses both
+ */
+#define NGX_EEXIST ERROR_ALREADY_EXISTS
+#define NGX_EEXIST_FILE ERROR_FILE_EXISTS
+#define NGX_EXDEV ERROR_NOT_SAME_DEVICE
+#define NGX_ENOTDIR ERROR_PATH_NOT_FOUND
+#define NGX_EISDIR ERROR_CANNOT_MAKE
+#define NGX_ENOSPC ERROR_DISK_FULL
+#define NGX_EPIPE EPIPE
+#define NGX_EAGAIN WSAEWOULDBLOCK
+#define NGX_EINPROGRESS WSAEINPROGRESS
+#define NGX_ENOPROTOOPT WSAENOPROTOOPT
+#define NGX_EOPNOTSUPP WSAEOPNOTSUPP
+#define NGX_EADDRINUSE WSAEADDRINUSE
+#define NGX_ECONNABORTED WSAECONNABORTED
+#define NGX_ECONNRESET WSAECONNRESET
+#define NGX_ENOTCONN WSAENOTCONN
+#define NGX_ETIMEDOUT WSAETIMEDOUT
+#define NGX_ECONNREFUSED WSAECONNREFUSED
+#define NGX_ENAMETOOLONG ERROR_BAD_PATHNAME
+#define NGX_ENETDOWN WSAENETDOWN
+#define NGX_ENETUNREACH WSAENETUNREACH
+#define NGX_EHOSTDOWN WSAEHOSTDOWN
+#define NGX_EHOSTUNREACH WSAEHOSTUNREACH
+#define NGX_ENOMOREFILES ERROR_NO_MORE_FILES
+#define NGX_EILSEQ ERROR_NO_UNICODE_TRANSLATION
+#define NGX_ELOOP 0
+#define NGX_EBADF WSAEBADF
+
+#define NGX_EALREADY WSAEALREADY
+#define NGX_EINVAL WSAEINVAL
+#define NGX_EMFILE WSAEMFILE
+#define NGX_ENFILE WSAEMFILE
+
+
+u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size);
+ngx_int_t ngx_strerror_init(void);
+
+
+#endif /* _NGX_ERRNO_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_event_log.c b/app/nginx/src/os/win32/ngx_event_log.c
new file mode 100644
index 0000000..e11ed1e
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_event_log.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_MAX_ERROR_STR 2048
+
+
+void ngx_cdecl
+ngx_event_log(ngx_err_t err, const char *fmt, ...)
+{
+ u_char *p, *last;
+ long types;
+ HKEY key;
+ HANDLE ev;
+ va_list args;
+ u_char text[NGX_MAX_ERROR_STR];
+ const char *msgarg[9];
+ static u_char netmsg[] = "%SystemRoot%\\System32\\netmsg.dll";
+
+ last = text + NGX_MAX_ERROR_STR;
+ p = text + GetModuleFileName(NULL, (char *) text, NGX_MAX_ERROR_STR - 50);
+
+ *p++ = ':';
+ ngx_linefeed(p);
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(p, last, fmt, args);
+ va_end(args);
+
+ if (err) {
+ p = ngx_log_errno(p, last, err);
+ }
+
+ if (p > last - NGX_LINEFEED_SIZE - 1) {
+ p = last - NGX_LINEFEED_SIZE - 1;
+ }
+
+ ngx_linefeed(p);
+
+ *p = '\0';
+
+ /*
+ * we do not log errors here since we use
+ * Event Log only to log our own logs open errors
+ */
+
+ if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\nginx",
+ 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &key, NULL)
+ != 0)
+ {
+ return;
+ }
+
+ if (RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ,
+ netmsg, sizeof(netmsg) - 1)
+ != 0)
+ {
+ return;
+ }
+
+ types = EVENTLOG_ERROR_TYPE;
+
+ if (RegSetValueEx(key, "TypesSupported", 0, REG_DWORD,
+ (u_char *) &types, sizeof(long))
+ != 0)
+ {
+ return;
+ }
+
+ RegCloseKey(key);
+
+ ev = RegisterEventSource(NULL, "nginx");
+
+ msgarg[0] = (char *) text;
+ msgarg[1] = NULL;
+ msgarg[2] = NULL;
+ msgarg[3] = NULL;
+ msgarg[4] = NULL;
+ msgarg[5] = NULL;
+ msgarg[6] = NULL;
+ msgarg[7] = NULL;
+ msgarg[8] = NULL;
+
+ /*
+ * the 3299 event id in netmsg.dll has the generic message format:
+ * "%1 %2 %3 %4 %5 %6 %7 %8 %9"
+ */
+
+ ReportEvent(ev, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, msgarg, NULL);
+
+ DeregisterEventSource(ev);
+}
diff --git a/app/nginx/src/os/win32/ngx_files.c b/app/nginx/src/os/win32/ngx_files.c
new file mode 100644
index 0000000..9ef22a5
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_files.c
@@ -0,0 +1,883 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_UTF16_BUFLEN 256
+
+static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u,
+ size_t len);
+static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len);
+
+
+/* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */
+
+ngx_fd_t
+ngx_open_file(u_char *name, u_long mode, u_long create, u_long access)
+{
+ size_t len;
+ u_short *u;
+ ngx_fd_t fd;
+ ngx_err_t err;
+ u_short utf16[NGX_UTF16_BUFLEN];
+
+ len = NGX_UTF16_BUFLEN;
+ u = ngx_utf8_to_utf16(utf16, name, &len);
+
+ if (u == NULL) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ fd = INVALID_HANDLE_VALUE;
+
+ if (create == NGX_FILE_OPEN
+ && ngx_win32_check_filename(name, u, len) != NGX_OK)
+ {
+ goto failed;
+ }
+
+ fd = CreateFileW(u, mode,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+failed:
+
+ if (u != utf16) {
+ err = ngx_errno;
+ ngx_free(u);
+ ngx_set_errno(err);
+ }
+
+ return fd;
+}
+
+
+ssize_t
+ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
+{
+ u_long n;
+ ngx_err_t err;
+ OVERLAPPED ovlp, *povlp;
+
+ ovlp.Internal = 0;
+ ovlp.InternalHigh = 0;
+ ovlp.Offset = (u_long) offset;
+ ovlp.OffsetHigh = (u_long) (offset >> 32);
+ ovlp.hEvent = NULL;
+
+ povlp = &ovlp;
+
+ if (ReadFile(file->fd, buf, size, &n, povlp) == 0) {
+ err = ngx_errno;
+
+ if (err == ERROR_HANDLE_EOF) {
+ return 0;
+ }
+
+ ngx_log_error(NGX_LOG_ERR, file->log, err,
+ "ReadFile() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ file->offset += n;
+
+ return n;
+}
+
+
+ssize_t
+ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
+{
+ u_long n;
+ OVERLAPPED ovlp, *povlp;
+
+ ovlp.Internal = 0;
+ ovlp.InternalHigh = 0;
+ ovlp.Offset = (u_long) offset;
+ ovlp.OffsetHigh = (u_long) (offset >> 32);
+ ovlp.hEvent = NULL;
+
+ povlp = &ovlp;
+
+ if (WriteFile(file->fd, buf, size, &n, povlp) == 0) {
+ ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno,
+ "WriteFile() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ if (n != size) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, 0,
+ "WriteFile() \"%s\" has written only %ul of %uz",
+ file->name.data, n, size);
+ return NGX_ERROR;
+ }
+
+ file->offset += n;
+
+ return n;
+}
+
+
+ssize_t
+ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
+ ngx_pool_t *pool)
+{
+ u_char *buf, *prev;
+ size_t size;
+ ssize_t total, n;
+
+ total = 0;
+
+ while (cl) {
+ buf = cl->buf->pos;
+ prev = buf;
+ size = 0;
+
+ /* coalesce the neighbouring bufs */
+
+ while (cl && prev == cl->buf->pos) {
+ size += cl->buf->last - cl->buf->pos;
+ prev = cl->buf->last;
+ cl = cl->next;
+ }
+
+ n = ngx_write_file(file, buf, size, offset);
+
+ if (n == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ total += n;
+ offset += n;
+ }
+
+ return total;
+}
+
+
+ssize_t
+ngx_read_fd(ngx_fd_t fd, void *buf, size_t size)
+{
+ u_long n;
+
+ if (ReadFile(fd, buf, size, &n, NULL) != 0) {
+ return (size_t) n;
+ }
+
+ return -1;
+}
+
+
+ssize_t
+ngx_write_fd(ngx_fd_t fd, void *buf, size_t size)
+{
+ u_long n;
+
+ if (WriteFile(fd, buf, size, &n, NULL) != 0) {
+ return (size_t) n;
+ }
+
+ return -1;
+}
+
+
+ssize_t
+ngx_write_console(ngx_fd_t fd, void *buf, size_t size)
+{
+ u_long n;
+
+ (void) CharToOemBuff(buf, buf, size);
+
+ if (WriteFile(fd, buf, size, &n, NULL) != 0) {
+ return (size_t) n;
+ }
+
+ return -1;
+}
+
+
+ngx_err_t
+ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log)
+{
+ u_char *name;
+ ngx_err_t err;
+ ngx_uint_t collision;
+ ngx_atomic_uint_t num;
+
+ name = ngx_alloc(to->len + 1 + NGX_ATOMIC_T_LEN + 1 + sizeof("DELETE"),
+ log);
+ if (name == NULL) {
+ return NGX_ENOMEM;
+ }
+
+ ngx_memcpy(name, to->data, to->len);
+
+ collision = 0;
+
+ /* mutex_lock() (per cache or single ?) */
+
+ for ( ;; ) {
+ num = ngx_next_temp_number(collision);
+
+ ngx_sprintf(name + to->len, ".%0muA.DELETE%Z", num);
+
+ if (MoveFile((const char *) to->data, (const char *) name) != 0) {
+ break;
+ }
+
+ collision = 1;
+
+ ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+ "MoveFile() \"%s\" to \"%s\" failed", to->data, name);
+ }
+
+ if (MoveFile((const char *) from->data, (const char *) to->data) == 0) {
+ err = ngx_errno;
+
+ } else {
+ err = 0;
+ }
+
+ if (DeleteFile((const char *) name) == 0) {
+ ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+ "DeleteFile() \"%s\" failed", name);
+ }
+
+ /* mutex_unlock() */
+
+ ngx_free(name);
+
+ return err;
+}
+
+
+ngx_int_t
+ngx_file_info(u_char *file, ngx_file_info_t *sb)
+{
+ size_t len;
+ long rc;
+ u_short *u;
+ ngx_err_t err;
+ WIN32_FILE_ATTRIBUTE_DATA fa;
+ u_short utf16[NGX_UTF16_BUFLEN];
+
+ len = NGX_UTF16_BUFLEN;
+
+ u = ngx_utf8_to_utf16(utf16, file, &len);
+
+ if (u == NULL) {
+ return NGX_FILE_ERROR;
+ }
+
+ rc = NGX_FILE_ERROR;
+
+ if (ngx_win32_check_filename(file, u, len) != NGX_OK) {
+ goto failed;
+ }
+
+ rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa);
+
+ sb->dwFileAttributes = fa.dwFileAttributes;
+ sb->ftCreationTime = fa.ftCreationTime;
+ sb->ftLastAccessTime = fa.ftLastAccessTime;
+ sb->ftLastWriteTime = fa.ftLastWriteTime;
+ sb->nFileSizeHigh = fa.nFileSizeHigh;
+ sb->nFileSizeLow = fa.nFileSizeLow;
+
+failed:
+
+ if (u != utf16) {
+ err = ngx_errno;
+ ngx_free(u);
+ ngx_set_errno(err);
+ }
+
+ return rc;
+}
+
+
+ngx_int_t
+ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s)
+{
+ uint64_t intervals;
+ FILETIME ft;
+
+ /* 116444736000000000 is commented in src/os/win32/ngx_time.c */
+
+ intervals = s * 10000000 + 116444736000000000;
+
+ ft.dwLowDateTime = (DWORD) intervals;
+ ft.dwHighDateTime = (DWORD) (intervals >> 32);
+
+ if (SetFileTime(fd, NULL, NULL, &ft) != 0) {
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_create_file_mapping(ngx_file_mapping_t *fm)
+{
+ LARGE_INTEGER size;
+
+ fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
+ NGX_FILE_DEFAULT_ACCESS);
+ if (fm->fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", fm->name);
+ return NGX_ERROR;
+ }
+
+ fm->handle = NULL;
+
+ size.QuadPart = fm->size;
+
+ if (SetFilePointerEx(fm->fd, size, NULL, FILE_BEGIN) == 0) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "SetFilePointerEx(\"%s\", %uz) failed",
+ fm->name, fm->size);
+ goto failed;
+ }
+
+ if (SetEndOfFile(fm->fd) == 0) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "SetEndOfFile() \"%s\" failed", fm->name);
+ goto failed;
+ }
+
+ fm->handle = CreateFileMapping(fm->fd, NULL, PAGE_READWRITE,
+ (u_long) ((off_t) fm->size >> 32),
+ (u_long) ((off_t) fm->size & 0xffffffff),
+ NULL);
+ if (fm->handle == NULL) {
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "CreateFileMapping(%s, %uz) failed",
+ fm->name, fm->size);
+ goto failed;
+ }
+
+ fm->addr = MapViewOfFile(fm->handle, FILE_MAP_WRITE, 0, 0, 0);
+
+ if (fm->addr != NULL) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
+ "MapViewOfFile(%uz) of file mapping \"%s\" failed",
+ fm->size, fm->name);
+
+failed:
+
+ if (fm->handle) {
+ if (CloseHandle(fm->handle) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ "CloseHandle() of file mapping \"%s\" failed",
+ fm->name);
+ }
+ }
+
+ if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", fm->name);
+ }
+
+ return NGX_ERROR;
+}
+
+
+void
+ngx_close_file_mapping(ngx_file_mapping_t *fm)
+{
+ if (UnmapViewOfFile(fm->addr) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ "UnmapViewOfFile(%p) of file mapping \"%s\" failed",
+ fm->addr, &fm->name);
+ }
+
+ if (CloseHandle(fm->handle) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ "CloseHandle() of file mapping \"%s\" failed",
+ &fm->name);
+ }
+
+ if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", fm->name);
+ }
+}
+
+
+u_char *
+ngx_realpath(u_char *path, u_char *resolved)
+{
+ /* STUB */
+ return path;
+}
+
+
+ngx_int_t
+ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir)
+{
+ ngx_cpystrn(name->data + name->len, NGX_DIR_MASK, NGX_DIR_MASK_LEN + 1);
+
+ dir->dir = FindFirstFile((const char *) name->data, &dir->finddata);
+
+ name->data[name->len] = '\0';
+
+ if (dir->dir == INVALID_HANDLE_VALUE) {
+ return NGX_ERROR;
+ }
+
+ dir->valid_info = 1;
+ dir->ready = 1;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_read_dir(ngx_dir_t *dir)
+{
+ if (dir->ready) {
+ dir->ready = 0;
+ return NGX_OK;
+ }
+
+ if (FindNextFile(dir->dir, &dir->finddata) != 0) {
+ dir->type = 1;
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_close_dir(ngx_dir_t *dir)
+{
+ if (FindClose(dir->dir) == 0) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_open_glob(ngx_glob_t *gl)
+{
+ u_char *p;
+ size_t len;
+ ngx_err_t err;
+
+ gl->dir = FindFirstFile((const char *) gl->pattern, &gl->finddata);
+
+ if (gl->dir == INVALID_HANDLE_VALUE) {
+
+ err = ngx_errno;
+
+ if ((err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+ && gl->test)
+ {
+ gl->no_match = 1;
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+ }
+
+ for (p = gl->pattern; *p; p++) {
+ if (*p == '/') {
+ gl->last = p + 1 - gl->pattern;
+ }
+ }
+
+ len = ngx_strlen(gl->finddata.cFileName);
+ gl->name.len = gl->last + len;
+
+ gl->name.data = ngx_alloc(gl->name.len + 1, gl->log);
+ if (gl->name.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(gl->name.data, gl->pattern, gl->last);
+ ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName,
+ len + 1);
+
+ gl->ready = 1;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name)
+{
+ size_t len;
+ ngx_err_t err;
+
+ if (gl->no_match) {
+ return NGX_DONE;
+ }
+
+ if (gl->ready) {
+ *name = gl->name;
+
+ gl->ready = 0;
+ return NGX_OK;
+ }
+
+ ngx_free(gl->name.data);
+ gl->name.data = NULL;
+
+ if (FindNextFile(gl->dir, &gl->finddata) != 0) {
+
+ len = ngx_strlen(gl->finddata.cFileName);
+ gl->name.len = gl->last + len;
+
+ gl->name.data = ngx_alloc(gl->name.len + 1, gl->log);
+ if (gl->name.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(gl->name.data, gl->pattern, gl->last);
+ ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName,
+ len + 1);
+
+ *name = gl->name;
+
+ return NGX_OK;
+ }
+
+ err = ngx_errno;
+
+ if (err == NGX_ENOMOREFILES) {
+ return NGX_DONE;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, gl->log, err,
+ "FindNextFile(%s) failed", gl->pattern);
+
+ return NGX_ERROR;
+}
+
+
+void
+ngx_close_glob(ngx_glob_t *gl)
+{
+ if (gl->name.data) {
+ ngx_free(gl->name.data);
+ }
+
+ if (gl->dir == INVALID_HANDLE_VALUE) {
+ return;
+ }
+
+ if (FindClose(gl->dir) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, gl->log, ngx_errno,
+ "FindClose(%s) failed", gl->pattern);
+ }
+}
+
+
+ngx_int_t
+ngx_de_info(u_char *name, ngx_dir_t *dir)
+{
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_de_link_info(u_char *name, ngx_dir_t *dir)
+{
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_read_ahead(ngx_fd_t fd, size_t n)
+{
+ return ~NGX_FILE_ERROR;
+}
+
+
+ngx_int_t
+ngx_directio_on(ngx_fd_t fd)
+{
+ return ~NGX_FILE_ERROR;
+}
+
+
+ngx_int_t
+ngx_directio_off(ngx_fd_t fd)
+{
+ return ~NGX_FILE_ERROR;
+}
+
+
+size_t
+ngx_fs_bsize(u_char *name)
+{
+ u_char root[4];
+ u_long sc, bs, nfree, ncl;
+
+ if (name[2] == ':') {
+ ngx_cpystrn(root, name, 4);
+ name = root;
+ }
+
+ if (GetDiskFreeSpace((const char *) name, &sc, &bs, &nfree, &ncl) == 0) {
+ return 512;
+ }
+
+ return sc * bs;
+}
+
+
+static ngx_int_t
+ngx_win32_check_filename(u_char *name, u_short *u, size_t len)
+{
+ u_char *p, ch;
+ u_long n;
+ u_short *lu;
+ ngx_err_t err;
+ enum {
+ sw_start = 0,
+ sw_normal,
+ sw_after_slash,
+ sw_after_colon,
+ sw_after_dot
+ } state;
+
+ /* check for NTFS streams (":"), trailing dots and spaces */
+
+ lu = NULL;
+ state = sw_start;
+
+ for (p = name; *p; p++) {
+ ch = *p;
+
+ switch (state) {
+
+ case sw_start:
+
+ /*
+ * skip till first "/" to allow paths starting with drive and
+ * relative path, like "c:html/"
+ */
+
+ if (ch == '/' || ch == '\\') {
+ state = sw_after_slash;
+ }
+
+ break;
+
+ case sw_normal:
+
+ if (ch == ':') {
+ state = sw_after_colon;
+ break;
+ }
+
+ if (ch == '.' || ch == ' ') {
+ state = sw_after_dot;
+ break;
+ }
+
+ if (ch == '/' || ch == '\\') {
+ state = sw_after_slash;
+ break;
+ }
+
+ break;
+
+ case sw_after_slash:
+
+ if (ch == '/' || ch == '\\') {
+ break;
+ }
+
+ if (ch == '.') {
+ break;
+ }
+
+ if (ch == ':') {
+ state = sw_after_colon;
+ break;
+ }
+
+ state = sw_normal;
+ break;
+
+ case sw_after_colon:
+
+ if (ch == '/' || ch == '\\') {
+ state = sw_after_slash;
+ break;
+ }
+
+ goto invalid;
+
+ case sw_after_dot:
+
+ if (ch == '/' || ch == '\\') {
+ goto invalid;
+ }
+
+ if (ch == ':') {
+ goto invalid;
+ }
+
+ if (ch == '.' || ch == ' ') {
+ break;
+ }
+
+ state = sw_normal;
+ break;
+ }
+ }
+
+ if (state == sw_after_dot) {
+ goto invalid;
+ }
+
+ /* check if long name match */
+
+ lu = malloc(len * 2);
+ if (lu == NULL) {
+ return NGX_ERROR;
+ }
+
+ n = GetLongPathNameW(u, lu, len);
+
+ if (n == 0) {
+ goto failed;
+ }
+
+ if (n != len - 1 || _wcsicmp(u, lu) != 0) {
+ goto invalid;
+ }
+
+ ngx_free(lu);
+
+ return NGX_OK;
+
+invalid:
+
+ ngx_set_errno(NGX_ENOENT);
+
+failed:
+
+ if (lu) {
+ err = ngx_errno;
+ ngx_free(lu);
+ ngx_set_errno(err);
+ }
+
+ return NGX_ERROR;
+}
+
+
+static u_short *
+ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len)
+{
+ u_char *p;
+ u_short *u, *last;
+ uint32_t n;
+
+ p = utf8;
+ u = utf16;
+ last = utf16 + *len;
+
+ while (u < last) {
+
+ if (*p < 0x80) {
+ *u++ = (u_short) *p;
+
+ if (*p == 0) {
+ *len = u - utf16;
+ return utf16;
+ }
+
+ p++;
+
+ continue;
+ }
+
+ if (u + 1 == last) {
+ *len = u - utf16;
+ break;
+ }
+
+ n = ngx_utf8_decode(&p, 4);
+
+ if (n > 0x10ffff) {
+ ngx_set_errno(NGX_EILSEQ);
+ return NULL;
+ }
+
+ if (n > 0xffff) {
+ n -= 0x10000;
+ *u++ = (u_short) (0xd800 + (n >> 10));
+ *u++ = (u_short) (0xdc00 + (n & 0x03ff));
+ continue;
+ }
+
+ *u++ = (u_short) n;
+ }
+
+ /* the given buffer is not enough, allocate a new one */
+
+ u = malloc(((p - utf8) + ngx_strlen(p) + 1) * sizeof(u_short));
+ if (u == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(u, utf16, *len * 2);
+
+ utf16 = u;
+ u += *len;
+
+ for ( ;; ) {
+
+ if (*p < 0x80) {
+ *u++ = (u_short) *p;
+
+ if (*p == 0) {
+ *len = u - utf16;
+ return utf16;
+ }
+
+ p++;
+
+ continue;
+ }
+
+ n = ngx_utf8_decode(&p, 4);
+
+ if (n > 0x10ffff) {
+ ngx_free(utf16);
+ ngx_set_errno(NGX_EILSEQ);
+ return NULL;
+ }
+
+ if (n > 0xffff) {
+ n -= 0x10000;
+ *u++ = (u_short) (0xd800 + (n >> 10));
+ *u++ = (u_short) (0xdc00 + (n & 0x03ff));
+ continue;
+ }
+
+ *u++ = (u_short) n;
+ }
+
+ /* unreachable */
+}
diff --git a/app/nginx/src/os/win32/ngx_files.h b/app/nginx/src/os/win32/ngx_files.h
new file mode 100644
index 0000000..895daea
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_files.h
@@ -0,0 +1,273 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_FILES_H_INCLUDED_
+#define _NGX_FILES_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef HANDLE ngx_fd_t;
+typedef BY_HANDLE_FILE_INFORMATION ngx_file_info_t;
+typedef uint64_t ngx_file_uniq_t;
+
+
+typedef struct {
+ u_char *name;
+ size_t size;
+ void *addr;
+ ngx_fd_t fd;
+ HANDLE handle;
+ ngx_log_t *log;
+} ngx_file_mapping_t;
+
+
+typedef struct {
+ HANDLE dir;
+ WIN32_FIND_DATA finddata;
+
+ unsigned valid_info:1;
+ unsigned type:1;
+ unsigned ready:1;
+} ngx_dir_t;
+
+
+typedef struct {
+ HANDLE dir;
+ WIN32_FIND_DATA finddata;
+
+ unsigned ready:1;
+ unsigned test:1;
+ unsigned no_match:1;
+
+ u_char *pattern;
+ ngx_str_t name;
+ size_t last;
+ ngx_log_t *log;
+} ngx_glob_t;
+
+
+
+/* INVALID_FILE_ATTRIBUTES is specified but not defined at least in MSVC6SP2 */
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES 0xffffffff
+#endif
+
+/* INVALID_SET_FILE_POINTER is not defined at least in MSVC6SP2 */
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xffffffff
+#endif
+
+
+#define NGX_INVALID_FILE INVALID_HANDLE_VALUE
+#define NGX_FILE_ERROR 0
+
+
+ngx_fd_t ngx_open_file(u_char *name, u_long mode, u_long create, u_long access);
+#define ngx_open_file_n "CreateFile()"
+
+#define NGX_FILE_RDONLY GENERIC_READ
+#define NGX_FILE_WRONLY GENERIC_WRITE
+#define NGX_FILE_RDWR GENERIC_READ|GENERIC_WRITE
+#define NGX_FILE_APPEND FILE_APPEND_DATA|SYNCHRONIZE
+#define NGX_FILE_NONBLOCK 0
+
+#define NGX_FILE_CREATE_OR_OPEN OPEN_ALWAYS
+#define NGX_FILE_OPEN OPEN_EXISTING
+#define NGX_FILE_TRUNCATE CREATE_ALWAYS
+
+#define NGX_FILE_DEFAULT_ACCESS 0
+#define NGX_FILE_OWNER_ACCESS 0
+
+
+#define ngx_open_tempfile(name, persistent, access) \
+ CreateFile((const char *) name, \
+ GENERIC_READ|GENERIC_WRITE, \
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, \
+ NULL, \
+ CREATE_NEW, \
+ persistent ? 0: \
+ FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, \
+ NULL);
+
+#define ngx_open_tempfile_n "CreateFile()"
+
+
+#define ngx_close_file CloseHandle
+#define ngx_close_file_n "CloseHandle()"
+
+
+ssize_t ngx_read_fd(ngx_fd_t fd, void *buf, size_t size);
+#define ngx_read_fd_n "ReadFile()"
+
+
+ssize_t ngx_write_fd(ngx_fd_t fd, void *buf, size_t size);
+#define ngx_write_fd_n "WriteFile()"
+
+
+ssize_t ngx_write_console(ngx_fd_t fd, void *buf, size_t size);
+
+
+#define ngx_linefeed(p) *p++ = CR; *p++ = LF;
+#define NGX_LINEFEED_SIZE 2
+#define NGX_LINEFEED CRLF
+
+
+#define ngx_delete_file(name) DeleteFile((const char *) name)
+#define ngx_delete_file_n "DeleteFile()"
+
+
+#define ngx_rename_file(o, n) MoveFile((const char *) o, (const char *) n)
+#define ngx_rename_file_n "MoveFile()"
+ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log);
+
+
+
+ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s);
+#define ngx_set_file_time_n "SetFileTime()"
+
+
+ngx_int_t ngx_file_info(u_char *filename, ngx_file_info_t *fi);
+#define ngx_file_info_n "GetFileAttributesEx()"
+
+
+#define ngx_fd_info(fd, fi) GetFileInformationByHandle(fd, fi)
+#define ngx_fd_info_n "GetFileInformationByHandle()"
+
+
+#define ngx_link_info(name, fi) ngx_file_info(name, fi)
+#define ngx_link_info_n "GetFileAttributesEx()"
+
+
+#define ngx_is_dir(fi) \
+ (((fi)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+#define ngx_is_file(fi) \
+ (((fi)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+#define ngx_is_link(fi) 0
+#define ngx_is_exec(fi) 0
+
+#define ngx_file_access(fi) 0
+
+#define ngx_file_size(fi) \
+ (((off_t) (fi)->nFileSizeHigh << 32) | (fi)->nFileSizeLow)
+#define ngx_file_fs_size(fi) ngx_file_size(fi)
+
+#define ngx_file_uniq(fi) (*(ngx_file_uniq_t *) &(fi)->nFileIndexHigh)
+
+
+/* 116444736000000000 is commented in src/os/win32/ngx_time.c */
+
+#define ngx_file_mtime(fi) \
+ (time_t) (((((unsigned __int64) (fi)->ftLastWriteTime.dwHighDateTime << 32) \
+ | (fi)->ftLastWriteTime.dwLowDateTime) \
+ - 116444736000000000) / 10000000)
+
+ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm);
+void ngx_close_file_mapping(ngx_file_mapping_t *fm);
+
+
+u_char *ngx_realpath(u_char *path, u_char *resolved);
+#define ngx_realpath_n ""
+#define ngx_getcwd(buf, size) GetCurrentDirectory(size, (char *) buf)
+#define ngx_getcwd_n "GetCurrentDirectory()"
+#define ngx_path_separator(c) ((c) == '/' || (c) == '\\')
+
+#define NGX_HAVE_MAX_PATH 1
+#define NGX_MAX_PATH MAX_PATH
+
+#define NGX_DIR_MASK (u_char *) "/*"
+#define NGX_DIR_MASK_LEN 2
+
+
+ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir);
+#define ngx_open_dir_n "FindFirstFile()"
+
+
+ngx_int_t ngx_read_dir(ngx_dir_t *dir);
+#define ngx_read_dir_n "FindNextFile()"
+
+
+ngx_int_t ngx_close_dir(ngx_dir_t *dir);
+#define ngx_close_dir_n "FindClose()"
+
+
+#define ngx_create_dir(name, access) CreateDirectory((const char *) name, NULL)
+#define ngx_create_dir_n "CreateDirectory()"
+
+
+#define ngx_delete_dir(name) RemoveDirectory((const char *) name)
+#define ngx_delete_dir_n "RemoveDirectory()"
+
+
+#define ngx_dir_access(a) (a)
+
+
+#define ngx_de_name(dir) ((u_char *) (dir)->finddata.cFileName)
+#define ngx_de_namelen(dir) ngx_strlen((dir)->finddata.cFileName)
+
+ngx_int_t ngx_de_info(u_char *name, ngx_dir_t *dir);
+#define ngx_de_info_n "dummy()"
+
+ngx_int_t ngx_de_link_info(u_char *name, ngx_dir_t *dir);
+#define ngx_de_link_info_n "dummy()"
+
+#define ngx_de_is_dir(dir) \
+ (((dir)->finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+#define ngx_de_is_file(dir) \
+ (((dir)->finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+#define ngx_de_is_link(dir) 0
+#define ngx_de_access(dir) 0
+#define ngx_de_size(dir) \
+ (((off_t) (dir)->finddata.nFileSizeHigh << 32) | (dir)->finddata.nFileSizeLow)
+#define ngx_de_fs_size(dir) ngx_de_size(dir)
+
+/* 116444736000000000 is commented in src/os/win32/ngx_time.c */
+
+#define ngx_de_mtime(dir) \
+ (time_t) (((((unsigned __int64) \
+ (dir)->finddata.ftLastWriteTime.dwHighDateTime << 32) \
+ | (dir)->finddata.ftLastWriteTime.dwLowDateTime) \
+ - 116444736000000000) / 10000000)
+
+
+ngx_int_t ngx_open_glob(ngx_glob_t *gl);
+#define ngx_open_glob_n "FindFirstFile()"
+
+ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name);
+void ngx_close_glob(ngx_glob_t *gl);
+
+
+ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset);
+#define ngx_read_file_n "ReadFile()"
+
+ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size,
+ off_t offset);
+
+ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce,
+ off_t offset, ngx_pool_t *pool);
+
+ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n);
+#define ngx_read_ahead_n "ngx_read_ahead_n"
+
+ngx_int_t ngx_directio_on(ngx_fd_t fd);
+#define ngx_directio_on_n "ngx_directio_on_n"
+
+ngx_int_t ngx_directio_off(ngx_fd_t fd);
+#define ngx_directio_off_n "ngx_directio_off_n"
+
+size_t ngx_fs_bsize(u_char *name);
+
+
+#define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE)
+#define ngx_stderr GetStdHandle(STD_ERROR_HANDLE)
+#define ngx_set_stderr(fd) SetStdHandle(STD_ERROR_HANDLE, fd)
+#define ngx_set_stderr_n "SetStdHandle(STD_ERROR_HANDLE)"
+
+
+#endif /* _NGX_FILES_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_os.h b/app/nginx/src/os/win32/ngx_os.h
new file mode 100644
index 0000000..15f5aa0
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_os.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_OS_H_INCLUDED_
+#define _NGX_OS_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_IO_SENDFILE 1
+
+
+typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);
+typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size);
+typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+typedef struct {
+ ngx_recv_pt recv;
+ ngx_recv_chain_pt recv_chain;
+ ngx_recv_pt udp_recv;
+ ngx_send_pt send;
+ ngx_send_pt udp_send;
+ ngx_send_chain_pt udp_send_chain;
+ ngx_send_chain_pt send_chain;
+ ngx_uint_t flags;
+} ngx_os_io_t;
+
+
+ngx_int_t ngx_os_init(ngx_log_t *log);
+void ngx_os_status(ngx_log_t *log);
+ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid);
+
+ssize_t ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_udp_wsarecv(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf,
+ size_t size);
+ssize_t ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit);
+ssize_t ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size);
+ssize_t ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size);
+ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+ngx_chain_t *ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
+
+void ngx_cdecl ngx_event_log(ngx_err_t err, const char *fmt, ...);
+
+
+extern ngx_os_io_t ngx_os_io;
+extern ngx_uint_t ngx_ncpu;
+extern ngx_uint_t ngx_max_wsabufs;
+extern ngx_int_t ngx_max_sockets;
+extern ngx_uint_t ngx_inherited_nonblocking;
+extern ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush;
+extern ngx_uint_t ngx_win32_version;
+extern char ngx_unique[];
+
+
+#endif /* _NGX_OS_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_process.c b/app/nginx/src/os/win32/ngx_process.c
new file mode 100644
index 0000000..57b1ae9
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_process.c
@@ -0,0 +1,238 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+int ngx_argc;
+char **ngx_argv;
+char **ngx_os_argv;
+
+ngx_int_t ngx_last_process;
+ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
+
+
+ngx_pid_t
+ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn)
+{
+ u_long rc, n, code;
+ ngx_int_t s;
+ ngx_pid_t pid;
+ ngx_exec_ctx_t ctx;
+ HANDLE events[2];
+ char file[MAX_PATH + 1];
+
+ if (respawn >= 0) {
+ s = respawn;
+
+ } else {
+ for (s = 0; s < ngx_last_process; s++) {
+ if (ngx_processes[s].handle == NULL) {
+ break;
+ }
+ }
+
+ if (s == NGX_MAX_PROCESSES) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "no more than %d processes can be spawned",
+ NGX_MAX_PROCESSES);
+ return NGX_INVALID_PID;
+ }
+ }
+
+ n = GetModuleFileName(NULL, file, MAX_PATH);
+
+ if (n == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "GetModuleFileName() failed");
+ return NGX_INVALID_PID;
+ }
+
+ file[n] = '\0';
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "GetModuleFileName: \"%s\"", file);
+
+ ctx.path = file;
+ ctx.name = name;
+ ctx.args = GetCommandLine();
+ ctx.argv = NULL;
+ ctx.envp = NULL;
+
+ pid = ngx_execute(cycle, &ctx);
+
+ if (pid == NGX_INVALID_PID) {
+ return pid;
+ }
+
+ ngx_memzero(&ngx_processes[s], sizeof(ngx_process_t));
+
+ ngx_processes[s].handle = ctx.child;
+ ngx_processes[s].pid = pid;
+ ngx_processes[s].name = name;
+
+ ngx_sprintf(ngx_processes[s].term_event, "ngx_%s_term_%P%Z", name, pid);
+ ngx_sprintf(ngx_processes[s].quit_event, "ngx_%s_quit_%P%Z", name, pid);
+ ngx_sprintf(ngx_processes[s].reopen_event, "ngx_%s_reopen_%P%Z",
+ name, pid);
+
+ events[0] = ngx_master_process_event;
+ events[1] = ctx.child;
+
+ rc = WaitForMultipleObjects(2, events, 0, 5000);
+
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "WaitForMultipleObjects: %ul", rc);
+
+ switch (rc) {
+
+ case WAIT_OBJECT_0:
+
+ ngx_processes[s].term = OpenEvent(EVENT_MODIFY_STATE, 0,
+ (char *) ngx_processes[s].term_event);
+ if (ngx_processes[s].term == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "OpenEvent(\"%s\") failed",
+ ngx_processes[s].term_event);
+ goto failed;
+ }
+
+ ngx_processes[s].quit = OpenEvent(EVENT_MODIFY_STATE, 0,
+ (char *) ngx_processes[s].quit_event);
+ if (ngx_processes[s].quit == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "OpenEvent(\"%s\") failed",
+ ngx_processes[s].quit_event);
+ goto failed;
+ }
+
+ ngx_processes[s].reopen = OpenEvent(EVENT_MODIFY_STATE, 0,
+ (char *) ngx_processes[s].reopen_event);
+ if (ngx_processes[s].reopen == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "OpenEvent(\"%s\") failed",
+ ngx_processes[s].reopen_event);
+ goto failed;
+ }
+
+ if (ResetEvent(ngx_master_process_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "ResetEvent(\"%s\") failed",
+ ngx_master_process_event_name);
+ goto failed;
+ }
+
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ if (GetExitCodeProcess(ctx.child, &code) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "GetExitCodeProcess(%P) failed", pid);
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "%s process %P exited with code %Xl",
+ name, pid, code);
+
+ goto failed;
+
+ case WAIT_TIMEOUT:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "the event \"%s\" was not signaled for 5s",
+ ngx_master_process_event_name);
+ goto failed;
+
+ case WAIT_FAILED:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "WaitForSingleObject(\"%s\") failed",
+ ngx_master_process_event_name);
+
+ goto failed;
+ }
+
+ if (respawn >= 0) {
+ return pid;
+ }
+
+ switch (respawn) {
+
+ case NGX_PROCESS_RESPAWN:
+ ngx_processes[s].just_spawn = 0;
+ break;
+
+ case NGX_PROCESS_JUST_RESPAWN:
+ ngx_processes[s].just_spawn = 1;
+ break;
+ }
+
+ if (s == ngx_last_process) {
+ ngx_last_process++;
+ }
+
+ return pid;
+
+failed:
+
+ if (ngx_processes[s].reopen) {
+ ngx_close_handle(ngx_processes[s].reopen);
+ }
+
+ if (ngx_processes[s].quit) {
+ ngx_close_handle(ngx_processes[s].quit);
+ }
+
+ if (ngx_processes[s].term) {
+ ngx_close_handle(ngx_processes[s].term);
+ }
+
+ TerminateProcess(ngx_processes[s].handle, 2);
+
+ if (ngx_processes[s].handle) {
+ ngx_close_handle(ngx_processes[s].handle);
+ ngx_processes[s].handle = NULL;
+ }
+
+ return NGX_INVALID_PID;
+}
+
+
+ngx_pid_t
+ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ ngx_memzero(&si, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+
+ ngx_memzero(&pi, sizeof(PROCESS_INFORMATION));
+
+ if (CreateProcess(ctx->path, ctx->args,
+ NULL, NULL, 0, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)
+ == 0)
+ {
+ ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno,
+ "CreateProcess(\"%s\") failed", ngx_argv[0]);
+
+ return 0;
+ }
+
+ ctx->child = pi.hProcess;
+
+ if (CloseHandle(pi.hThread) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CloseHandle(pi.hThread) failed");
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
+ "start %s process %P", ctx->name, pi.dwProcessId);
+
+ return pi.dwProcessId;
+}
diff --git a/app/nginx/src/os/win32/ngx_process.h b/app/nginx/src/os/win32/ngx_process.h
new file mode 100644
index 0000000..a6a5aa2
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_process.h
@@ -0,0 +1,78 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PROCESS_H_INCLUDED_
+#define _NGX_PROCESS_H_INCLUDED_
+
+
+typedef DWORD ngx_pid_t;
+#define NGX_INVALID_PID 0
+
+
+#define ngx_getpid GetCurrentProcessId
+#define ngx_log_pid ngx_pid
+
+
+#define NGX_PROCESS_SYNC_NAME \
+ (sizeof("ngx_cache_manager_mutex_") + NGX_INT32_LEN)
+
+
+typedef uint64_t ngx_cpuset_t;
+
+
+typedef struct {
+ HANDLE handle;
+ ngx_pid_t pid;
+ char *name;
+
+ HANDLE term;
+ HANDLE quit;
+ HANDLE reopen;
+
+ u_char term_event[NGX_PROCESS_SYNC_NAME];
+ u_char quit_event[NGX_PROCESS_SYNC_NAME];
+ u_char reopen_event[NGX_PROCESS_SYNC_NAME];
+
+ unsigned just_spawn:1;
+ unsigned exiting:1;
+} ngx_process_t;
+
+
+typedef struct {
+ char *path;
+ char *name;
+ char *args;
+ char *const *argv;
+ char *const *envp;
+ HANDLE child;
+} ngx_exec_ctx_t;
+
+
+ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn);
+ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx);
+
+#define ngx_debug_point()
+#define ngx_sched_yield() SwitchToThread()
+
+
+#define NGX_MAX_PROCESSES (MAXIMUM_WAIT_OBJECTS - 4)
+
+#define NGX_PROCESS_RESPAWN -2
+#define NGX_PROCESS_JUST_RESPAWN -3
+
+
+extern int ngx_argc;
+extern char **ngx_argv;
+extern char **ngx_os_argv;
+
+extern ngx_int_t ngx_last_process;
+extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
+
+extern ngx_pid_t ngx_pid;
+
+
+#endif /* _NGX_PROCESS_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_process_cycle.c b/app/nginx/src/os/win32/ngx_process_cycle.c
new file mode 100644
index 0000000..293b967
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_process_cycle.c
@@ -0,0 +1,1042 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <nginx.h>
+
+
+static void ngx_console_init(ngx_cycle_t *cycle);
+static int __stdcall ngx_console_handler(u_long type);
+static ngx_int_t ngx_create_signal_events(ngx_cycle_t *cycle);
+static ngx_int_t ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type);
+static void ngx_reopen_worker_processes(ngx_cycle_t *cycle);
+static void ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old);
+static void ngx_terminate_worker_processes(ngx_cycle_t *cycle);
+static ngx_uint_t ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h);
+static void ngx_master_process_exit(ngx_cycle_t *cycle);
+static void ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn);
+static void ngx_worker_process_exit(ngx_cycle_t *cycle);
+static ngx_thread_value_t __stdcall ngx_worker_thread(void *data);
+static ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data);
+static void ngx_cache_manager_process_handler(void);
+static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data);
+
+
+ngx_uint_t ngx_process;
+ngx_uint_t ngx_worker;
+ngx_pid_t ngx_pid;
+
+ngx_uint_t ngx_inherited;
+ngx_pid_t ngx_new_binary;
+
+sig_atomic_t ngx_terminate;
+sig_atomic_t ngx_quit;
+sig_atomic_t ngx_reopen;
+sig_atomic_t ngx_reconfigure;
+ngx_uint_t ngx_exiting;
+
+
+HANDLE ngx_master_process_event;
+char ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME];
+
+static HANDLE ngx_stop_event;
+static char ngx_stop_event_name[NGX_PROCESS_SYNC_NAME];
+static HANDLE ngx_quit_event;
+static char ngx_quit_event_name[NGX_PROCESS_SYNC_NAME];
+static HANDLE ngx_reopen_event;
+static char ngx_reopen_event_name[NGX_PROCESS_SYNC_NAME];
+static HANDLE ngx_reload_event;
+static char ngx_reload_event_name[NGX_PROCESS_SYNC_NAME];
+
+HANDLE ngx_cache_manager_mutex;
+char ngx_cache_manager_mutex_name[NGX_PROCESS_SYNC_NAME];
+HANDLE ngx_cache_manager_event;
+
+
+void
+ngx_master_process_cycle(ngx_cycle_t *cycle)
+{
+ u_long nev, ev, timeout;
+ ngx_err_t err;
+ ngx_int_t n;
+ ngx_msec_t timer;
+ ngx_uint_t live;
+ HANDLE events[MAXIMUM_WAIT_OBJECTS];
+
+ ngx_sprintf((u_char *) ngx_master_process_event_name,
+ "ngx_master_%s%Z", ngx_unique);
+
+ if (ngx_process == NGX_PROCESS_WORKER) {
+ ngx_worker_process_cycle(cycle, ngx_master_process_event_name);
+ return;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master started");
+
+ ngx_console_init(cycle);
+
+ SetEnvironmentVariable("ngx_unique", ngx_unique);
+
+ ngx_master_process_event = CreateEvent(NULL, 1, 0,
+ ngx_master_process_event_name);
+ if (ngx_master_process_event == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateEvent(\"%s\") failed",
+ ngx_master_process_event_name);
+ exit(2);
+ }
+
+ if (ngx_create_signal_events(cycle) != NGX_OK) {
+ exit(2);
+ }
+
+ ngx_sprintf((u_char *) ngx_cache_manager_mutex_name,
+ "ngx_cache_manager_mutex_%s%Z", ngx_unique);
+
+ ngx_cache_manager_mutex = CreateMutex(NULL, 0,
+ ngx_cache_manager_mutex_name);
+ if (ngx_cache_manager_mutex == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateMutex(\"%s\") failed", ngx_cache_manager_mutex_name);
+ exit(2);
+ }
+
+
+ events[0] = ngx_stop_event;
+ events[1] = ngx_quit_event;
+ events[2] = ngx_reopen_event;
+ events[3] = ngx_reload_event;
+
+ ngx_close_listening_sockets(cycle);
+
+ if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) {
+ exit(2);
+ }
+
+ timer = 0;
+ timeout = INFINITE;
+
+ for ( ;; ) {
+
+ nev = 4;
+ for (n = 0; n < ngx_last_process; n++) {
+ if (ngx_processes[n].handle) {
+ events[nev++] = ngx_processes[n].handle;
+ }
+ }
+
+ if (timer) {
+ timeout = timer > ngx_current_msec ? timer - ngx_current_msec : 0;
+ }
+
+ ev = WaitForMultipleObjects(nev, events, 0, timeout);
+
+ err = ngx_errno;
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "master WaitForMultipleObjects: %ul", ev);
+
+ if (ev == WAIT_OBJECT_0) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+
+ if (ResetEvent(ngx_stop_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "ResetEvent(\"%s\") failed", ngx_stop_event_name);
+ }
+
+ if (timer == 0) {
+ timer = ngx_current_msec + 5000;
+ }
+
+ ngx_terminate = 1;
+ ngx_quit_worker_processes(cycle, 0);
+
+ continue;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 1) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "shutting down");
+
+ if (ResetEvent(ngx_quit_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "ResetEvent(\"%s\") failed", ngx_quit_event_name);
+ }
+
+ ngx_quit = 1;
+ ngx_quit_worker_processes(cycle, 0);
+
+ continue;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 2) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
+
+ if (ResetEvent(ngx_reopen_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "ResetEvent(\"%s\") failed",
+ ngx_reopen_event_name);
+ }
+
+ ngx_reopen_files(cycle, -1);
+ ngx_reopen_worker_processes(cycle);
+
+ continue;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 3) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
+
+ if (ResetEvent(ngx_reload_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "ResetEvent(\"%s\") failed",
+ ngx_reload_event_name);
+ }
+
+ cycle = ngx_init_cycle(cycle);
+ if (cycle == NULL) {
+ cycle = (ngx_cycle_t *) ngx_cycle;
+ continue;
+ }
+
+ ngx_cycle = cycle;
+
+ ngx_close_listening_sockets(cycle);
+
+ if (ngx_start_worker_processes(cycle, NGX_PROCESS_JUST_RESPAWN)) {
+ ngx_quit_worker_processes(cycle, 1);
+ }
+
+ continue;
+ }
+
+ if (ev > WAIT_OBJECT_0 + 3 && ev < WAIT_OBJECT_0 + nev) {
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "reap worker");
+
+ live = ngx_reap_worker(cycle, events[ev]);
+
+ if (!live && (ngx_terminate || ngx_quit)) {
+ ngx_master_process_exit(cycle);
+ }
+
+ continue;
+ }
+
+ if (ev == WAIT_TIMEOUT) {
+ ngx_terminate_worker_processes(cycle);
+
+ ngx_master_process_exit(cycle);
+ }
+
+ if (ev == WAIT_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "WaitForMultipleObjects() failed");
+
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "WaitForMultipleObjects() returned unexpected value %ul", ev);
+ }
+}
+
+
+static void
+ngx_console_init(ngx_cycle_t *cycle)
+{
+ ngx_core_conf_t *ccf;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ if (ccf->daemon) {
+ if (FreeConsole() == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "FreeConsole() failed");
+ }
+
+ return;
+ }
+
+ if (SetConsoleCtrlHandler(ngx_console_handler, 1) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "SetConsoleCtrlHandler() failed");
+ }
+}
+
+
+static int __stdcall
+ngx_console_handler(u_long type)
+{
+ char *msg;
+
+ switch (type) {
+
+ case CTRL_C_EVENT:
+ msg = "Ctrl-C pressed, exiting";
+ break;
+
+ case CTRL_BREAK_EVENT:
+ msg = "Ctrl-Break pressed, exiting";
+ break;
+
+ case CTRL_CLOSE_EVENT:
+ msg = "console closing, exiting";
+ break;
+
+ case CTRL_LOGOFF_EVENT:
+ msg = "user logs off, exiting";
+ break;
+
+ default:
+ return 0;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, msg);
+
+ if (ngx_stop_event == NULL) {
+ return 1;
+ }
+
+ if (SetEvent(ngx_stop_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "SetEvent(\"%s\") failed", ngx_stop_event_name);
+ }
+
+ return 1;
+}
+
+
+static ngx_int_t
+ngx_create_signal_events(ngx_cycle_t *cycle)
+{
+ ngx_sprintf((u_char *) ngx_stop_event_name,
+ "Global\\ngx_stop_%s%Z", ngx_unique);
+
+ ngx_stop_event = CreateEvent(NULL, 1, 0, ngx_stop_event_name);
+ if (ngx_stop_event == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateEvent(\"%s\") failed", ngx_stop_event_name);
+ return NGX_ERROR;
+ }
+
+
+ ngx_sprintf((u_char *) ngx_quit_event_name,
+ "Global\\ngx_quit_%s%Z", ngx_unique);
+
+ ngx_quit_event = CreateEvent(NULL, 1, 0, ngx_quit_event_name);
+ if (ngx_quit_event == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateEvent(\"%s\") failed", ngx_quit_event_name);
+ return NGX_ERROR;
+ }
+
+
+ ngx_sprintf((u_char *) ngx_reopen_event_name,
+ "Global\\ngx_reopen_%s%Z", ngx_unique);
+
+ ngx_reopen_event = CreateEvent(NULL, 1, 0, ngx_reopen_event_name);
+ if (ngx_reopen_event == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateEvent(\"%s\") failed", ngx_reopen_event_name);
+ return NGX_ERROR;
+ }
+
+
+ ngx_sprintf((u_char *) ngx_reload_event_name,
+ "Global\\ngx_reload_%s%Z", ngx_unique);
+
+ ngx_reload_event = CreateEvent(NULL, 1, 0, ngx_reload_event_name);
+ if (ngx_reload_event == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateEvent(\"%s\") failed", ngx_reload_event_name);
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type)
+{
+ ngx_int_t n;
+ ngx_core_conf_t *ccf;
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ for (n = 0; n < ccf->worker_processes; n++) {
+ if (ngx_spawn_process(cycle, "worker", type) == NGX_INVALID_PID) {
+ break;
+ }
+ }
+
+ return n;
+}
+
+
+static void
+ngx_reopen_worker_processes(ngx_cycle_t *cycle)
+{
+ ngx_int_t n;
+
+ for (n = 0; n < ngx_last_process; n++) {
+
+ if (ngx_processes[n].handle == NULL) {
+ continue;
+ }
+
+ if (SetEvent(ngx_processes[n].reopen) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "SetEvent(\"%s\") failed",
+ ngx_processes[n].reopen_event);
+ }
+ }
+}
+
+
+static void
+ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old)
+{
+ ngx_int_t n;
+
+ for (n = 0; n < ngx_last_process; n++) {
+
+ ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "process: %d %P %p e:%d j:%d",
+ n,
+ ngx_processes[n].pid,
+ ngx_processes[n].handle,
+ ngx_processes[n].exiting,
+ ngx_processes[n].just_spawn);
+
+ if (old && ngx_processes[n].just_spawn) {
+ ngx_processes[n].just_spawn = 0;
+ continue;
+ }
+
+ if (ngx_processes[n].handle == NULL) {
+ continue;
+ }
+
+ if (SetEvent(ngx_processes[n].quit) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "SetEvent(\"%s\") failed",
+ ngx_processes[n].quit_event);
+ }
+
+ ngx_processes[n].exiting = 1;
+ }
+}
+
+
+static void
+ngx_terminate_worker_processes(ngx_cycle_t *cycle)
+{
+ ngx_int_t n;
+
+ for (n = 0; n < ngx_last_process; n++) {
+
+ if (ngx_processes[n].handle == NULL) {
+ continue;
+ }
+
+ if (TerminateProcess(ngx_processes[n].handle, 0) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "TerminateProcess(\"%p\") failed",
+ ngx_processes[n].handle);
+ }
+
+ ngx_processes[n].exiting = 1;
+
+ ngx_close_handle(ngx_processes[n].reopen);
+ ngx_close_handle(ngx_processes[n].quit);
+ ngx_close_handle(ngx_processes[n].term);
+ ngx_close_handle(ngx_processes[n].handle);
+ }
+}
+
+
+static ngx_uint_t
+ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h)
+{
+ u_long code;
+ ngx_int_t n;
+
+ for (n = 0; n < ngx_last_process; n++) {
+
+ if (ngx_processes[n].handle != h) {
+ continue;
+ }
+
+ if (GetExitCodeProcess(h, &code) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "GetExitCodeProcess(%P) failed",
+ ngx_processes[n].pid);
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
+ "%s process %P exited with code %Xl",
+ ngx_processes[n].name, ngx_processes[n].pid, code);
+
+ ngx_close_handle(ngx_processes[n].reopen);
+ ngx_close_handle(ngx_processes[n].quit);
+ ngx_close_handle(ngx_processes[n].term);
+ ngx_close_handle(h);
+
+ ngx_processes[n].handle = NULL;
+ ngx_processes[n].term = NULL;
+ ngx_processes[n].quit = NULL;
+ ngx_processes[n].reopen = NULL;
+
+ if (!ngx_processes[n].exiting && !ngx_terminate && !ngx_quit) {
+
+ if (ngx_spawn_process(cycle, ngx_processes[n].name, n)
+ == NGX_INVALID_PID)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "could not respawn %s", ngx_processes[n].name);
+
+ if (n == ngx_last_process - 1) {
+ ngx_last_process--;
+ }
+ }
+ }
+
+ goto found;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unknown process handle %p", h);
+
+found:
+
+ for (n = 0; n < ngx_last_process; n++) {
+
+ ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "process: %d %P %p e:%d j:%d",
+ n,
+ ngx_processes[n].pid,
+ ngx_processes[n].handle,
+ ngx_processes[n].exiting,
+ ngx_processes[n].just_spawn);
+
+ if (ngx_processes[n].handle) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void
+ngx_master_process_exit(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+
+ ngx_delete_pidfile(cycle);
+
+ ngx_close_handle(ngx_cache_manager_mutex);
+ ngx_close_handle(ngx_stop_event);
+ ngx_close_handle(ngx_quit_event);
+ ngx_close_handle(ngx_reopen_event);
+ ngx_close_handle(ngx_reload_event);
+ ngx_close_handle(ngx_master_process_event);
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit");
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->exit_master) {
+ cycle->modules[i]->exit_master(cycle);
+ }
+ }
+
+ ngx_destroy_pool(cycle->pool);
+
+ exit(0);
+}
+
+
+static void
+ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn)
+{
+ char wtevn[NGX_PROCESS_SYNC_NAME];
+ char wqevn[NGX_PROCESS_SYNC_NAME];
+ char wroevn[NGX_PROCESS_SYNC_NAME];
+ HANDLE mev, events[3];
+ u_long nev, ev;
+ ngx_err_t err;
+ ngx_tid_t wtid, cmtid, cltid;
+ ngx_log_t *log;
+
+ log = cycle->log;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "worker started");
+
+ ngx_sprintf((u_char *) wtevn, "ngx_worker_term_%P%Z", ngx_pid);
+ events[0] = CreateEvent(NULL, 1, 0, wtevn);
+ if (events[0] == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "CreateEvent(\"%s\") failed", wtevn);
+ goto failed;
+ }
+
+ ngx_sprintf((u_char *) wqevn, "ngx_worker_quit_%P%Z", ngx_pid);
+ events[1] = CreateEvent(NULL, 1, 0, wqevn);
+ if (events[1] == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "CreateEvent(\"%s\") failed", wqevn);
+ goto failed;
+ }
+
+ ngx_sprintf((u_char *) wroevn, "ngx_worker_reopen_%P%Z", ngx_pid);
+ events[2] = CreateEvent(NULL, 1, 0, wroevn);
+ if (events[2] == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "CreateEvent(\"%s\") failed", wroevn);
+ goto failed;
+ }
+
+ mev = OpenEvent(EVENT_MODIFY_STATE, 0, mevn);
+ if (mev == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "OpenEvent(\"%s\") failed", mevn);
+ goto failed;
+ }
+
+ if (SetEvent(mev) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "SetEvent(\"%s\") failed", mevn);
+ goto failed;
+ }
+
+
+ ngx_sprintf((u_char *) ngx_cache_manager_mutex_name,
+ "ngx_cache_manager_mutex_%s%Z", ngx_unique);
+
+ ngx_cache_manager_mutex = OpenMutex(SYNCHRONIZE, 0,
+ ngx_cache_manager_mutex_name);
+ if (ngx_cache_manager_mutex == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "OpenMutex(\"%s\") failed", ngx_cache_manager_mutex_name);
+ goto failed;
+ }
+
+ ngx_cache_manager_event = CreateEvent(NULL, 1, 0, NULL);
+ if (ngx_cache_manager_event == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "CreateEvent(\"ngx_cache_manager_event\") failed");
+ goto failed;
+ }
+
+
+ if (ngx_create_thread(&wtid, ngx_worker_thread, NULL, log) != 0) {
+ goto failed;
+ }
+
+ if (ngx_create_thread(&cmtid, ngx_cache_manager_thread, NULL, log) != 0) {
+ goto failed;
+ }
+
+ if (ngx_create_thread(&cltid, ngx_cache_loader_thread, NULL, log) != 0) {
+ goto failed;
+ }
+
+ for ( ;; ) {
+ ev = WaitForMultipleObjects(3, events, 0, INFINITE);
+
+ err = ngx_errno;
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "worker WaitForMultipleObjects: %ul", ev);
+
+ if (ev == WAIT_OBJECT_0) {
+ ngx_terminate = 1;
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "exiting");
+
+ if (ResetEvent(events[0]) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "ResetEvent(\"%s\") failed", wtevn);
+ }
+
+ break;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 1) {
+ ngx_quit = 1;
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "gracefully shutting down");
+ break;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 2) {
+ ngx_reopen = 1;
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, "reopening logs");
+
+ if (ResetEvent(events[2]) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "ResetEvent(\"%s\") failed", wroevn);
+ }
+
+ continue;
+ }
+
+ if (ev == WAIT_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "WaitForMultipleObjects() failed");
+
+ goto failed;
+ }
+ }
+
+ /* wait threads */
+
+ if (SetEvent(ngx_cache_manager_event) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "SetEvent(\"ngx_cache_manager_event\") failed");
+ }
+
+ events[1] = wtid;
+ events[2] = cmtid;
+
+ nev = 3;
+
+ for ( ;; ) {
+ ev = WaitForMultipleObjects(nev, events, 0, INFINITE);
+
+ err = ngx_errno;
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "worker exit WaitForMultipleObjects: %ul", ev);
+
+ if (ev == WAIT_OBJECT_0) {
+ break;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 1) {
+ if (nev == 2) {
+ break;
+ }
+
+ events[1] = events[2];
+ nev = 2;
+ continue;
+ }
+
+ if (ev == WAIT_OBJECT_0 + 2) {
+ nev = 2;
+ continue;
+ }
+
+ if (ev == WAIT_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "WaitForMultipleObjects() failed");
+ break;
+ }
+ }
+
+ ngx_close_handle(ngx_cache_manager_event);
+ ngx_close_handle(events[0]);
+ ngx_close_handle(events[1]);
+ ngx_close_handle(events[2]);
+ ngx_close_handle(mev);
+
+ ngx_worker_process_exit(cycle);
+
+failed:
+
+ exit(2);
+}
+
+
+static ngx_thread_value_t __stdcall
+ngx_worker_thread(void *data)
+{
+ ngx_int_t n;
+ ngx_time_t *tp;
+ ngx_cycle_t *cycle;
+
+ tp = ngx_timeofday();
+ srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec);
+
+ cycle = (ngx_cycle_t *) ngx_cycle;
+
+ for (n = 0; cycle->modules[n]; n++) {
+ if (cycle->modules[n]->init_process) {
+ if (cycle->modules[n]->init_process(cycle) == NGX_ERROR) {
+ /* fatal */
+ exit(2);
+ }
+ }
+ }
+
+ while (!ngx_quit) {
+
+ if (ngx_exiting) {
+ if (ngx_event_no_timers_left() == NGX_OK) {
+ break;
+ }
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "worker cycle");
+
+ ngx_process_events_and_timers(cycle);
+
+ if (ngx_terminate) {
+ return 0;
+ }
+
+ if (ngx_quit) {
+ ngx_quit = 0;
+
+ if (!ngx_exiting) {
+ ngx_exiting = 1;
+ ngx_set_shutdown_timer(cycle);
+ ngx_close_listening_sockets(cycle);
+ ngx_close_idle_connections(cycle);
+ }
+ }
+
+ if (ngx_reopen) {
+ ngx_reopen = 0;
+ ngx_reopen_files(cycle, -1);
+ }
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+
+ return 0;
+}
+
+
+static void
+ngx_worker_process_exit(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_connection_t *c;
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit");
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->exit_process) {
+ cycle->modules[i]->exit_process(cycle);
+ }
+ }
+
+ if (ngx_exiting) {
+ c = cycle->connections;
+ for (i = 0; i < cycle->connection_n; i++) {
+ if (c[i].fd != (ngx_socket_t) -1
+ && c[i].read
+ && !c[i].read->accept
+ && !c[i].read->channel
+ && !c[i].read->resolver)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "*%uA open socket #%d left in connection %ui",
+ c[i].number, c[i].fd, i);
+ }
+ }
+ }
+
+ ngx_destroy_pool(cycle->pool);
+
+ exit(0);
+}
+
+
+static ngx_thread_value_t __stdcall
+ngx_cache_manager_thread(void *data)
+{
+ u_long ev;
+ HANDLE events[2];
+ ngx_err_t err;
+ ngx_cycle_t *cycle;
+
+ cycle = (ngx_cycle_t *) ngx_cycle;
+
+ events[0] = ngx_cache_manager_event;
+ events[1] = ngx_cache_manager_mutex;
+
+ for ( ;; ) {
+ ev = WaitForMultipleObjects(2, events, 0, INFINITE);
+
+ err = ngx_errno;
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "cache manager WaitForMultipleObjects: %ul", ev);
+
+ if (ev == WAIT_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+ "WaitForMultipleObjects() failed");
+ }
+
+ /*
+ * ev == WAIT_OBJECT_0
+ * ev == WAIT_OBJECT_0 + 1
+ * ev == WAIT_ABANDONED_0 + 1
+ */
+
+ if (ngx_terminate || ngx_quit || ngx_exiting) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+ return 0;
+ }
+
+ break;
+ }
+
+ for ( ;; ) {
+
+ if (ngx_terminate || ngx_quit || ngx_exiting) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
+ break;
+ }
+
+ ngx_cache_manager_process_handler();
+ }
+
+ if (ReleaseMutex(ngx_cache_manager_mutex) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "ReleaseMutex() failed");
+ }
+
+ return 0;
+}
+
+
+static void
+ngx_cache_manager_process_handler(void)
+{
+ u_long ev;
+ ngx_uint_t i;
+ ngx_msec_t next, n;
+ ngx_path_t **path;
+
+ next = 60 * 60 * 1000;
+
+ path = ngx_cycle->paths.elts;
+ for (i = 0; i < ngx_cycle->paths.nelts; i++) {
+
+ if (path[i]->manager) {
+ n = path[i]->manager(path[i]->data);
+
+ next = (n <= next) ? n : next;
+
+ ngx_time_update();
+ }
+ }
+
+ if (next == 0) {
+ next = 1;
+ }
+
+ ev = WaitForSingleObject(ngx_cache_manager_event, (u_long) next);
+
+ if (ev != WAIT_TIMEOUT) {
+
+ ngx_time_update();
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "cache manager WaitForSingleObject: %ul", ev);
+ }
+}
+
+
+static ngx_thread_value_t __stdcall
+ngx_cache_loader_thread(void *data)
+{
+ ngx_uint_t i;
+ ngx_path_t **path;
+ ngx_cycle_t *cycle;
+
+ ngx_msleep(60000);
+
+ cycle = (ngx_cycle_t *) ngx_cycle;
+
+ path = cycle->paths.elts;
+ for (i = 0; i < cycle->paths.nelts; i++) {
+
+ if (ngx_terminate || ngx_quit || ngx_exiting) {
+ break;
+ }
+
+ if (path[i]->loader) {
+ path[i]->loader(path[i]->data);
+ ngx_time_update();
+ }
+ }
+
+ return 0;
+}
+
+
+void
+ngx_single_process_cycle(ngx_cycle_t *cycle)
+{
+ ngx_tid_t tid;
+
+ ngx_console_init(cycle);
+
+ if (ngx_create_signal_events(cycle) != NGX_OK) {
+ exit(2);
+ }
+
+ if (ngx_create_thread(&tid, ngx_worker_thread, NULL, cycle->log) != 0) {
+ /* fatal */
+ exit(2);
+ }
+
+ /* STUB */
+ WaitForSingleObject(ngx_stop_event, INFINITE);
+}
+
+
+ngx_int_t
+ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid)
+{
+ HANDLE ev;
+ ngx_int_t rc;
+ char evn[NGX_PROCESS_SYNC_NAME];
+
+ ngx_sprintf((u_char *) evn, "Global\\ngx_%s_%P%Z", sig, pid);
+
+ ev = OpenEvent(EVENT_MODIFY_STATE, 0, evn);
+ if (ev == NULL) {
+ ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno,
+ "OpenEvent(\"%s\") failed", evn);
+ return 1;
+ }
+
+ if (SetEvent(ev) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "SetEvent(\"%s\") failed", evn);
+ rc = 1;
+
+ } else {
+ rc = 0;
+ }
+
+ ngx_close_handle(ev);
+
+ return rc;
+}
+
+
+void
+ngx_close_handle(HANDLE h)
+{
+ if (CloseHandle(h) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "CloseHandle(%p) failed", h);
+ }
+}
diff --git a/app/nginx/src/os/win32/ngx_process_cycle.h b/app/nginx/src/os/win32/ngx_process_cycle.h
new file mode 100644
index 0000000..95d2743
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_process_cycle.h
@@ -0,0 +1,44 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_
+#define _NGX_PROCESS_CYCLE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_PROCESS_SINGLE 0
+#define NGX_PROCESS_MASTER 1
+#define NGX_PROCESS_SIGNALLER 2
+#define NGX_PROCESS_WORKER 3
+
+
+void ngx_master_process_cycle(ngx_cycle_t *cycle);
+void ngx_single_process_cycle(ngx_cycle_t *cycle);
+void ngx_close_handle(HANDLE h);
+
+
+extern ngx_uint_t ngx_process;
+extern ngx_uint_t ngx_worker;
+extern ngx_pid_t ngx_pid;
+extern ngx_uint_t ngx_exiting;
+
+extern sig_atomic_t ngx_quit;
+extern sig_atomic_t ngx_terminate;
+extern sig_atomic_t ngx_reopen;
+
+extern ngx_uint_t ngx_inherited;
+extern ngx_pid_t ngx_new_binary;
+
+
+extern HANDLE ngx_master_process_event;
+extern char ngx_master_process_event_name[];
+
+
+#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_service.c b/app/nginx/src/os/win32/ngx_service.c
new file mode 100644
index 0000000..835d9cf
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_service.c
@@ -0,0 +1,134 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+
+#define NGX_SERVICE_CONTROL_SHUTDOWN 128
+#define NGX_SERVICE_CONTROL_REOPEN 129
+
+
+SERVICE_TABLE_ENTRY st[] = {
+ { "nginx", service_main },
+ { NULL, NULL }
+};
+
+
+ngx_int_t
+ngx_service(ngx_log_t *log)
+{
+ /* primary thread */
+
+ /* StartServiceCtrlDispatcher() should be called within 30 seconds */
+
+ if (StartServiceCtrlDispatcher(st) == 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "StartServiceCtrlDispatcher() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+void
+service_main(u_int argc, char **argv)
+{
+ SERVICE_STATUS status;
+ SERVICE_STATUS_HANDLE service;
+
+ /* thread spawned by SCM */
+
+ service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx);
+ if (service == INVALID_HANDLE_VALUE) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "RegisterServiceCtrlHandlerEx() failed");
+ return;
+ }
+
+ status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ status.dwCurrentState = SERVICE_START_PENDING;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP
+ |SERVICE_ACCEPT_PARAMCHANGE;
+ status.dwWin32ExitCode = NO_ERROR;
+ status.dwServiceSpecificExitCode = 0;
+ status.dwCheckPoint = 1;
+ status.dwWaitHint = 2000;
+
+ /* SetServiceStatus() should be called within 80 seconds */
+
+ if (SetServiceStatus(service, &status) == 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "SetServiceStatus() failed");
+ return;
+ }
+
+ /* init */
+
+ status.dwCurrentState = SERVICE_RUNNING;
+ status.dwCheckPoint = 0;
+ status.dwWaitHint = 0;
+
+ if (SetServiceStatus(service, &status) == 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "SetServiceStatus() failed");
+ return;
+ }
+
+ /* call master or worker loop */
+
+ /*
+ * master should use event notification and look status
+ * single should use iocp to get notifications from service handler
+ */
+
+}
+
+
+u_int
+service_handler(u_int control, u_int type, void *data, void *ctx)
+{
+ /* primary thread */
+
+ switch (control) {
+
+ case SERVICE_CONTROL_INTERROGATE:
+ status = NGX_IOCP_INTERROGATE;
+ break;
+
+ case SERVICE_CONTROL_STOP:
+ status = NGX_IOCP_STOP;
+ break;
+
+ case SERVICE_CONTROL_PARAMCHANGE:
+ status = NGX_IOCP_RECONFIGURE;
+ break;
+
+ case NGX_SERVICE_CONTROL_SHUTDOWN:
+ status = NGX_IOCP_REOPEN;
+ break;
+
+ case NGX_SERVICE_CONTROL_REOPEN:
+ status = NGX_IOCP_REOPEN;
+ break;
+
+ default:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ if (ngx_single) {
+ if (PostQueuedCompletionStatus(iocp, ... status, ...) == 0) {
+ err = ngx_errno;
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "PostQueuedCompletionStatus() failed");
+ return err;
+ }
+
+ } else {
+ Event
+ }
+
+ return NO_ERROR;
+}
diff --git a/app/nginx/src/os/win32/ngx_shmem.c b/app/nginx/src/os/win32/ngx_shmem.c
new file mode 100644
index 0000000..c3ed699
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_shmem.c
@@ -0,0 +1,161 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * Base addresses selected by system for shared memory mappings are likely
+ * to be different on Windows Vista and later versions due to address space
+ * layout randomization. This is however incompatible with storing absolute
+ * addresses within the shared memory.
+ *
+ * To make it possible to store absolute addresses we create mappings
+ * at the same address in all processes by starting mappings at predefined
+ * addresses. The addresses were selected somewhat randomly in order to
+ * minimize the probability that some other library doing something similar
+ * conflicts with us. The addresses are from the following typically free
+ * blocks:
+ *
+ * - 0x10000000 .. 0x70000000 (about 1.5 GB in total) on 32-bit platforms
+ * - 0x000000007fff0000 .. 0x000007f68e8b0000 (about 8 TB) on 64-bit platforms
+ *
+ * Additionally, we allow to change the mapping address once it was detected
+ * to be different from one originally used. This is needed to support
+ * reconfiguration.
+ */
+
+
+#ifdef _WIN64
+#define NGX_SHMEM_BASE 0x0000047047e00000
+#else
+#define NGX_SHMEM_BASE 0x2efe0000
+#endif
+
+
+ngx_uint_t ngx_allocation_granularity;
+
+
+ngx_int_t
+ngx_shm_alloc(ngx_shm_t *shm)
+{
+ u_char *name;
+ uint64_t size;
+ static u_char *base = (u_char *) NGX_SHMEM_BASE;
+
+ name = ngx_alloc(shm->name.len + 2 + NGX_INT32_LEN, shm->log);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_sprintf(name, "%V_%s%Z", &shm->name, ngx_unique);
+
+ ngx_set_errno(0);
+
+ size = shm->size;
+
+ shm->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
+ (u_long) (size >> 32),
+ (u_long) (size & 0xffffffff),
+ (char *) name);
+
+ if (shm->handle == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "CreateFileMapping(%uz, %s) failed",
+ shm->size, name);
+ ngx_free(name);
+
+ return NGX_ERROR;
+ }
+
+ ngx_free(name);
+
+ if (ngx_errno == ERROR_ALREADY_EXISTS) {
+ shm->exists = 1;
+ }
+
+ shm->addr = MapViewOfFileEx(shm->handle, FILE_MAP_WRITE, 0, 0, 0, base);
+
+ if (shm->addr != NULL) {
+ base += ngx_align(size, ngx_allocation_granularity);
+ return NGX_OK;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, shm->log, ngx_errno,
+ "MapViewOfFileEx(%uz, %p) of file mapping \"%V\" failed, "
+ "retry without a base address",
+ shm->size, base, &shm->name);
+
+ /*
+ * Order of shared memory zones may be different in the master process
+ * and worker processes after reconfiguration. As a result, the above
+ * may fail due to a conflict with a previously created mapping remapped
+ * to a different address. Additionally, there may be a conflict with
+ * some other uses of the memory. In this case we retry without a base
+ * address to let the system assign the address itself.
+ */
+
+ shm->addr = MapViewOfFile(shm->handle, FILE_MAP_WRITE, 0, 0, 0);
+
+ if (shm->addr != NULL) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "MapViewOfFile(%uz) of file mapping \"%V\" failed",
+ shm->size, &shm->name);
+
+ if (CloseHandle(shm->handle) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "CloseHandle() of file mapping \"%V\" failed",
+ &shm->name);
+ }
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_shm_remap(ngx_shm_t *shm, u_char *addr)
+{
+ if (UnmapViewOfFile(shm->addr) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "UnmapViewOfFile(%p) of file mapping \"%V\" failed",
+ shm->addr, &shm->name);
+ return NGX_ERROR;
+ }
+
+ shm->addr = MapViewOfFileEx(shm->handle, FILE_MAP_WRITE, 0, 0, 0, addr);
+
+ if (shm->addr != NULL) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "MapViewOfFileEx(%uz, %p) of file mapping \"%V\" failed",
+ shm->size, addr, &shm->name);
+
+ return NGX_ERROR;
+}
+
+
+void
+ngx_shm_free(ngx_shm_t *shm)
+{
+ if (UnmapViewOfFile(shm->addr) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "UnmapViewOfFile(%p) of file mapping \"%V\" failed",
+ shm->addr, &shm->name);
+ }
+
+ if (CloseHandle(shm->handle) == 0) {
+ ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
+ "CloseHandle() of file mapping \"%V\" failed",
+ &shm->name);
+ }
+}
diff --git a/app/nginx/src/os/win32/ngx_shmem.h b/app/nginx/src/os/win32/ngx_shmem.h
new file mode 100644
index 0000000..ee47429
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_shmem.h
@@ -0,0 +1,33 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SHMEM_H_INCLUDED_
+#define _NGX_SHMEM_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ u_char *addr;
+ size_t size;
+ ngx_str_t name;
+ HANDLE handle;
+ ngx_log_t *log;
+ ngx_uint_t exists; /* unsigned exists:1; */
+} ngx_shm_t;
+
+
+ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
+ngx_int_t ngx_shm_remap(ngx_shm_t *shm, u_char *addr);
+void ngx_shm_free(ngx_shm_t *shm);
+
+extern ngx_uint_t ngx_allocation_granularity;
+
+
+#endif /* _NGX_SHMEM_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_socket.c b/app/nginx/src/os/win32/ngx_socket.c
new file mode 100644
index 0000000..05a39f4
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_socket.c
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+int
+ngx_nonblocking(ngx_socket_t s)
+{
+ unsigned long nb = 1;
+
+ return ioctlsocket(s, FIONBIO, &nb);
+}
+
+
+int
+ngx_blocking(ngx_socket_t s)
+{
+ unsigned long nb = 0;
+
+ return ioctlsocket(s, FIONBIO, &nb);
+}
+
+
+int
+ngx_tcp_push(ngx_socket_t s)
+{
+ return 0;
+}
diff --git a/app/nginx/src/os/win32/ngx_socket.h b/app/nginx/src/os/win32/ngx_socket.h
new file mode 100644
index 0000000..a9e26c2
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_socket.h
@@ -0,0 +1,207 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SOCKET_H_INCLUDED_
+#define _NGX_SOCKET_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_WRITE_SHUTDOWN SD_SEND
+
+
+typedef SOCKET ngx_socket_t;
+typedef int socklen_t;
+
+
+#define ngx_socket(af, type, proto) \
+ WSASocketW(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED)
+
+#define ngx_socket_n "WSASocketW()"
+
+int ngx_nonblocking(ngx_socket_t s);
+int ngx_blocking(ngx_socket_t s);
+
+#define ngx_nonblocking_n "ioctlsocket(FIONBIO)"
+#define ngx_blocking_n "ioctlsocket(!FIONBIO)"
+
+#define ngx_shutdown_socket shutdown
+#define ngx_shutdown_socket_n "shutdown()"
+
+#define ngx_close_socket closesocket
+#define ngx_close_socket_n "closesocket()"
+
+
+#ifndef WSAID_ACCEPTEX
+
+typedef BOOL (PASCAL FAR * LPFN_ACCEPTEX)(
+ IN SOCKET sListenSocket,
+ IN SOCKET sAcceptSocket,
+ IN PVOID lpOutputBuffer,
+ IN DWORD dwReceiveDataLength,
+ IN DWORD dwLocalAddressLength,
+ IN DWORD dwRemoteAddressLength,
+ OUT LPDWORD lpdwBytesReceived,
+ IN LPOVERLAPPED lpOverlapped
+ );
+
+#define WSAID_ACCEPTEX \
+ {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+
+#endif
+
+
+#ifndef WSAID_GETACCEPTEXSOCKADDRS
+
+typedef VOID (PASCAL FAR * LPFN_GETACCEPTEXSOCKADDRS)(
+ IN PVOID lpOutputBuffer,
+ IN DWORD dwReceiveDataLength,
+ IN DWORD dwLocalAddressLength,
+ IN DWORD dwRemoteAddressLength,
+ OUT struct sockaddr **LocalSockaddr,
+ OUT LPINT LocalSockaddrLength,
+ OUT struct sockaddr **RemoteSockaddr,
+ OUT LPINT RemoteSockaddrLength
+ );
+
+#define WSAID_GETACCEPTEXSOCKADDRS \
+ {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+
+#endif
+
+
+#ifndef WSAID_TRANSMITFILE
+
+#ifndef TF_DISCONNECT
+
+#define TF_DISCONNECT 1
+#define TF_REUSE_SOCKET 2
+#define TF_WRITE_BEHIND 4
+#define TF_USE_DEFAULT_WORKER 0
+#define TF_USE_SYSTEM_THREAD 16
+#define TF_USE_KERNEL_APC 32
+
+typedef struct _TRANSMIT_FILE_BUFFERS {
+ LPVOID Head;
+ DWORD HeadLength;
+ LPVOID Tail;
+ DWORD TailLength;
+} TRANSMIT_FILE_BUFFERS, *PTRANSMIT_FILE_BUFFERS, FAR *LPTRANSMIT_FILE_BUFFERS;
+
+#endif
+
+typedef BOOL (PASCAL FAR * LPFN_TRANSMITFILE)(
+ IN SOCKET hSocket,
+ IN HANDLE hFile,
+ IN DWORD nNumberOfBytesToWrite,
+ IN DWORD nNumberOfBytesPerSend,
+ IN LPOVERLAPPED lpOverlapped,
+ IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
+ IN DWORD dwReserved
+ );
+
+#define WSAID_TRANSMITFILE \
+ {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+
+#endif
+
+
+#ifndef WSAID_TRANSMITPACKETS
+
+/* OpenWatcom has a swapped TP_ELEMENT_FILE and TP_ELEMENT_MEMORY definition */
+
+#ifndef TP_ELEMENT_FILE
+
+#ifdef _MSC_VER
+#pragma warning(disable:4201) /* Nonstandard extension, nameless struct/union */
+#endif
+
+typedef struct _TRANSMIT_PACKETS_ELEMENT {
+ ULONG dwElFlags;
+#define TP_ELEMENT_MEMORY 1
+#define TP_ELEMENT_FILE 2
+#define TP_ELEMENT_EOP 4
+ ULONG cLength;
+ union {
+ struct {
+ LARGE_INTEGER nFileOffset;
+ HANDLE hFile;
+ };
+ PVOID pBuffer;
+ };
+} TRANSMIT_PACKETS_ELEMENT, *PTRANSMIT_PACKETS_ELEMENT,
+ FAR *LPTRANSMIT_PACKETS_ELEMENT;
+
+#ifdef _MSC_VER
+#pragma warning(default:4201)
+#endif
+
+#endif
+
+typedef BOOL (PASCAL FAR * LPFN_TRANSMITPACKETS) (
+ SOCKET hSocket,
+ TRANSMIT_PACKETS_ELEMENT *lpPacketArray,
+ DWORD nElementCount,
+ DWORD nSendSize,
+ LPOVERLAPPED lpOverlapped,
+ DWORD dwFlags
+ );
+
+#define WSAID_TRANSMITPACKETS \
+ {0xd9689da0,0x1f90,0x11d3,{0x99,0x71,0x00,0xc0,0x4f,0x68,0xc8,0x76}}
+
+#endif
+
+
+#ifndef WSAID_CONNECTEX
+
+typedef BOOL (PASCAL FAR * LPFN_CONNECTEX) (
+ IN SOCKET s,
+ IN const struct sockaddr FAR *name,
+ IN int namelen,
+ IN PVOID lpSendBuffer OPTIONAL,
+ IN DWORD dwSendDataLength,
+ OUT LPDWORD lpdwBytesSent,
+ IN LPOVERLAPPED lpOverlapped
+ );
+
+#define WSAID_CONNECTEX \
+ {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
+
+#endif
+
+
+#ifndef WSAID_DISCONNECTEX
+
+typedef BOOL (PASCAL FAR * LPFN_DISCONNECTEX) (
+ IN SOCKET s,
+ IN LPOVERLAPPED lpOverlapped,
+ IN DWORD dwFlags,
+ IN DWORD dwReserved
+ );
+
+#define WSAID_DISCONNECTEX \
+ {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}}
+
+#endif
+
+
+extern LPFN_ACCEPTEX ngx_acceptex;
+extern LPFN_GETACCEPTEXSOCKADDRS ngx_getacceptexsockaddrs;
+extern LPFN_TRANSMITFILE ngx_transmitfile;
+extern LPFN_TRANSMITPACKETS ngx_transmitpackets;
+extern LPFN_CONNECTEX ngx_connectex;
+extern LPFN_DISCONNECTEX ngx_disconnectex;
+
+
+int ngx_tcp_push(ngx_socket_t s);
+#define ngx_tcp_push_n "tcp_push()"
+
+
+#endif /* _NGX_SOCKET_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_stat.c b/app/nginx/src/os/win32/ngx_stat.c
new file mode 100644
index 0000000..51bcd96
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_stat.c
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+int ngx_file_type(char *file, ngx_file_info_t *sb)
+{
+ sb->dwFileAttributes = GetFileAttributes(file);
+
+ if (sb->dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+int ngx_stat(char *file, ngx_stat_t *sb)
+{
+ *sb = GetFileAttributes(file);
+
+ if (*sb == INVALID_FILE_ATTRIBUTES) {
+ return -1;
+ }
+
+ return 0;
+}
+*/
diff --git a/app/nginx/src/os/win32/ngx_thread.c b/app/nginx/src/os/win32/ngx_thread.c
new file mode 100644
index 0000000..a13de2d
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_thread.c
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_err_t
+ngx_create_thread(ngx_tid_t *tid,
+ ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log)
+{
+ u_long id;
+ ngx_err_t err;
+
+ *tid = CreateThread(NULL, 0, func, arg, 0, &id);
+
+ if (*tid != NULL) {
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "create thread " NGX_TID_T_FMT, id);
+ return 0;
+ }
+
+ err = ngx_errno;
+ ngx_log_error(NGX_LOG_ALERT, log, err, "CreateThread() failed");
+ return err;
+}
diff --git a/app/nginx/src/os/win32/ngx_thread.h b/app/nginx/src/os/win32/ngx_thread.h
new file mode 100644
index 0000000..4012276
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_thread.h
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_THREAD_H_INCLUDED_
+#define _NGX_THREAD_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef HANDLE ngx_tid_t;
+typedef DWORD ngx_thread_value_t;
+
+
+ngx_err_t ngx_create_thread(ngx_tid_t *tid,
+ ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log);
+
+#define ngx_log_tid GetCurrentThreadId()
+#define NGX_TID_T_FMT "%ud"
+
+
+#endif /* _NGX_THREAD_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_time.c b/app/nginx/src/os/win32/ngx_time.c
new file mode 100644
index 0000000..bd6d287
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_time.c
@@ -0,0 +1,83 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void
+ngx_gettimeofday(struct timeval *tp)
+{
+ uint64_t intervals;
+ FILETIME ft;
+
+ GetSystemTimeAsFileTime(&ft);
+
+ /*
+ * A file time is a 64-bit value that represents the number
+ * of 100-nanosecond intervals that have elapsed since
+ * January 1, 1601 12:00 A.M. UTC.
+ *
+ * Between January 1, 1970 (Epoch) and January 1, 1601 there were
+ * 134744 days,
+ * 11644473600 seconds or
+ * 11644473600,000,000,0 100-nanosecond intervals.
+ *
+ * See also MSKB Q167296.
+ */
+
+ intervals = ((uint64_t) ft.dwHighDateTime << 32) | ft.dwLowDateTime;
+ intervals -= 116444736000000000;
+
+ tp->tv_sec = (long) (intervals / 10000000);
+ tp->tv_usec = (long) ((intervals % 10000000) / 10);
+}
+
+
+void
+ngx_libc_localtime(time_t s, struct tm *tm)
+{
+ struct tm *t;
+
+ t = localtime(&s);
+ *tm = *t;
+}
+
+
+void
+ngx_libc_gmtime(time_t s, struct tm *tm)
+{
+ struct tm *t;
+
+ t = gmtime(&s);
+ *tm = *t;
+}
+
+
+ngx_int_t
+ngx_gettimezone(void)
+{
+ u_long n;
+ TIME_ZONE_INFORMATION tz;
+
+ n = GetTimeZoneInformation(&tz);
+
+ switch (n) {
+
+ case TIME_ZONE_ID_UNKNOWN:
+ return -tz.Bias;
+
+ case TIME_ZONE_ID_STANDARD:
+ return -(tz.Bias + tz.StandardBias);
+
+ case TIME_ZONE_ID_DAYLIGHT:
+ return -(tz.Bias + tz.DaylightBias);
+
+ default: /* TIME_ZONE_ID_INVALID */
+ return 0;
+ }
+}
diff --git a/app/nginx/src/os/win32/ngx_time.h b/app/nginx/src/os/win32/ngx_time.h
new file mode 100644
index 0000000..6c2f806
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_time.h
@@ -0,0 +1,51 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_TIME_H_INCLUDED_
+#define _NGX_TIME_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef ngx_rbtree_key_t ngx_msec_t;
+typedef ngx_rbtree_key_int_t ngx_msec_int_t;
+
+typedef SYSTEMTIME ngx_tm_t;
+typedef FILETIME ngx_mtime_t;
+
+#define ngx_tm_sec wSecond
+#define ngx_tm_min wMinute
+#define ngx_tm_hour wHour
+#define ngx_tm_mday wDay
+#define ngx_tm_mon wMonth
+#define ngx_tm_year wYear
+#define ngx_tm_wday wDayOfWeek
+
+#define ngx_tm_sec_t u_short
+#define ngx_tm_min_t u_short
+#define ngx_tm_hour_t u_short
+#define ngx_tm_mday_t u_short
+#define ngx_tm_mon_t u_short
+#define ngx_tm_year_t u_short
+#define ngx_tm_wday_t u_short
+
+
+#define ngx_msleep Sleep
+
+#define NGX_HAVE_GETTIMEZONE 1
+
+#define ngx_timezone_update()
+
+ngx_int_t ngx_gettimezone(void);
+void ngx_libc_localtime(time_t s, struct tm *tm);
+void ngx_libc_gmtime(time_t s, struct tm *tm);
+void ngx_gettimeofday(struct timeval *tp);
+
+
+#endif /* _NGX_TIME_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_udp_wsarecv.c b/app/nginx/src/os/win32/ngx_udp_wsarecv.c
new file mode 100644
index 0000000..5424375
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_udp_wsarecv.c
@@ -0,0 +1,149 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_udp_wsarecv(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ int rc;
+ u_long bytes, flags;
+ WSABUF wsabuf[1];
+ ngx_err_t err;
+ ngx_event_t *rev;
+
+ wsabuf[0].buf = (char *) buf;
+ wsabuf[0].len = size;
+ flags = 0;
+ bytes = 0;
+
+ rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL);
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv: fd:%d rc:%d %ul of %z", c->fd, rc, bytes, size);
+
+ rev = c->read;
+
+ if (rc == -1) {
+ rev->ready = 0;
+ err = ngx_socket_errno;
+
+ if (err == WSAEWOULDBLOCK) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSARecv() not ready");
+ return NGX_AGAIN;
+ }
+
+ rev->error = 1;
+ ngx_connection_error(c, err, "WSARecv() failed");
+
+ return NGX_ERROR;
+ }
+
+ return bytes;
+}
+
+
+ssize_t
+ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ int rc;
+ u_long bytes, flags;
+ WSABUF wsabuf[1];
+ ngx_err_t err;
+ ngx_event_t *rev;
+ LPWSAOVERLAPPED ovlp;
+
+ rev = c->read;
+
+ if (!rev->ready) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second wsa post");
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "rev->complete: %d", rev->complete);
+
+ if (rev->complete) {
+ rev->complete = 0;
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+ if (rev->ovlp.error) {
+ ngx_connection_error(c, rev->ovlp.error, "WSARecv() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv ovlp: fd:%d %ul of %z",
+ c->fd, rev->available, size);
+
+ return rev->available;
+ }
+
+ if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp,
+ &bytes, 0, NULL)
+ == 0)
+ {
+ ngx_connection_error(c, ngx_socket_errno,
+ "WSARecv() or WSAGetOverlappedResult() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv: fd:%d %ul of %z", c->fd, bytes, size);
+
+ return bytes;
+ }
+
+ ovlp = (LPWSAOVERLAPPED) &rev->ovlp;
+ ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+ wsabuf[0].buf = (char *) buf;
+ wsabuf[0].len = size;
+ flags = 0;
+ bytes = 0;
+
+ rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL);
+
+ rev->complete = 0;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv ovlp: fd:%d rc:%d %ul of %z",
+ c->fd, rc, bytes, size);
+
+ if (rc == -1) {
+ err = ngx_socket_errno;
+ if (err == WSA_IO_PENDING) {
+ rev->active = 1;
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSARecv() posted");
+ return NGX_AGAIN;
+ }
+
+ rev->error = 1;
+ ngx_connection_error(c, err, "WSARecv() failed");
+ return NGX_ERROR;
+ }
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+ /*
+ * if a socket was bound with I/O completion port
+ * then GetQueuedCompletionStatus() would anyway return its status
+ * despite that WSARecv() was already complete
+ */
+
+ rev->active = 1;
+ return NGX_AGAIN;
+ }
+
+ rev->active = 0;
+
+ return bytes;
+}
diff --git a/app/nginx/src/os/win32/ngx_user.c b/app/nginx/src/os/win32/ngx_user.c
new file mode 100644
index 0000000..ea6da5a
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_user.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_CRYPT)
+
+ngx_int_t
+ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ /* STUB: a plain text password */
+
+ *encrypted = key;
+
+ return NGX_OK;
+}
+
+#endif /* NGX_CRYPT */
diff --git a/app/nginx/src/os/win32/ngx_user.h b/app/nginx/src/os/win32/ngx_user.h
new file mode 100644
index 0000000..61408e4
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_user.h
@@ -0,0 +1,25 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_USER_H_INCLUDED_
+#define _NGX_USER_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/* STUB */
+#define ngx_uid_t ngx_int_t
+#define ngx_gid_t ngx_int_t
+
+
+ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+
+
+#endif /* _NGX_USER_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_win32_config.h b/app/nginx/src/os/win32/ngx_win32_config.h
new file mode 100644
index 0000000..4824d05
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_win32_config.h
@@ -0,0 +1,282 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_WIN32_CONFIG_H_INCLUDED_
+#define _NGX_WIN32_CONFIG_H_INCLUDED_
+
+
+#undef WIN32
+#define WIN32 0x0400
+#define _WIN32_WINNT 0x0501
+
+
+#define STRICT
+#define WIN32_LEAN_AND_MEAN
+
+/* enable getenv() and gmtime() in msvc8 */
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_DEPRECATE
+
+/* enable gethostbyname() in msvc2015 */
+#if !(NGX_HAVE_INET6)
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
+#endif
+
+/*
+ * we need to include <windows.h> explicitly before <winsock2.h> because
+ * the warning 4201 is enabled in <windows.h>
+ */
+#include <windows.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable:4201)
+#endif
+
+#include <winsock2.h>
+#include <ws2tcpip.h> /* ipv6 */
+#include <mswsock.h>
+#include <shellapi.h>
+#include <stddef.h> /* offsetof() */
+
+#ifdef __MINGW64_VERSION_MAJOR
+
+/* GCC MinGW-w64 supports _FILE_OFFSET_BITS */
+#define _FILE_OFFSET_BITS 64
+
+#elif defined __GNUC__
+
+/* GCC MinGW's stdio.h includes sys/types.h */
+#define _OFF_T_
+#define __have_typedef_off_t
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef __GNUC__
+#include <stdint.h>
+#endif
+#include <ctype.h>
+#include <locale.h>
+
+#ifdef __WATCOMC__
+#define _TIME_T_DEFINED
+typedef long time_t;
+/* OpenWatcom defines time_t as "unsigned long" */
+#endif
+
+#include <time.h> /* localtime(), strftime() */
+
+
+#ifdef _MSC_VER
+
+/* the end of the precompiled headers */
+#pragma hdrstop
+
+#pragma warning(default:4201)
+
+/* disable some "-W4" level warnings */
+
+/* 'type cast': from function pointer to data pointer */
+#pragma warning(disable:4054)
+
+/* 'type cast': from data pointer to function pointer */
+#pragma warning(disable:4055)
+
+/* 'function' : different 'const' qualifiers */
+#pragma warning(disable:4090)
+
+/* unreferenced formal parameter */
+#pragma warning(disable:4100)
+
+/* FD_SET() and FD_CLR(): conditional expression is constant */
+#pragma warning(disable:4127)
+
+/* conversion from 'type1' to 'type2', possible loss of data */
+#pragma warning(disable:4244)
+
+/* conversion from 'size_t' to 'type', possible loss of data */
+#pragma warning(disable:4267)
+
+/* array is too small to include a terminating null character */
+#pragma warning(disable:4295)
+
+#endif
+
+
+#ifdef __WATCOMC__
+
+/* symbol 'ngx_rbtree_min' has been defined, but not referenced */
+#pragma disable_message(202)
+
+#endif
+
+
+#ifdef __BORLANDC__
+
+/* the end of the precompiled headers */
+#pragma hdrstop
+
+/* functions containing (for|while|some if) are not expanded inline */
+#pragma warn -8027
+
+/* unreferenced formal parameter */
+#pragma warn -8057
+
+/* suspicious pointer arithmetic */
+#pragma warn -8072
+
+#endif
+
+
+#include <ngx_auto_config.h>
+
+
+#define ngx_inline __inline
+#define ngx_cdecl __cdecl
+
+
+#ifdef _MSC_VER
+typedef unsigned __int32 uint32_t;
+typedef __int32 int32_t;
+typedef unsigned __int16 uint16_t;
+#define ngx_libc_cdecl __cdecl
+
+#elif defined __BORLANDC__
+typedef unsigned __int32 uint32_t;
+typedef __int32 int32_t;
+typedef unsigned __int16 uint16_t;
+#define ngx_libc_cdecl __cdecl
+
+#else /* __WATCOMC__ */
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef unsigned short int uint16_t;
+#define ngx_libc_cdecl
+
+#endif
+
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#if __BORLANDC__
+typedef int intptr_t;
+typedef u_int uintptr_t;
+#endif
+
+
+#ifndef __MINGW64_VERSION_MAJOR
+
+/* Windows defines off_t as long, which is 32-bit */
+typedef __int64 off_t;
+#define _OFF_T_DEFINED
+
+#endif
+
+
+#ifdef __WATCOMC__
+
+/* off_t is redefined by sys/types.h used by zlib.h */
+#define __TYPES_H_INCLUDED
+typedef int dev_t;
+typedef unsigned int ino_t;
+
+#elif __BORLANDC__
+
+/* off_t is redefined by sys/types.h used by zlib.h */
+#define __TYPES_H
+
+typedef int dev_t;
+typedef unsigned int ino_t;
+
+#endif
+
+
+#ifndef __GNUC__
+#ifdef _WIN64
+typedef __int64 ssize_t;
+#else
+typedef int ssize_t;
+#endif
+#endif
+
+
+typedef uint32_t in_addr_t;
+typedef u_short in_port_t;
+typedef int sig_atomic_t;
+
+
+#ifdef _WIN64
+
+#define NGX_PTR_SIZE 8
+#define NGX_SIZE_T_LEN (sizeof("-9223372036854775808") - 1)
+#define NGX_MAX_SIZE_T_VALUE 9223372036854775807
+#define NGX_TIME_T_LEN (sizeof("-9223372036854775808") - 1)
+#define NGX_TIME_T_SIZE 8
+#define NGX_MAX_TIME_T_VALUE 9223372036854775807
+
+#else
+
+#define NGX_PTR_SIZE 4
+#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1)
+#define NGX_MAX_SIZE_T_VALUE 2147483647
+#define NGX_TIME_T_LEN (sizeof("-2147483648") - 1)
+#define NGX_TIME_T_SIZE 4
+#define NGX_MAX_TIME_T_VALUE 2147483647
+
+#endif
+
+
+#define NGX_OFF_T_LEN (sizeof("-9223372036854775807") - 1)
+#define NGX_MAX_OFF_T_VALUE 9223372036854775807
+#define NGX_SIG_ATOMIC_T_SIZE 4
+
+
+#define NGX_HAVE_LITTLE_ENDIAN 1
+#define NGX_HAVE_NONALIGNED 1
+
+
+#define NGX_WIN_NT 200000
+
+
+#define NGX_LISTEN_BACKLOG 511
+
+
+#ifndef NGX_HAVE_INHERITED_NONBLOCK
+#define NGX_HAVE_INHERITED_NONBLOCK 1
+#endif
+
+#ifndef NGX_HAVE_CASELESS_FILESYSTEM
+#define NGX_HAVE_CASELESS_FILESYSTEM 1
+#endif
+
+#ifndef NGX_HAVE_WIN32_TRANSMITPACKETS
+#define NGX_HAVE_WIN32_TRANSMITPACKETS 1
+#define NGX_HAVE_WIN32_TRANSMITFILE 0
+#endif
+
+#ifndef NGX_HAVE_WIN32_TRANSMITFILE
+#define NGX_HAVE_WIN32_TRANSMITFILE 1
+#endif
+
+#if (NGX_HAVE_WIN32_TRANSMITPACKETS) || (NGX_HAVE_WIN32_TRANSMITFILE)
+#define NGX_HAVE_SENDFILE 1
+#endif
+
+#ifndef NGX_HAVE_SO_SNDLOWAT
+/* setsockopt(SO_SNDLOWAT) returns error WSAENOPROTOOPT */
+#define NGX_HAVE_SO_SNDLOWAT 0
+#endif
+
+#define NGX_HAVE_GETADDRINFO 1
+
+#define ngx_random rand
+#define ngx_debug_init()
+
+
+#endif /* _NGX_WIN32_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/os/win32/ngx_win32_init.c b/app/nginx/src/os/win32/ngx_win32_init.c
new file mode 100644
index 0000000..ec9b51e
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_win32_init.c
@@ -0,0 +1,297 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <nginx.h>
+
+
+ngx_uint_t ngx_win32_version;
+ngx_uint_t ngx_ncpu;
+ngx_uint_t ngx_max_wsabufs;
+ngx_int_t ngx_max_sockets;
+ngx_uint_t ngx_inherited_nonblocking = 1;
+ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush;
+
+char ngx_unique[NGX_INT32_LEN + 1];
+
+
+ngx_os_io_t ngx_os_io = {
+ ngx_wsarecv,
+ ngx_wsarecv_chain,
+ ngx_udp_wsarecv,
+ ngx_wsasend,
+ NULL,
+ NULL,
+ ngx_wsasend_chain,
+ 0
+};
+
+
+typedef struct {
+ WORD wServicePackMinor;
+ WORD wSuiteMask;
+ BYTE wProductType;
+} ngx_osviex_stub_t;
+
+
+static u_int osviex;
+static OSVERSIONINFOEX osvi;
+
+/* Should these pointers be per protocol ? */
+LPFN_ACCEPTEX ngx_acceptex;
+LPFN_GETACCEPTEXSOCKADDRS ngx_getacceptexsockaddrs;
+LPFN_TRANSMITFILE ngx_transmitfile;
+LPFN_TRANSMITPACKETS ngx_transmitpackets;
+LPFN_CONNECTEX ngx_connectex;
+LPFN_DISCONNECTEX ngx_disconnectex;
+
+static GUID ax_guid = WSAID_ACCEPTEX;
+static GUID as_guid = WSAID_GETACCEPTEXSOCKADDRS;
+static GUID tf_guid = WSAID_TRANSMITFILE;
+static GUID tp_guid = WSAID_TRANSMITPACKETS;
+static GUID cx_guid = WSAID_CONNECTEX;
+static GUID dx_guid = WSAID_DISCONNECTEX;
+
+
+ngx_int_t
+ngx_os_init(ngx_log_t *log)
+{
+ DWORD bytes;
+ SOCKET s;
+ WSADATA wsd;
+ ngx_err_t err;
+ ngx_time_t *tp;
+ ngx_uint_t n;
+ SYSTEM_INFO si;
+
+ /* get Windows version */
+
+ ngx_memzero(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+#ifdef _MSC_VER
+#pragma warning(disable:4996)
+#endif
+
+ osviex = GetVersionEx((OSVERSIONINFO *) &osvi);
+
+ if (osviex == 0) {
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "GetVersionEx() failed");
+ return NGX_ERROR;
+ }
+ }
+
+#ifdef _MSC_VER
+#pragma warning(default:4996)
+#endif
+
+ /*
+ * Windows 3.1 Win32s 0xxxxx
+ *
+ * Windows 95 140000
+ * Windows 98 141000
+ * Windows ME 149000
+ * Windows NT 3.51 235100
+ * Windows NT 4.0 240000
+ * Windows NT 4.0 SP5 240050
+ * Windows 2000 250000
+ * Windows XP 250100
+ * Windows 2003 250200
+ * Windows Vista/2008 260000
+ *
+ * Windows CE x.x 3xxxxx
+ */
+
+ ngx_win32_version = osvi.dwPlatformId * 100000
+ + osvi.dwMajorVersion * 10000
+ + osvi.dwMinorVersion * 100;
+
+ if (osviex) {
+ ngx_win32_version += osvi.wServicePackMajor * 10
+ + osvi.wServicePackMinor;
+ }
+
+ GetSystemInfo(&si);
+ ngx_pagesize = si.dwPageSize;
+ ngx_allocation_granularity = si.dwAllocationGranularity;
+ ngx_ncpu = si.dwNumberOfProcessors;
+ ngx_cacheline_size = NGX_CPU_CACHE_LINE;
+
+ for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }
+
+ /* delete default "C" locale for _wcsicmp() */
+ setlocale(LC_ALL, "");
+
+
+ /* init Winsock */
+
+ if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ "WSAStartup() failed");
+ return NGX_ERROR;
+ }
+
+ if (ngx_win32_version < NGX_WIN_NT) {
+ ngx_max_wsabufs = 16;
+ return NGX_OK;
+ }
+
+ /* STUB: ngx_uint_t max */
+ ngx_max_wsabufs = 1024 * 1024;
+
+ /*
+ * get AcceptEx(), GetAcceptExSockAddrs(), TransmitFile(),
+ * TransmitPackets(), ConnectEx(), and DisconnectEx() addresses
+ */
+
+ s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (s == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_socket_n " failed");
+ return NGX_ERROR;
+ }
+
+ if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &ax_guid, sizeof(GUID),
+ &ngx_acceptex, sizeof(LPFN_ACCEPTEX), &bytes, NULL, NULL)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno,
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, "
+ "WSAID_ACCEPTEX) failed");
+ }
+
+ if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &as_guid, sizeof(GUID),
+ &ngx_getacceptexsockaddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS),
+ &bytes, NULL, NULL)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno,
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, "
+ "WSAID_GETACCEPTEXSOCKADDRS) failed");
+ }
+
+ if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tf_guid, sizeof(GUID),
+ &ngx_transmitfile, sizeof(LPFN_TRANSMITFILE), &bytes,
+ NULL, NULL)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno,
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, "
+ "WSAID_TRANSMITFILE) failed");
+ }
+
+ if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tp_guid, sizeof(GUID),
+ &ngx_transmitpackets, sizeof(LPFN_TRANSMITPACKETS), &bytes,
+ NULL, NULL)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno,
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, "
+ "WSAID_TRANSMITPACKETS) failed");
+ }
+
+ if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &cx_guid, sizeof(GUID),
+ &ngx_connectex, sizeof(LPFN_CONNECTEX), &bytes,
+ NULL, NULL)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno,
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, "
+ "WSAID_CONNECTEX) failed");
+ }
+
+ if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &dx_guid, sizeof(GUID),
+ &ngx_disconnectex, sizeof(LPFN_DISCONNECTEX), &bytes,
+ NULL, NULL)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno,
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, "
+ "WSAID_DISCONNECTEX) failed");
+ }
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1)
+ != 0)
+ {
+ ngx_process = NGX_PROCESS_WORKER;
+
+ } else {
+ err = ngx_errno;
+
+ if (err != ERROR_ENVVAR_NOT_FOUND) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "GetEnvironmentVariable(\"ngx_unique\") failed");
+ return NGX_ERROR;
+ }
+
+ ngx_sprintf((u_char *) ngx_unique, "%P%Z", ngx_pid);
+ }
+
+ tp = ngx_timeofday();
+ srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec);
+
+ return NGX_OK;
+}
+
+
+void
+ngx_os_status(ngx_log_t *log)
+{
+ ngx_osviex_stub_t *osviex_stub;
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD);
+
+ if (osviex) {
+
+ /*
+ * the MSVC 6.0 SP2 defines wSuiteMask and wProductType
+ * as WORD wReserved[2]
+ */
+ osviex_stub = (ngx_osviex_stub_t *) &osvi.wServicePackMinor;
+
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "OS: %ud build:%ud, \"%s\", suite:%Xd, type:%ud",
+ ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion,
+ osviex_stub->wSuiteMask, osviex_stub->wProductType);
+
+ } else {
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+
+ /* Win9x build */
+
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "OS: %u build:%ud.%ud.%ud, \"%s\"",
+ ngx_win32_version,
+ osvi.dwBuildNumber >> 24,
+ (osvi.dwBuildNumber >> 16) & 0xff,
+ osvi.dwBuildNumber & 0xffff,
+ osvi.szCSDVersion);
+
+ } else {
+
+ /*
+ * VER_PLATFORM_WIN32_NT
+ *
+ * we do not currently support VER_PLATFORM_WIN32_CE
+ * and we do not support VER_PLATFORM_WIN32s at all
+ */
+
+ ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ud build:%ud, \"%s\"",
+ ngx_win32_version, osvi.dwBuildNumber,
+ osvi.szCSDVersion);
+ }
+ }
+}
diff --git a/app/nginx/src/os/win32/ngx_wsarecv.c b/app/nginx/src/os/win32/ngx_wsarecv.c
new file mode 100644
index 0000000..1925f0b
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_wsarecv.c
@@ -0,0 +1,174 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ int rc;
+ u_long bytes, flags;
+ WSABUF wsabuf[1];
+ ngx_err_t err;
+ ngx_int_t n;
+ ngx_event_t *rev;
+
+ wsabuf[0].buf = (char *) buf;
+ wsabuf[0].len = size;
+ flags = 0;
+ bytes = 0;
+
+ rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL);
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv: fd:%d rc:%d %ul of %z", c->fd, rc, bytes, size);
+
+ rev = c->read;
+
+ if (rc == -1) {
+ rev->ready = 0;
+ err = ngx_socket_errno;
+
+ if (err == WSAEWOULDBLOCK) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSARecv() not ready");
+ return NGX_AGAIN;
+ }
+
+ n = ngx_connection_error(c, err, "WSARecv() failed");
+
+ if (n == NGX_ERROR) {
+ rev->error = 1;
+ }
+
+ return n;
+ }
+
+ if (bytes < size) {
+ rev->ready = 0;
+ }
+
+ if (bytes == 0) {
+ rev->eof = 1;
+ }
+
+ return bytes;
+}
+
+
+ssize_t
+ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ int rc;
+ u_long bytes, flags;
+ WSABUF wsabuf[1];
+ ngx_err_t err;
+ ngx_int_t n;
+ ngx_event_t *rev;
+ LPWSAOVERLAPPED ovlp;
+
+ rev = c->read;
+
+ if (!rev->ready) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second wsa post");
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "rev->complete: %d", rev->complete);
+
+ if (rev->complete) {
+ rev->complete = 0;
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+ if (rev->ovlp.error) {
+ ngx_connection_error(c, rev->ovlp.error, "WSARecv() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv ovlp: fd:%d %ul of %z",
+ c->fd, rev->available, size);
+
+ return rev->available;
+ }
+
+ if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp,
+ &bytes, 0, NULL)
+ == 0)
+ {
+ ngx_connection_error(c, ngx_socket_errno,
+ "WSARecv() or WSAGetOverlappedResult() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv: fd:%d %ul of %z", c->fd, bytes, size);
+
+ return bytes;
+ }
+
+ ovlp = (LPWSAOVERLAPPED) &rev->ovlp;
+ ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+ wsabuf[0].buf = (char *) buf;
+ wsabuf[0].len = size;
+ flags = 0;
+ bytes = 0;
+
+ rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL);
+
+ rev->complete = 0;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv ovlp: fd:%d rc:%d %ul of %z",
+ c->fd, rc, bytes, size);
+
+ if (rc == -1) {
+ err = ngx_socket_errno;
+ if (err == WSA_IO_PENDING) {
+ rev->active = 1;
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSARecv() posted");
+ return NGX_AGAIN;
+ }
+
+ n = ngx_connection_error(c, err, "WSARecv() failed");
+
+ if (n == NGX_ERROR) {
+ rev->error = 1;
+ }
+
+ return n;
+ }
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+ /*
+ * if a socket was bound with I/O completion port
+ * then GetQueuedCompletionStatus() would anyway return its status
+ * despite that WSARecv() was already complete
+ */
+
+ rev->active = 1;
+ return NGX_AGAIN;
+ }
+
+ if (bytes == 0) {
+ rev->eof = 1;
+ rev->ready = 0;
+
+ } else {
+ rev->ready = 1;
+ }
+
+ rev->active = 0;
+
+ return bytes;
+}
diff --git a/app/nginx/src/os/win32/ngx_wsarecv_chain.c b/app/nginx/src/os/win32/ngx_wsarecv_chain.c
new file mode 100644
index 0000000..2598e09
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_wsarecv_chain.c
@@ -0,0 +1,106 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_WSABUFS 8
+
+
+ssize_t
+ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
+{
+ int rc;
+ u_char *prev;
+ u_long bytes, flags;
+ size_t n, size;
+ ngx_err_t err;
+ ngx_array_t vec;
+ ngx_event_t *rev;
+ LPWSABUF wsabuf;
+ WSABUF wsabufs[NGX_WSABUFS];
+
+ prev = NULL;
+ wsabuf = NULL;
+ flags = 0;
+ size = 0;
+ bytes = 0;
+
+ vec.elts = wsabufs;
+ vec.nelts = 0;
+ vec.size = sizeof(WSABUF);
+ vec.nalloc = NGX_WSABUFS;
+ vec.pool = c->pool;
+
+ /* coalesce the neighbouring bufs */
+
+ while (chain) {
+ n = chain->buf->end - chain->buf->last;
+
+ if (limit) {
+ if (size >= (size_t) limit) {
+ break;
+ }
+
+ if (size + n > (size_t) limit) {
+ n = (size_t) limit - size;
+ }
+ }
+
+ if (prev == chain->buf->last) {
+ wsabuf->len += n;
+
+ } else {
+ wsabuf = ngx_array_push(&vec);
+ if (wsabuf == NULL) {
+ return NGX_ERROR;
+ }
+
+ wsabuf->buf = (char *) chain->buf->last;
+ wsabuf->len = n;
+ }
+
+ size += n;
+ prev = chain->buf->end;
+ chain = chain->next;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSARecv: %d:%d", vec.nelts, wsabuf->len);
+
+
+ rc = WSARecv(c->fd, vec.elts, vec.nelts, &bytes, &flags, NULL, NULL);
+
+ rev = c->read;
+
+ if (rc == -1) {
+ rev->ready = 0;
+ err = ngx_socket_errno;
+
+ if (err == WSAEWOULDBLOCK) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSARecv() not ready");
+ return NGX_AGAIN;
+ }
+
+ rev->error = 1;
+ ngx_connection_error(c, err, "WSARecv() failed");
+ return NGX_ERROR;
+ }
+
+ if (bytes < size) {
+ rev->ready = 0;
+ }
+
+ if (bytes == 0) {
+ rev->eof = 1;
+ }
+
+ return bytes;
+}
diff --git a/app/nginx/src/os/win32/ngx_wsasend.c b/app/nginx/src/os/win32/ngx_wsasend.c
new file mode 100644
index 0000000..d6a23d1
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_wsasend.c
@@ -0,0 +1,185 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ssize_t
+ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ int n;
+ u_long sent;
+ ngx_err_t err;
+ ngx_event_t *wev;
+ WSABUF wsabuf;
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return NGX_AGAIN;
+ }
+
+ /*
+ * WSABUF must be 4-byte aligned otherwise
+ * WSASend() will return undocumented WSAEINVAL error.
+ */
+
+ wsabuf.buf = (char *) buf;
+ wsabuf.len = size;
+
+ sent = 0;
+
+ n = WSASend(c->fd, &wsabuf, 1, &sent, 0, NULL, NULL);
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size);
+
+ if (n == 0) {
+ if (sent < size) {
+ wev->ready = 0;
+ }
+
+ c->sent += sent;
+
+ return sent;
+ }
+
+ err = ngx_socket_errno;
+
+ if (err == WSAEWOULDBLOCK) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "WSASend() not ready");
+ wev->ready = 0;
+ return NGX_AGAIN;
+ }
+
+ wev->error = 1;
+ ngx_connection_error(c, err, "WSASend() failed");
+
+ return NGX_ERROR;
+}
+
+
+ssize_t
+ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size)
+{
+ int n;
+ u_long sent;
+ ngx_err_t err;
+ ngx_event_t *wev;
+ LPWSAOVERLAPPED ovlp;
+ WSABUF wsabuf;
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "wev->complete: %d", wev->complete);
+
+ if (!wev->complete) {
+
+ /* post the overlapped WSASend() */
+
+ /*
+ * WSABUFs must be 4-byte aligned otherwise
+ * WSASend() will return undocumented WSAEINVAL error.
+ */
+
+ wsabuf.buf = (char *) buf;
+ wsabuf.len = size;
+
+ sent = 0;
+
+ ovlp = (LPWSAOVERLAPPED) &c->write->ovlp;
+ ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+
+ n = WSASend(c->fd, &wsabuf, 1, &sent, 0, ovlp, NULL);
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size);
+
+ wev->complete = 0;
+
+ if (n == 0) {
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+ /*
+ * if a socket was bound with I/O completion port then
+ * GetQueuedCompletionStatus() would anyway return its status
+ * despite that WSASend() was already complete
+ */
+
+ wev->active = 1;
+ return NGX_AGAIN;
+ }
+
+ if (sent < size) {
+ wev->ready = 0;
+ }
+
+ c->sent += sent;
+
+ return sent;
+ }
+
+ err = ngx_socket_errno;
+
+ if (err == WSA_IO_PENDING) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSASend() posted");
+ wev->active = 1;
+ return NGX_AGAIN;
+ }
+
+ wev->error = 1;
+ ngx_connection_error(c, err, "WSASend() failed");
+
+ return NGX_ERROR;
+ }
+
+ /* the overlapped WSASend() complete */
+
+ wev->complete = 0;
+ wev->active = 0;
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+ if (wev->ovlp.error) {
+ ngx_connection_error(c, wev->ovlp.error, "WSASend() failed");
+ return NGX_ERROR;
+ }
+
+ sent = wev->available;
+
+ } else {
+ if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp,
+ &sent, 0, NULL)
+ == 0)
+ {
+ ngx_connection_error(c, ngx_socket_errno,
+ "WSASend() or WSAGetOverlappedResult() failed");
+
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSAGetOverlappedResult: fd:%d, %ul of %uz",
+ c->fd, sent, size);
+
+ if (sent < size) {
+ wev->ready = 0;
+ }
+
+ c->sent += sent;
+
+ return sent;
+}
diff --git a/app/nginx/src/os/win32/ngx_wsasend_chain.c b/app/nginx/src/os/win32/ngx_wsasend_chain.c
new file mode 100644
index 0000000..e2dde22
--- /dev/null
+++ b/app/nginx/src/os/win32/ngx_wsasend_chain.c
@@ -0,0 +1,292 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_WSABUFS 8
+
+
+ngx_chain_t *
+ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ int rc;
+ u_char *prev;
+ u_long size, sent, send, prev_send;
+ ngx_err_t err;
+ ngx_event_t *wev;
+ ngx_array_t vec;
+ ngx_chain_t *cl;
+ LPWSABUF wsabuf;
+ WSABUF wsabufs[NGX_WSABUFS];
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+ /* the maximum limit size is the maximum u_long value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize)) {
+ limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
+ }
+
+ send = 0;
+
+ /*
+ * WSABUFs must be 4-byte aligned otherwise
+ * WSASend() will return undocumented WSAEINVAL error.
+ */
+
+ vec.elts = wsabufs;
+ vec.size = sizeof(WSABUF);
+ vec.nalloc = NGX_WSABUFS;
+ vec.pool = c->pool;
+
+ for ( ;; ) {
+ prev = NULL;
+ wsabuf = NULL;
+ prev_send = send;
+
+ vec.nelts = 0;
+
+ /* create the WSABUF and coalesce the neighbouring bufs */
+
+ for (cl = in;
+ cl && vec.nelts < ngx_max_wsabufs && send < limit;
+ cl = cl->next)
+ {
+ if (ngx_buf_special(cl->buf)) {
+ continue;
+ }
+
+ size = cl->buf->last - cl->buf->pos;
+
+ if (send + size > limit) {
+ size = (u_long) (limit - send);
+ }
+
+ if (prev == cl->buf->pos) {
+ wsabuf->len += cl->buf->last - cl->buf->pos;
+
+ } else {
+ wsabuf = ngx_array_push(&vec);
+ if (wsabuf == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ wsabuf->buf = (char *) cl->buf->pos;
+ wsabuf->len = cl->buf->last - cl->buf->pos;
+ }
+
+ prev = cl->buf->last;
+ send += size;
+ }
+
+ sent = 0;
+
+ rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, NULL, NULL);
+
+ if (rc == -1) {
+ err = ngx_errno;
+
+ if (err == WSAEWOULDBLOCK) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSASend() not ready");
+
+ } else {
+ wev->error = 1;
+ ngx_connection_error(c, err, "WSASend() failed");
+ return NGX_CHAIN_ERROR;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSASend: fd:%d, s:%ul", c->fd, sent);
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+ if (send - prev_send != sent) {
+ wev->ready = 0;
+ return in;
+ }
+
+ if (send >= limit || in == NULL) {
+ return in;
+ }
+ }
+}
+
+
+ngx_chain_t *
+ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
+{
+ int rc;
+ u_char *prev;
+ u_long size, send, sent;
+ ngx_err_t err;
+ ngx_event_t *wev;
+ ngx_array_t vec;
+ ngx_chain_t *cl;
+ LPWSAOVERLAPPED ovlp;
+ LPWSABUF wsabuf;
+ WSABUF wsabufs[NGX_WSABUFS];
+
+ wev = c->write;
+
+ if (!wev->ready) {
+ return in;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "wev->complete: %d", wev->complete);
+
+ if (!wev->complete) {
+
+ /* post the overlapped WSASend() */
+
+ /* the maximum limit size is the maximum u_long value - the page size */
+
+ if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize))
+ {
+ limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
+ }
+
+ /*
+ * WSABUFs must be 4-byte aligned otherwise
+ * WSASend() will return undocumented WSAEINVAL error.
+ */
+
+ vec.elts = wsabufs;
+ vec.nelts = 0;
+ vec.size = sizeof(WSABUF);
+ vec.nalloc = NGX_WSABUFS;
+ vec.pool = c->pool;
+
+ send = 0;
+ prev = NULL;
+ wsabuf = NULL;
+
+ /* create the WSABUF and coalesce the neighbouring bufs */
+
+ for (cl = in;
+ cl && vec.nelts < ngx_max_wsabufs && send < limit;
+ cl = cl->next)
+ {
+ if (ngx_buf_special(cl->buf)) {
+ continue;
+ }
+
+ size = cl->buf->last - cl->buf->pos;
+
+ if (send + size > limit) {
+ size = (u_long) (limit - send);
+ }
+
+ if (prev == cl->buf->pos) {
+ wsabuf->len += cl->buf->last - cl->buf->pos;
+
+ } else {
+ wsabuf = ngx_array_push(&vec);
+ if (wsabuf == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ wsabuf->buf = (char *) cl->buf->pos;
+ wsabuf->len = cl->buf->last - cl->buf->pos;
+ }
+
+ prev = cl->buf->last;
+ send += size;
+ }
+
+ ovlp = (LPWSAOVERLAPPED) &c->write->ovlp;
+ ngx_memzero(ovlp, sizeof(WSAOVERLAPPED));
+
+ rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, ovlp, NULL);
+
+ wev->complete = 0;
+
+ if (rc == -1) {
+ err = ngx_errno;
+
+ if (err == WSA_IO_PENDING) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "WSASend() posted");
+ wev->active = 1;
+ return in;
+
+ } else {
+ wev->error = 1;
+ ngx_connection_error(c, err, "WSASend() failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ } else if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+ /*
+ * if a socket was bound with I/O completion port then
+ * GetQueuedCompletionStatus() would anyway return its status
+ * despite that WSASend() was already complete
+ */
+
+ wev->active = 1;
+ return in;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSASend: fd:%d, s:%ul", c->fd, sent);
+
+ } else {
+
+ /* the overlapped WSASend() complete */
+
+ wev->complete = 0;
+ wev->active = 0;
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+ if (wev->ovlp.error) {
+ ngx_connection_error(c, wev->ovlp.error, "WSASend() failed");
+ return NGX_CHAIN_ERROR;
+ }
+
+ sent = wev->available;
+
+ } else {
+ if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp,
+ &sent, 0, NULL)
+ == 0)
+ {
+ ngx_connection_error(c, ngx_socket_errno,
+ "WSASend() or WSAGetOverlappedResult() failed");
+
+ return NGX_CHAIN_ERROR;
+ }
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "WSASend ovlp: fd:%d, s:%ul", c->fd, sent);
+
+ c->sent += sent;
+
+ in = ngx_chain_update_sent(in, sent);
+
+ if (in) {
+ wev->ready = 0;
+
+ } else {
+ wev->ready = 1;
+ }
+
+ return in;
+}